diff --git a/Console/Console_VS2005.vcproj b/Console/Console_VS2005.vcproj new file mode 100644 index 00000000..b579ea18 --- /dev/null +++ b/Console/Console_VS2005.vcproj @@ -0,0 +1,679 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Console/Console_VS2008.vcproj b/Console/Console_VS2008.vcproj index d658acbc..539399c0 100644 --- a/Console/Console_VS2008.vcproj +++ b/Console/Console_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -149,7 +149,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -214,7 +214,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > diff --git a/Console/Console_VS2010.vcxproj b/Console/Console_VS2010.vcxproj new file mode 100644 index 00000000..98557bce --- /dev/null +++ b/Console/Console_VS2010.vcxproj @@ -0,0 +1,227 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + {A32479BF-C284-4C40-99A5-4F6B5933D1C0} + Win32Proj + Console + Console + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Console/Console_VS2010.vcxproj.filters b/Console/Console_VS2010.vcxproj.filters new file mode 100644 index 00000000..e7559662 --- /dev/null +++ b/Console/Console_VS2010.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + {abfafc0c-c637-4524-960d-bddcb96d0913} + + + {680812ee-68a6-4c84-a9aa-615d9523b3b1} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Credits.cpp b/Credits.cpp index 4bd2c003..9bb0866c 100644 --- a/Credits.cpp +++ b/Credits.cpp @@ -1575,13 +1575,7 @@ UINT32 GetAndHandleCreditCodeFromCodeString( STR16 pzCode ) { return( CRDT_FLAG__END_SECTION ); } - - //else its an error - else - { - Assert( 0 ); - } - + return( CRDT_NODE_NONE ); } diff --git a/Editor/Editor Callbacks.cpp b/Editor/Editor Callbacks.cpp index 8fc198d8..fa8d6517 100644 --- a/Editor/Editor Callbacks.cpp +++ b/Editor/Editor Callbacks.cpp @@ -33,6 +33,8 @@ #include "EditorMapInfo.h" #endif +#include "LoadScreen.h" + extern SOLDIERINITNODE *gpSelected; extern SCHEDULENODE gCurrSchedule; extern void ExtractAndUpdateMercSchedule(); @@ -648,8 +650,17 @@ void BtnChangeTilesetCallback(GUI_BUTTON *btn,INT32 reason) { if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) { - btn->uiFlags |= BUTTON_CLICKED_ON; - iEditorToolbarState = TBAR_MODE_CHANGE_TILESET; + // WANNE: Check if map has been saved when we have a new map that has not been saved before! + if (fNewMapSaved) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + iEditorToolbarState = TBAR_MODE_CHANGE_TILESET; + } + else + { + swprintf(gzErrorCatchString, L"Before changing tilesets you have to save the new map!"); + InitErrorCatchDialog(); + } } } diff --git a/Editor/Editor Taskbar Creation.cpp b/Editor/Editor Taskbar Creation.cpp index 7f5f3526..eed584ec 100644 --- a/Editor/Editor Taskbar Creation.cpp +++ b/Editor/Editor Taskbar Creation.cpp @@ -708,7 +708,7 @@ void InitEditorOptionsToolbar() //dnl ch33 160909 iEditorButton[OPTIONS_VANILLA_MODE] = CreateCheckBoxButton(iScreenWidthOffset+71, SCREEN_HEIGHT-119, "EDITOR//smcheckbox.sti", MSYS_PRIORITY_NORMAL, VanillaModeCallback); - SetButtonFastHelpText(iEditorButton[OPTIONS_VANILLA_MODE],L"Set save map as v1.12"); + SetButtonFastHelpText(iEditorButton[OPTIONS_VANILLA_MODE],L"When checked, the map will be saved in original JA2 format (Version: 5.00 / 25)"); } void InitEditorTerrainToolbar() diff --git a/Editor/Editor Taskbar Utils.cpp b/Editor/Editor Taskbar Utils.cpp index d3d031ab..f69d7ac7 100644 --- a/Editor/Editor Taskbar Utils.cpp +++ b/Editor/Editor Taskbar Utils.cpp @@ -906,7 +906,7 @@ void RenderEditorInfo( ) switch( iCurrentTaskbar ) { case TASK_OPTIONS: - mprintf(iScreenWidthOffset+71+15, SCREEN_HEIGHT-117, L"v1.12");//dnl ch33 160909 + mprintf(iScreenWidthOffset+71+15, SCREEN_HEIGHT-117, L"Save map in original JA2 map format (Version: 5.00 / 25)");//dnl ch33 160909 if( !gfWorldLoaded || giCurrentTilesetID < 0 ) mprintf( iScreenWidthOffset + 260, 2 * iScreenHeightOffset + 445, L"No map currently loaded." ); else diff --git a/Editor/EditorItems.cpp b/Editor/EditorItems.cpp index e472828a..42a500c5 100644 --- a/Editor/EditorItems.cpp +++ b/Editor/EditorItems.cpp @@ -45,7 +45,7 @@ #include "InterfaceItemImages.h" #endif -#include "VFS/Tools/Log.h" +#include #define NUMBER_TRIGGERS 27 #define PRESSURE_ACTION_ID (NUMBER_TRIGGERS - 1) @@ -557,10 +557,10 @@ void InitEditorItemsInfo(UINT32 uiItemType) } else { - static CLog& editorLog = *CLog::create(L"EditorItems.log"); + static vfs::Log& editorLog = *vfs::Log::create(L"EditorItems.log"); editorLog << L"Tried to access item [" << item->ubGraphicNum << L"/" << hVObject->usNumberOfObjects - << L"]" << CLog::ENDL; + << L"]" << vfs::Log::endl; } } usCounter++; diff --git a/Editor/EditorMapInfo.cpp b/Editor/EditorMapInfo.cpp index 029c4e74..8c0ebb58 100644 --- a/Editor/EditorMapInfo.cpp +++ b/Editor/EditorMapInfo.cpp @@ -141,7 +141,7 @@ void SetupTextInputForMapInfo() swprintf( str, L"%d", gExitGrid.ubGotoSectorZ ); AddTextInputField( iScreenWidthOffset + 338, 2 * iScreenHeightOffset + 383, 30, 18, MSYS_PRIORITY_NORMAL, str, 1, INPUTTYPE_NUMERICSTRICT ); swprintf( str, L"%d", gExitGrid.usGridNo ); - AddTextInputField( iScreenWidthOffset + 338, 2 * iScreenHeightOffset + 403, 40, 18, MSYS_PRIORITY_NORMAL, str, 5, INPUTTYPE_NUMERICSTRICT ); + AddTextInputField( iScreenWidthOffset + 338, 2 * iScreenHeightOffset + 403, 45, 18, MSYS_PRIORITY_NORMAL, str, 6, INPUTTYPE_NUMERICSTRICT ); } void UpdateMapInfo() @@ -183,8 +183,8 @@ void UpdateMapInfo() mprintf( iScreenWidthOffset + 368, 2 * iScreenHeightOffset + 372, L"Sector" ); mprintf( iScreenWidthOffset + 368, 2 * iScreenHeightOffset + 383, L"Destination"); mprintf( iScreenWidthOffset + 368, 2 * iScreenHeightOffset + 392, L"Bsmt. Level" ); - mprintf( iScreenWidthOffset + 378, 2 * iScreenHeightOffset + 403, L"Dest." ); - mprintf( iScreenWidthOffset + 378, 2 * iScreenHeightOffset + 412, L"GridNo" ); + mprintf( iScreenWidthOffset + 383, 2 * iScreenHeightOffset + 403, L"Dest." ); + mprintf( iScreenWidthOffset + 383, 2 * iScreenHeightOffset + 412, L"GridNo" ); SetFontForeground( FONT_RED ); } diff --git a/Editor/EditorMercs.cpp b/Editor/EditorMercs.cpp index 9142b3e3..fca45019 100644 --- a/Editor/EditorMercs.cpp +++ b/Editor/EditorMercs.cpp @@ -77,6 +77,11 @@ extern void GetSoldierAboveGuyPositions( SOLDIERTYPE *pSoldier, INT16 *psX, INT1 // SANMONA_ARMS_GROUP, // ANGELS_GROUP, // NUM_CIV_GROUPS + +CHAR16 gszCivGroupNames[ NUM_CIV_GROUPS ][ 128 ]; + + +/* CHAR16 gszCivGroupNames[ NUM_CIV_GROUPS ][ 20 ] = { L"NONE", @@ -102,7 +107,7 @@ CHAR16 gszCivGroupNames[ NUM_CIV_GROUPS ][ 20 ] = L"UNUSED18", L"UNUSED19", }; - +*/ //-------------------------------------------------- // SCHEDULE_ACTION_NONE, @@ -311,6 +316,27 @@ extern SOLDIERCREATE_STRUCT gSaveBufferDetailedPlacement; //void CopyMercPlacement(); // moved to header (jonathanl) //void PasteMercPlacement(); // moved to header (jonathanl) + +//legion2 jazz + +wchar_t *GetGrupaString( SOLDIERTYPE *pSoldier ) //Legion 2 +{ + INT32 cnt, cntStart,par; + + cntStart = 0; + for ( cnt = cntStart; cnt < NUM_CIV_GROUPS; cnt ++ ) + { + if (pSoldier->ubCivilianGroup == cnt) + { + par = cnt; + } + + } + return gszCivGroupNames[ par ]; +} +//------------ + + void GameInitEditorMercsInfo() { INT32 i; @@ -3106,7 +3132,7 @@ void RenderMercStrings() SOLDIERTYPE *pSoldier; INT16 sXPos, sYPos; INT16 sX, sY; - STR16 pStr; + STR16 pStr, pStr2; SOLDIERINITNODE *curr; CHAR16 str[50]; @@ -3154,6 +3180,24 @@ void RenderMercStrings() mprintf( sX, sY, str ); } sYPos += 10; + + + if (pSoldier->bTeam == CIV_TEAM ) + { + //legion2 + pStr2 = GetGrupaString( pSoldier ); + + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); //FONT_MCOLOR_WHITE + FindFontCenterCoordinates( sXPos, sYPos, 80, 1, pStr2, TINYFONT1, &sX, &sY ); + if( sY < (2 * iScreenHeightOffset + 352 )) + { + gprintfdirty( sX, sY, pStr2 ); + mprintf( sX, sY, pStr2 ); + } + sYPos += 10; + } + } else { @@ -3180,6 +3224,25 @@ void RenderMercStrings() mprintf( sX, sY, str ); } sYPos += 10; + + //legion + if (pSoldier->bTeam == CIV_TEAM ) //(pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == CREATURE_TEAM || pSoldier->bTeam == MILITIA_TEAM) + { + //legion 2 + pStr2 = GetGrupaString( pSoldier ); + + //SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); //FONT_MCOLOR_WHITE + FindFontCenterCoordinates( sXPos, sYPos, 80, 1, pStr2, TINYFONT1, &sX, &sY ); + if( sY < (2 * iScreenHeightOffset + 352 )) + { + gprintfdirty( sX, sY, pStr2 ); + mprintf( sX, sY, pStr2 ); + } + sYPos += 10; + } + } if( curr->pBasicPlacement->bOrders == RNDPTPATROL || curr->pBasicPlacement->bOrders == POINTPATROL ) { //make sure the placement has at least one waypoint. @@ -3302,7 +3365,7 @@ void CancelCurrentScheduleAction() void RegisterCurrentScheduleAction( INT32 iMapIndex ) { - CHAR16 str[6]; + CHAR16 str[10]; MarkWorldDirty(); swprintf( str, L"%d", iMapIndex ); if( gfUseScheduleData2 ) diff --git a/Editor/Editor_VS2005.vcproj b/Editor/Editor_VS2005.vcproj new file mode 100644 index 00000000..090d57ee --- /dev/null +++ b/Editor/Editor_VS2005.vcproj @@ -0,0 +1,559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Editor/Editor_VS2008.vcproj b/Editor/Editor_VS2008.vcproj index a06031ed..efd16c40 100644 --- a/Editor/Editor_VS2008.vcproj +++ b/Editor/Editor_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > diff --git a/Editor/Editor_VS2010.vcxproj b/Editor/Editor_VS2010.vcxproj new file mode 100644 index 00000000..28a36a00 --- /dev/null +++ b/Editor/Editor_VS2010.vcxproj @@ -0,0 +1,265 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {23EA0500-038A-4EB8-B753-0C709B25470D} + Win32Proj + Editor + Editor + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Editor/Editor_VS2010.vcxproj.filters b/Editor/Editor_VS2010.vcxproj.filters new file mode 100644 index 00000000..ca9d84a6 --- /dev/null +++ b/Editor/Editor_VS2010.vcxproj.filters @@ -0,0 +1,171 @@ + + + + + {1305164a-0ad7-4d96-af15-765647f97f27} + + + {02bb6629-3e96-4c7d-931f-fb1ec12b8ef5} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Editor/Item Statistics.cpp b/Editor/Item Statistics.cpp index a1db49cf..731c82e8 100644 --- a/Editor/Item Statistics.cpp +++ b/Editor/Item Statistics.cpp @@ -671,7 +671,7 @@ void SetupGunGUI() //for a particular weapon. Show only the ones that we can apply to this gun. yp = 2 * iScreenHeightOffset + 383; guiAttachmentButton[ SILENCER_ATTACHMENT_BUTTON ] = -1; - if( ValidAttachment( SILENCER, gpItem->usItem ) ) + if( ValidAttachment( SILENCER, gpItem ) ) { guiAttachmentButton[ SILENCER_ATTACHMENT_BUTTON ] = CreateTextButton( L"SILENCER", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -684,7 +684,7 @@ void SetupGunGUI() } } guiAttachmentButton[ SNIPERSCOPE_ATTACHMENT_BUTTON ] = -1; - if( ValidAttachment( SNIPERSCOPE, gpItem->usItem ) ) + if( ValidAttachment( SNIPERSCOPE, gpItem ) ) { guiAttachmentButton[ SNIPERSCOPE_ATTACHMENT_BUTTON ] = CreateTextButton( L"SNIPERSCOPE", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -697,7 +697,7 @@ void SetupGunGUI() } } guiAttachmentButton[ LASERSCOPE_ATTACHMENT_BUTTON ] = -1; - if( ValidAttachment( LASERSCOPE, gpItem->usItem ) ) + if( ValidAttachment( LASERSCOPE, gpItem ) ) { guiAttachmentButton[ LASERSCOPE_ATTACHMENT_BUTTON ] = CreateTextButton( L"LASERSCOPE", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -710,7 +710,7 @@ void SetupGunGUI() } } guiAttachmentButton[ BIPOD_ATTACHMENT_BUTTON ] = -1; - if( ValidAttachment( BIPOD, gpItem->usItem ) ) + if( ValidAttachment( BIPOD, gpItem ) ) { guiAttachmentButton[ BIPOD_ATTACHMENT_BUTTON ] = CreateTextButton( L"BIPOD", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -723,7 +723,7 @@ void SetupGunGUI() } } guiAttachmentButton[ DUCKBILL_ATTACHMENT_BUTTON ] = -1; - if( ValidAttachment( DUCKBILL, gpItem->usItem ) ) + if( ValidAttachment( DUCKBILL, gpItem ) ) { guiAttachmentButton[ DUCKBILL_ATTACHMENT_BUTTON ] = CreateTextButton( L"DUCKBILL", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -736,7 +736,7 @@ void SetupGunGUI() } } guiAttachmentButton[ GLAUNCHER_ATTACHMENT_BUTTON ] = -1; - if( ValidAttachment( UNDER_GLAUNCHER, gpItem->usItem ) ) + if( ValidAttachment( UNDER_GLAUNCHER, gpItem ) ) { guiAttachmentButton[ GLAUNCHER_ATTACHMENT_BUTTON ] = CreateTextButton( L"G-LAUNCHER", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -855,7 +855,7 @@ void SetupArmourGUI() } guiCeramicPlatesButton = -1; - if( ValidAttachment( CERAMIC_PLATES, gpItem->usItem ) ) + if( ValidAttachment( CERAMIC_PLATES, gpItem ) ) { guiCeramicPlatesButton = CreateTextButton( L"CERAMIC PLATES", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, @@ -1012,7 +1012,7 @@ void SetupExplosivesGUI() yp = 375; gfDetonator = FALSE; guiDetonatorButton = -1; - if( ValidAttachment( DETONATOR, gpItem->usItem ) ) + if( ValidAttachment( DETONATOR, gpItem ) ) { guiDetonatorButton = CreateTextButton( L"DETONATOR", SMALLCOMPFONT, FONT_YELLOW, FONT_BLACK, BUTTON_USE_DEFAULT, diff --git a/Editor/LoadScreen.cpp b/Editor/LoadScreen.cpp index b7372720..b7acf76c 100644 --- a/Editor/LoadScreen.cpp +++ b/Editor/LoadScreen.cpp @@ -43,9 +43,11 @@ #include "Item Statistics.h" #include "Scheduling.h" #include "MessageBoxScreen.h" - #include "VFS/vfs.h"//dnl ch37 110909 + #include //dnl ch37 110909 #endif +INT16 gsMouseWheelDeltaValue; + //=========================================================================== BOOLEAN gfErrorCatch = FALSE; @@ -190,7 +192,7 @@ void LoadSaveScreenEntry() vfs::CVirtualProfile::FileIterator fit = prof->files(L"MAPS/*"); while(!fit.end()) { - utf8string fname = fit.value()->getName().c_str(); + vfs::String fname = fit.value()->getName().c_str(); memset(&FileInfo, 0, sizeof(GETFILESTRUCT)); strcpy(FileInfo.zFileName, fname.utf8().c_str()); FileInfo.uiFileSize = fname.length(); @@ -1013,8 +1015,7 @@ UINT32 ProcessFileIO() return(EDIT_SCREEN); } gbCurrentFileIOStatus = IOSTATUS_NONE; - utf8string msg = utf8string(" Error saving ") + ubNewFilename + utf8string(" file. Try another filename? "); - CreateMessageBox((STR16)msg.c_wcs().c_str()); + CreateMessageBox((STR16)(_BS(L" Error saving ") << (const char*)ubNewFilename << L" file. Try another filename? " << _BS::wget).c_str() ); return(guiCurrentScreen); } if( gfShowPits ) @@ -1035,6 +1036,9 @@ UINT32 ProcessFileIO() InitErrorCatchDialog(); return EDIT_SCREEN; } + + fNewMapSaved = TRUE; + return EDIT_SCREEN; case INITIATE_MAP_LOAD: //draw load message SaveFontSettings(); @@ -1056,8 +1060,7 @@ UINT32 ProcessFileIO() gbCurrentFileIOStatus = IOSTATUS_NONE; gfGlobalError = FALSE; gfLoadError = TRUE; - utf8string msg = utf8string(" Error loading ") + ubNewFilename + utf8string(" file. Try another filename? "); - CreateMessageBox((STR16)msg.c_wcs().c_str()); + CreateMessageBox((STR16)(_BS(L" Error loading ") << (const char*)ubNewFilename << L" file. Try another filename? " << _BS::wget).c_str()); return(guiCurrentScreen); } //ADB these are NOT set yet! but they need to be, duh diff --git a/Editor/LoadScreen.h b/Editor/LoadScreen.h index 90c24dae..2958a605 100644 --- a/Editor/LoadScreen.h +++ b/Editor/LoadScreen.h @@ -42,6 +42,8 @@ BOOLEAN ValidMapFileName(STR16 szFilename); BOOLEAN ExternalLoadMap(STR16 szFilename); BOOLEAN ExternalSaveMap(STR16 szFilename); +void InitErrorCatchDialog(); + extern BOOLEAN gfErrorCatch; extern CHAR16 gzErrorCatchString[ 256 ]; diff --git a/Editor/Sector Summary.cpp b/Editor/Sector Summary.cpp index 9ea6fe33..4f38c493 100644 --- a/Editor/Sector Summary.cpp +++ b/Editor/Sector Summary.cpp @@ -39,10 +39,11 @@ #include "Soldier Create.h" #include "GameVersion.h" #include "Campaign Types.h" + #include "GameSettings.h" #endif -#include "VFS/vfs.h" -#include "VFS/vfs_file_raii.h" +#include +#include extern BOOLEAN gfOverheadMapDirty; @@ -416,9 +417,10 @@ void CreateSummaryWindow() if( gfAutoLoadA9 ) { gfAutoLoadA9++; - gsSelSectorX = 9; - gsSelSectorY = 1; - gpCurrentSectorSummary = gpSectorSummary[ 8 ][ 0 ][ 0 ]; + gsSelSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;//9; + gsSelSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;//1; + //gpCurrentSectorSummary = gpSectorSummary[ 8 ][ 0 ][ 0 ]; + gpCurrentSectorSummary = gpSectorSummary[ gGameExternalOptions.ubDefaultArrivalSectorX - 1 ][ gGameExternalOptions.ubDefaultArrivalSectorY - 1 ][ 0 ]; ButtonList[ iSummaryButton[ SUMMARY_LOAD ] ]->uiFlags |= BUTTON_CLICKED_ON; } } @@ -761,6 +763,7 @@ void RenderItemDetails() pItem = &gpWorldItemsSummaryArray[ i ].object; uiExistChance += (100 - gpWorldItemsSummaryArray[ i ].ubNonExistChance) * pItem->ubNumberOfObjects; uiStatus += (*pItem)[0]->data.objectStatus; + uiQuantity += pItem->ubNumberOfObjects; } } } @@ -1965,7 +1968,7 @@ void CreateGlobalSummary() vfs::COpenWriteFile wfile(L"DevInfo\\readme.txt",true,true); std::string str = "This information is used in conjunction with the editor.\n"; str += "This directory or it's contents shouldn't be included with final release.\n"; - TRYCATCH_RETHROW( wfile.file().write(str.c_str(), str.length()), L"" ); + SGP_TRYCATCH_RETHROW( wfile->write(str.c_str(), str.length()), L"" ); #endif // Snap: Restore the data directory once we are finished. @@ -2155,6 +2158,8 @@ void SummaryLoadMapCallback( GUI_BUTTON *btn, INT32 reason ) SetFontForeground( FONT_LTKHAKI ); SetFontShadow( FONT_NEARBLACK ); + fNewMapSaved = TRUE; + //swprintf( str, L"Loading map: %s...", gszDisplayName ); //mprintf( MAP_LEFT, MAP_BOTTOM+100, str ); //InvalidateRegion( MAP_LEFT, MAP_BOTTOM+100, MAP_LEFT+150, MAP_BOTTOM+110 ); @@ -2640,11 +2645,11 @@ void GenerateSummaryList() vfs::COpenWriteFile wfile(L"DevInfo/readme.txt",true,true); std::string str = "This information is used in conjunction with the editor.\n"; str += "This directory or it's contents shouldn't be included with final release.\n"; - TRYCATCH_RETHROW( wfile.file().write(str.c_str(), str.length()), L""); + SGP_TRYCATCH_RETHROW( wfile->write(str.c_str(), str.length()), L""); } - catch(CBasicException &ex) + catch(std::exception &ex) { - RETHROWEXCEPTION(L"Could not create readme.txt",&ex); + SGP_RETHROW(L"Could not create readme.txt", ex); } #endif } @@ -3220,6 +3225,9 @@ void SetupItemDetailsMode( BOOLEAN fAllowRecursion ) OBJECTTYPE *pItem; UINT16 usPEnemyIndex, usNEnemyIndex; + SUMMARYFILE *s = gpCurrentSectorSummary; + MAPCREATE_STRUCT *m = &gpCurrentSectorSummary->MapInfo; + //Clear memory for all the item summaries loaded if( gpWorldItemsSummaryArray ) { @@ -3291,7 +3299,7 @@ void SetupItemDetailsMode( BOOLEAN fAllowRecursion ) gusWorldItemsSummaryArraySize = gpCurrentSectorSummary->usNumItems; for (unsigned int x = 0; x < uiNumItems; ++x) { - gpWorldItemsSummaryArray[x].Load(hfile); + gpWorldItemsSummaryArray[x].Load(hfile, s->dMajorMapVersion, m->ubMapVersion); } //NOW, do the enemy's items! diff --git a/Editor/edit_sys.cpp b/Editor/edit_sys.cpp index 34ef96e8..c5877cba 100644 --- a/Editor/edit_sys.cpp +++ b/Editor/edit_sys.cpp @@ -365,8 +365,9 @@ void PasteSingleWallCommon( INT32 iMapIndex ) // TEMP STUFF FOR ONROOF THINGS! if ( (usUseObjIndex >= FIRSTONROOF) && (usUseObjIndex <= SECONDONROOF ) ) { + // WANNE: Disabled the next line, because if makes placing sandbags on rooftops impossible! //dnl Remove all onroof things before placing new one to avoid stacking problems of same element - RemoveAllOnRoofsOfTypeRange( iMapIndex, FIRSTONROOF, SECONDONROOF ); + //RemoveAllOnRoofsOfTypeRange( iMapIndex, FIRSTONROOF, SECONDONROOF ); // Add to onroof section! AddOnRoofToTail( iMapIndex, (UINT16)(gTileTypeStartIndex[ usUseObjIndex ] + usUseIndex) ); diff --git a/Editor/editscreen.cpp b/Editor/editscreen.cpp index efa73a4e..b2e49663 100644 --- a/Editor/editscreen.cpp +++ b/Editor/editscreen.cpp @@ -214,6 +214,7 @@ BOOLEAN gfRealGunNut = TRUE; INT16 sGridX, sGridY; INT32 iMapIndex; BOOLEAN fNewMap = FALSE; +BOOLEAN fNewMapSaved = TRUE; INT32 iPrevDrawMode = DRAW_MODE_NOTHING; UINT16 PrevCurrentPaste = FIRSTTEXTURE; @@ -297,7 +298,8 @@ BOOLEAN EditModeInit( void ) //dnl after multiplayer stuff was implemeted, editor goes to assertion when you leave editor mode, because InitGameOption() is not called anymore from InitializeGame() is_networked = FALSE; - InitGameOptions(); + //InitGameOptions(); + GameInitOptionsScreenInit(); ResetCustomFileSectorSummary();//dnl ch30 150909 @@ -375,6 +377,7 @@ BOOLEAN EditModeInit( void ) gfEditMode = TRUE; fNewMap = FALSE; + fNewMapSaved = TRUE; gfEditingDoor = FALSE; @@ -2483,6 +2486,8 @@ void CreateNewMap() ResetCustomFileSectorSummary();//dnl ch30 150909 SetRenderCenter(WORLD_COLS/2, WORLD_ROWS/2);//dnl ch43 280909 InitRenderParams(gMapInformation.ubRestrictedScrollID);//dnl ch54 101009 + + fNewMapSaved = FALSE; } diff --git a/Editor/editscreen.h b/Editor/editscreen.h index 162dd07c..858a2b58 100644 --- a/Editor/editscreen.h +++ b/Editor/editscreen.h @@ -14,6 +14,9 @@ extern GUI_BUTTON *gpPersistantButton; extern UINT16 GenericButtonFillColors[40]; +// WANNE: 05.10.2010 +extern BOOLEAN fNewMapSaved; + void DisplayWayPoints(void); BOOLEAN CheckForSlantRoofs( void ); diff --git a/Editor/selectwin.cpp b/Editor/selectwin.cpp index c4f6d0cb..728646a6 100644 --- a/Editor/selectwin.cpp +++ b/Editor/selectwin.cpp @@ -185,36 +185,36 @@ void CreateJA2SelectionWindow( INT16 sWhat ) DisableEditorTaskbar( ); // Load up the button images - iButtonIcons[ CANCEL_ICON ] = LoadGenericButtonIcon( "EDITOR//bigX.sti" ); - iButtonIcons[ UP_ICON ] = LoadGenericButtonIcon( "EDITOR//lgUpArrow.sti" ); - iButtonIcons[ DOWN_ICON ] = LoadGenericButtonIcon( "EDITOR//lgDownArrow.sti" ); - iButtonIcons[ OK_ICON ] = LoadGenericButtonIcon( "EDITOR//checkmark.sti" ); + iButtonIcons[ SEL_WIN_CANCEL_ICON ] = LoadGenericButtonIcon( "EDITOR//bigX.sti" ); + iButtonIcons[ SEL_WIN_UP_ICON ] = LoadGenericButtonIcon( "EDITOR//lgUpArrow.sti" ); + iButtonIcons[ SEL_WIN_DOWN_ICON ] = LoadGenericButtonIcon( "EDITOR//lgDownArrow.sti" ); + iButtonIcons[ SEL_WIN_OK_ICON ] = LoadGenericButtonIcon( "EDITOR//checkmark.sti" ); iSelectWin = CreateHotSpot(0, 0, 600, 360, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, SelWinClkCallback); - iCancelWin = CreateIconButton((INT16)iButtonIcons[CANCEL_ICON], 0, + iCancelWin = CreateIconButton((INT16)iButtonIcons[SEL_WIN_CANCEL_ICON], 0, BUTTON_USE_DEFAULT, 600, 40, 40, 40, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, CnclClkCallback); SetButtonFastHelpText(iCancelWin,L"Cancel selections"); - iOkWin = CreateIconButton((INT16)iButtonIcons[OK_ICON], 0, + iOkWin = CreateIconButton((INT16)iButtonIcons[SEL_WIN_OK_ICON], 0, BUTTON_USE_DEFAULT, 600, 0, 40, 40, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, OkClkCallback); SetButtonFastHelpText(iOkWin,L"Accept selections"); - iScrollUp = CreateIconButton((INT16)iButtonIcons[UP_ICON], 0, + iScrollUp = CreateIconButton((INT16)iButtonIcons[SEL_WIN_UP_ICON], 0, BUTTON_USE_DEFAULT, 600, 80, 40, 160, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, UpClkCallback); SetButtonFastHelpText(iScrollUp,L"Scroll window up"); - iScrollDown = CreateIconButton((INT16)iButtonIcons[DOWN_ICON], 0, + iScrollDown = CreateIconButton((INT16)iButtonIcons[SEL_WIN_DOWN_ICON], 0, BUTTON_USE_DEFAULT, 600, 240, 40, 160, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, diff --git a/Editor/selectwin.h b/Editor/selectwin.h index fe02e8aa..7d9c8981 100644 --- a/Editor/selectwin.h +++ b/Editor/selectwin.h @@ -10,10 +10,10 @@ #include "mousesystem.h" #include "Button System.h" -#define CANCEL_ICON 0 -#define UP_ICON 1 -#define DOWN_ICON 2 -#define OK_ICON 3 +#define SEL_WIN_CANCEL_ICON 0 +#define SEL_WIN_UP_ICON 1 +#define SEL_WIN_DOWN_ICON 2 +#define SEL_WIN_OK_ICON 3 extern INT32 iButtonIcons[4]; extern INT32 iSelectWin,iCancelWin,iScrollUp,iScrollDown; diff --git a/Fade Screen.cpp b/Fade Screen.cpp index ee6e21b9..9e7d930f 100644 --- a/Fade Screen.cpp +++ b/Fade Screen.cpp @@ -30,7 +30,8 @@ INT32 giX1, giX2, giY1, giY2; INT16 gsFadeRealCount; BOOLEAN gfFadeInVideo; -UINT32 uiOldMusicMode; +// unused +//UINT32 uiOldMusicMode; FADE_FUNCTION gFadeFunction = NULL; @@ -154,7 +155,8 @@ void BeginFade( UINT32 uiExitScreen, INT8 bFadeValue, INT8 bType, UINT32 uiDelay gfFadeIn = FALSE; gfFadeInVideo = TRUE; - uiOldMusicMode = uiMusicHandle; + // unused + //uiOldMusicMode = uiMusicHandle; // Calculate step; diff --git a/GameInitOptionsScreen.cpp b/GameInitOptionsScreen.cpp index 5dacb4c4..041c5ce7 100644 --- a/GameInitOptionsScreen.cpp +++ b/GameInitOptionsScreen.cpp @@ -28,65 +28,122 @@ #include "connect.h" #include "saveloadscreen.h" +#include +#include +#include +#include + +////////////////////////////////////////////////////////////// +// SANDRO - the start-new-game screen has been changed a lot +////////////////////////////////////////////////////////////// + //////////////////////////////////////////// // // Global Defines // /////////////////////////////////////////// -#define GIO_TITLE_FONT FONT14ARIAL//FONT16ARIAL -#define GIO_TITLE_COLOR FONT_MCOLOR_WHITE +#define GIO_TITLE_FONT FONT14ARIAL +#define GIO_TITLE_COLOR FONT_MCOLOR_WHITE -#define GIO_TOGGLE_TEXT_FONT FONT12ARIAL//FONT16ARIAL -#define GIO_TOGGLE_TEXT_COLOR FONT_MCOLOR_WHITE +#define GIO_TOGGLE_TEXT_FONT FONT10ARIAL +#define GIO_TOGGLE_TEXT_COLOR FONT_MCOLOR_WHITE //buttons -#define GIO_BTN_OK_X iScreenWidthOffset + ((320 - 115) / 2) -#define GIO_BTN_OK_Y iScreenHeightOffset + 435 -#define GIO_CANCEL_X iScreenWidthOffset + 320 + 143 +#define GIO_CANCEL_X iScreenWidthOffset + ((320 - 115) / 2) + +#define GIO_BTN_START_X iScreenWidthOffset + 320 + 105 +#define GIO_BTN_START_Y iScreenHeightOffset + 435 + //main title -#define GIO_MAIN_TITLE_X 0 +#define GIO_MAIN_TITLE_X 0 #define GIO_MAIN_TITLE_Y iScreenHeightOffset + 10 #define GIO_MAIN_TITLE_WIDTH SCREEN_WIDTH //radio box locations -#define GIO_GAP_BN_SETTINGS 35 -#define GIO_OFFSET_TO_TEXT 30 -#define GIO_OFFSET_TO_TOGGLE_BOX 250 -#define GIO_OFFSET_TO_TOGGLE_BOX_Y 9 +#define GIO_GAP_BN_SETTINGS 35 +#define GIO_OFFSET_TO_TEXT 36 +#define GIO_OFFSET_TO_TOGGLE_BOX 180 +#define GIO_OFFSET_TO_TOGGLE_BOX_Y 9 -#define GIO_DIF_SETTINGS_X iScreenWidthOffset + 20 -#define GIO_DIF_SETTINGS_Y iScreenHeightOffset + 75 -#define GIO_DIF_SETTINGS_WIDTH GIO_OFFSET_TO_TOGGLE_BOX - GIO_OFFSET_TO_TEXT +#define GIO_TITLE_DISTANCE 30 // higher means closer + +#define GIO_DIF_SETTING_X iScreenWidthOffset + 48 +#define GIO_DIF_SETTING_Y iScreenHeightOffset + 55 +#define GIO_DIF_SETTING_WIDTH GIO_OFFSET_TO_TOGGLE_BOX - GIO_OFFSET_TO_TEXT + +#define GIO_IMP_SETTING_X GIO_DIF_SETTING_X +#define GIO_IMP_SETTING_Y GIO_DIF_SETTING_Y + 63 +#define GIO_IMP_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +// old/new traits +#define GIO_TRAITS_SETTING_X GIO_DIF_SETTING_X + 36 +#define GIO_TRAITS_SETTING_Y GIO_IMP_SETTING_Y + 52 +#define GIO_TRAITS_SETTING_WIDTH GIO_DIF_SETTING_WIDTH // Madd -#define GIO_GAME_SETTINGS_X GIO_DIF_SETTINGS_X -#define GIO_GAME_SETTINGS_Y GIO_GUN_SETTINGS_Y -#define GIO_GAME_SETTINGS_WIDTH GIO_DIF_SETTINGS_WIDTH +#define GIO_GAME_SETTING_X GIO_TRAITS_SETTING_X +#define GIO_GAME_SETTING_Y GIO_TRAITS_SETTING_Y + 67 +#define GIO_GAME_SETTING_WIDTH GIO_DIF_SETTING_WIDTH -#define GIO_GUN_SETTINGS_X GIO_BR_SETTING_X -#define GIO_GUN_SETTINGS_Y iScreenHeightOffset + 242 -#define GIO_GUN_SETTINGS_WIDTH GIO_DIF_SETTINGS_WIDTH +#define GIO_IRON_MAN_SETTING_X GIO_TRAITS_SETTING_X +#define GIO_IRON_MAN_SETTING_Y GIO_GAME_SETTING_Y + 67 +#define GIO_IRON_MAN_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_TERRORISTS_SETTING_X GIO_TRAITS_SETTING_X +#define GIO_TERRORISTS_SETTING_Y GIO_IRON_MAN_SETTING_Y + 67 +#define GIO_TERRORISTS_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_BR_SETTING_X iScreenWidthOffset + 370 +#define GIO_BR_SETTING_Y GIO_DIF_SETTING_Y +#define GIO_BR_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_PROGRESS_SETTING_X GIO_BR_SETTING_X +#define GIO_PROGRESS_SETTING_Y GIO_BR_SETTING_Y + 63 +#define GIO_PROGRESS_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_INV_SETTING_X GIO_PROGRESS_SETTING_X +#define GIO_INV_SETTING_Y GIO_PROGRESS_SETTING_Y + 63 +#define GIO_INV_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_DROPALL_SETTING_X GIO_INV_SETTING_X + 36 +#define GIO_DROPALL_SETTING_Y GIO_INV_SETTING_Y + 56 +#define GIO_DROPALL_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_GUN_SETTING_X GIO_DROPALL_SETTING_X +#define GIO_GUN_SETTING_Y GIO_DROPALL_SETTING_Y + 67 +#define GIO_GUN_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_CACHES_SETTING_X GIO_GUN_SETTING_X +#define GIO_CACHES_SETTING_Y GIO_GUN_SETTING_Y + 67 +#define GIO_CACHES_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +#define GIO_TIMED_TURN_SETTING_X GIO_GUN_SETTING_X +#define GIO_TIMED_TURN_SETTING_Y GIO_IRON_MAN_SETTING_Y +#define GIO_TIMED_TURN_SETTING_WIDTH GIO_DIF_SETTING_WIDTH + +// INI File +#define JA2SP_INI_FILENAME "ja2_sp.ini" + +// INI Section +#define JA2SP_INI_INITIAL_SECTION "JA2 Singleplayer Initial Settings" + +// INI Properties +#define JA2SP_DIFFICULTY_LEVEL "DIFFICULTY_LEVEL" +#define JA2SP_BOBBY_RAY_SELECTION "BOBBY_RAY_SELECTION" +#define JA2SP_MAX_IMP_CHARACTERS "MAX_IMP_CHARACTERS" +#define JA2SP_PROGRESS_SPEED_OF_ITEM_CHOICES "PROGRESS_SPEED_OF_ITEM_CHOICES" +#define JA2SP_SKILL_TRAITS "SKILL_TRAITS" +#define JA2SP_INVENTORY_ATTACHMENTS "INVENTORY_ATTACHMENTS" +#define JA2SP_GAME_STYLE "GAME_STYLE" +#define JA2SP_ENEMIES_DROP_ALL_ITEMS "ENEMIES_DROP_ALL_ITEMS" +#define JA2SP_EXTRA_DIFFICULTY "EXTRA_DIFFICULTY" +#define JA2SP_AVAILABLE_ARSENAL "AVAILABLE_ARSENAL" +#define JA2SP_NUMBER_OF_TERRORISTS "NUMBER_OF_TERRORISTS" +#define JA2SP_SECRET_WEAPON_CACHES "SECRET_WEAPON_CACHES" -#define GIO_TIMED_TURN_SETTING_X GIO_GUN_SETTINGS_X -#define GIO_TIMED_TURN_SETTING_Y GIO_IRON_MAN_SETTING_Y//hayden -#define GIO_TIMED_TURN_SETTING_WIDTH GIO_DIF_SETTINGS_WIDTH - - -// Madd -#define GIO_BR_SETTING_X iScreenWidthOffset + 340 -#define GIO_BR_SETTING_Y GIO_DIF_SETTINGS_Y -#define GIO_BR_SETTING_WIDTH GIO_DIF_SETTINGS_WIDTH -#define GIO_IRON_MAN_SETTING_X iScreenWidthOffset + 20 -#define GIO_IRON_MAN_SETTING_Y iScreenHeightOffset + 355 -#define GIO_IRON_MAN_SETTING_WIDTH GIO_DIF_SETTINGS_WIDTH - -// CHRISL: -#define GIO_INV_SETTING_X iScreenWidthOffset + 340 -#define GIO_INV_SETTING_Y GIO_IRON_MAN_SETTING_Y -#define GIO_INV_SETTING_WIDTH GIO_DIF_SETTINGS_WIDTH //Difficulty settings enum @@ -95,29 +152,44 @@ enum GIO_DIFF_MED, GIO_DIFF_HARD, GIO_DIFF_INSANE, + NUM_DIFF_SETTINGS, }; +enum +{ + GIO_TRAITS_OLD, + GIO_TRAITS_NEW, + + NUM_TRAIT_OPTIONS, +}; + // Game Settings options enum { GIO_REALISTIC, - GIO_SCI_FI, - //GIO_PLATINUM, + GIO_SCI_FI, NUM_GAME_STYLES, }; -// Gun options +// Iron man mode enum { - GIO_REDUCED_GUNS, - GIO_GUN_NUT, + GIO_CAN_SAVE, + GIO_IRON_MAN, - NUM_GUN_OPTIONS, + NUM_SAVE_OPTIONS, +}; + +enum +{ + GIO_TERRORISTS_RANDOM, + GIO_TERRORISTS_ALL, + + NUM_TERRORISTS_OPTIONS, }; -// Madd // BR options enum { @@ -129,38 +201,63 @@ enum NUM_BR_OPTIONS, }; -// CHRISL: New inventory options +enum +{ + GIO_PROGRESS_VERY_SLOW, + GIO_PROGRESS_SLOW, + GIO_PROGRESS_NORMAL, + GIO_PROGRESS_FAST, + GIO_PROGRESS_VERY_FAST, + + NUM_PROGRESS_OPTIONS, +}; + +// New inventory options enum { GIO_INV_OLD, GIO_INV_NEW, + GIO_INV_NEW_NAS, // WANNE: Added NAS to the start new game screen NUM_INV_OPTIONS, }; -// JA2Gold: no more timed turns setting +enum +{ + GIO_DROPALL_OFF, + GIO_DROPALL_ON, + + NUM_DROPALL_OPTIONS, +}; + +// Gun options +enum +{ + GIO_REDUCED_GUNS, + GIO_GUN_NUT, + + NUM_GUN_OPTIONS, +}; + +enum +{ + GIO_CACHES_RANDOM, + GIO_CACHES_ALL, + + NUM_CACHES_OPTIONS, +}; -//enum for the timed turns setting +// Timed turns setting (Multiplayer exclusive) enum { GIO_NO_TIMED_TURNS, GIO_TIMED_TURNS, GIO_NUM_TIMED_TURN_OPTIONS, -};//hayden : re-enabled - - -// Iron man mode - -enum -{ - GIO_CAN_SAVE, - GIO_IRON_MAN, - - NUM_SAVE_OPTIONS, }; + //enum for different states of game enum { @@ -182,27 +279,22 @@ BOOLEAN gfGIOScreenExit = FALSE; BOOLEAN gfReRenderGIOScreen=TRUE; BOOLEAN gfGIOButtonsAllocated = FALSE; -UINT8 gubGameOptionScreenHandler=GIO_NOTHING; +UINT8 gubGameOptionScreenHandler=GIO_NOTHING; UINT32 gubGIOExitScreen = GAME_INIT_OPTIONS_SCREEN; UINT32 guiGIOMainBackGroundImage; +INT32 giGioMessageBox = -1; -INT32 giGioMessageBox = -1; -//BOOLEAN gfExitGioDueToMessageBox=FALSE; +INT8 iCurrentDifficulty; +INT8 iCurrentBRSetting; +INT8 iCurrentIMPNumberSetting; +INT8 iCurrentProgressSetting; +INT8 iCurrentInventorySetting; -//UINT8 gubDifficultySettings[ NUM_DIFF_SETTINGS ]; -//UINT8 gubGameSettings[ NUM_GAME_STYLES ]; -//UINT8 gubGunSettings[ NUM_GUN_OPTIONS ]; - -//extern INT32 gp16PointArial; - - -// CHRISL: checkbox to toggle INV selection -UINT32 guiINVOptionToggles[ NUM_INV_OPTIONS ]; -void BtnINVOptionTogglesCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 guiGIOSMALLFRAME; // Done Button void BtnGIODoneCallback(GUI_BUTTON *btn,INT32 reason); @@ -219,34 +311,75 @@ void MPBtnGIOCancelCallback(GUI_BUTTON *btn,INT32 reason); UINT32 MPguiGIOCancelButton; INT32 MPgiGIOCancelBtnImage; +UINT32 giGIODifficultyButton[ 2 ]; +INT32 giGIODifficultyButtonImage[ 2 ]; +void BtnGIODifficultySelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnGIODifficultySelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); -//checkbox to toggle the Diff level -UINT32 guiDifficultySettingsToggles[ NUM_DIFF_SETTINGS ]; -void BtnDifficultyTogglesCallback(GUI_BUTTON *btn,INT32 reason); +UINT32 giGIOIMPNumberButton[ 2 ]; +INT32 giGIOIMPNumberButtonImage[ 2 ]; +void BtnGIOIMPNumberSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnGIOIMPNumberSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +UINT32 giGIOBRSettingButton[ 2 ]; +INT32 giGIOBRSettingButtonImage[ 2 ]; +void BtnGIOBRSettingLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnGIOBRSettingRightCallback( GUI_BUTTON *btn,INT32 reason ); + +UINT32 giGIOProgressSettingButton[ 2 ]; +INT32 giGIOProgressSettingButtonImage[ 2 ]; +void BtnGIOProgressSettingLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnGIOProgressSettingRightCallback( GUI_BUTTON *btn,INT32 reason ); + +UINT32 giGIOInventorySettingButton [ 2 ]; +INT32 giGIOInventorySettingButtonImage [ 2 ]; +void BtnGIOInventorySettingLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnGIOInventorySettingRightCallback( GUI_BUTTON *btn,INT32 reason ); + +UINT32 guiTraitsOptionTogglesImage[ NUM_TRAIT_OPTIONS ]; +UINT32 guiTraitsOptionToggles[ NUM_TRAIT_OPTIONS ]; +void BtnGIOOldTraitsCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIONewTraitsCallback(GUI_BUTTON *btn,INT32 reason); +void NewTraitsNotPossibleMessageBoxCallBack( UINT8 bExitValue ); //checkbox to toggle Game style +UINT32 guiGameStyleTogglesImage[ NUM_GAME_STYLES ]; UINT32 guiGameStyleToggles[ NUM_GAME_STYLES ]; -void BtnGameStyleTogglesCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIORealisticStyleCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIOScifiStyleCallback(GUI_BUTTON *btn,INT32 reason); + +//checkbox to toggle Save style +UINT32 guiGameSaveTogglesImage[ NUM_SAVE_OPTIONS ]; +UINT32 guiGameSaveToggles[ NUM_SAVE_OPTIONS ]; +void BtnGIOIronManOffCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIOIronManOnCallback(GUI_BUTTON *btn,INT32 reason); + +UINT32 guiTerroristsOptionTogglesImage[ NUM_TERRORISTS_OPTIONS ]; +UINT32 guiTerroristsOptionToggles[ NUM_TERRORISTS_OPTIONS ]; +void BtnGIOTerroristsRandomCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIOTerroristsAllCallback(GUI_BUTTON *btn,INT32 reason); + +UINT32 guiDropAllOptionTogglesImage[ NUM_DROPALL_OPTIONS ]; +UINT32 guiDropAllOptionToggles[ NUM_DROPALL_OPTIONS ]; +void BtnGIODropAllOffCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIODropAllOnCallback(GUI_BUTTON *btn,INT32 reason); //checkbox to toggle Gun options +UINT32 guiGunOptionTogglesImage[ NUM_GUN_OPTIONS ]; UINT32 guiGunOptionToggles[ NUM_GUN_OPTIONS ]; -void BtnGunOptionsTogglesCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIOGunSettingReducedCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIOGunSettingToGCallback(GUI_BUTTON *btn,INT32 reason); + +UINT32 guiWeaponCachesOptionTogglesImage[ NUM_CACHES_OPTIONS ]; +UINT32 guiWeaponCachesOptionToggles[ NUM_CACHES_OPTIONS ]; +void BtnGIOWeaponCachesRandomCallback(GUI_BUTTON *btn,INT32 reason); +void BtnGIOWeaponCachesAllCallback(GUI_BUTTON *btn,INT32 reason); + -// JA2Gold: no more timed turns setting -//hayden : re-enabled -//checkbox to toggle Timed turn option on or off UINT32 guiTimedTurnToggles[ GIO_NUM_TIMED_TURN_OPTIONS ]; void BtnTimedTurnsTogglesCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox to toggle Save style -UINT32 guiGameSaveToggles[ NUM_SAVE_OPTIONS ]; -void BtnGameSaveTogglesCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox to toggle BR selection -UINT32 guiBROptionToggles[ NUM_BR_OPTIONS ]; -void BtnBROptionTogglesCallback(GUI_BUTTON *btn,INT32 reason); - +void RenderGIOSmallSelectionFrame(INT16 sX, INT16 sY); //////////////////////////////////////////// // @@ -265,24 +398,131 @@ UINT8 GetCurrentGunButtonSetting(); // JA2Gold: added save (iron man) button setting UINT8 GetCurrentGameSaveButtonSetting(); UINT8 GetCurrentGameStyleButtonSetting(); -UINT8 GetCurrentDifficultyButtonSetting(); -void RestoreGIOButtonBackGrounds(); -void DoneFadeOutForExitGameInitOptionScreen( void ); -void DoneFadeInForExitGameInitOptionScreen( void ); -// JA2Gold: no more timed turns setting -UINT8 GetCurrentTimedTurnsButtonSetting();//hayden : re-enabled -BOOLEAN DoGioMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); -void DisplayMessageToUserAboutGameDifficulty(); -void ConfirmGioDifSettingMessageBoxCallBack( UINT8 bExitValue ); -BOOLEAN DisplayMessageToUserAboutIronManMode(); -void ConfirmGioIronManMessageBoxCallBack( UINT8 bExitValue ); +// SANDRO - added following +UINT8 GetCurrentTraitsOptionButtonSetting(); +UINT8 GetCurrentDropAllButtonSetting(); +UINT8 GetCurrentTerroristsButtonSetting(); +UINT8 GetCurrentWeaponCachesButtonSetting(); + +void DoneFadeOutForExitGameInitOptionScreen( void ); +void DoneFadeInForExitGameInitOptionScreen( void ); +UINT8 GetCurrentTimedTurnsButtonSetting(); +BOOLEAN DoGioMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); +void DisplayMessageToUserAboutGameDifficulty(); +void ConfirmGioDifSettingMessageBoxCallBack( UINT8 bExitValue ); +BOOLEAN DisplayMessageToUserAboutIronManMode(); +BOOLEAN DisplayMessageToUserAboutOIVandNASincompatibility(); +void ConfirmGioIronManMessageBoxCallBack( UINT8 bExitValue ); + +BOOLEAN SpIniExists() +{ + BOOLEAN exists = TRUE; + + if(!getVFS()->fileExists(JA2SP_INI_FILENAME)) + exists = FALSE; + + return exists; +} UINT32 GameInitOptionsScreenInit( void ) { - return( 1 ); -} + memset( &gGameOptions, 0, sizeof( GAME_OPTIONS ) ); + // WANNE: Read initial game settings from ja2_sp.ini + vfs::PropertyContainer props; + + if (SpIniExists()) + props.initFromIniFile(JA2SP_INI_FILENAME); + + // Difficulty Level (Default: Experienced = 1) + gGameOptions.ubDifficultyLevel = ((UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_DIFFICULTY_LEVEL, 1)) + 1; + + // Bobby Ray's Selection (Default: Great = 1) + UINT8 ubBobbyRay = (UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_BOBBY_RAY_SELECTION, 1); + switch (ubBobbyRay) + { + // Normal + case 0: + gGameOptions.ubBobbyRay = BR_GOOD; + break; + // Great + case 1: + gGameOptions.ubBobbyRay = BR_GREAT; + break; + // Excellent + case 2: + gGameOptions.ubBobbyRay = BR_EXCELLENT; + break; + // Awesome + case 3: + gGameOptions.ubBobbyRay = BR_AWESOME; + break; + } + + // Max. IMP Characters + UINT8 maxIMPCharacterCount = (UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_MAX_IMP_CHARACTERS, 1); + gGameOptions.ubMaxIMPCharacters = min( (gGameExternalOptions.iIMPMaleCharacterCount + gGameExternalOptions.iIMPFemaleCharacterCount), ( max( 1, maxIMPCharacterCount) )); + + // Progress Speed of Item Choices (Default: Normal) + gGameOptions.ubProgressSpeedOfItemsChoices = (UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_PROGRESS_SPEED_OF_ITEM_CHOICES, ITEM_PROGRESS_NORMAL); + + // Skill Traits + UINT8 ubTraitSystem = (UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_SKILL_TRAITS, 1); + if (!gGameExternalOptions.fReadProfileDataFromXML) + ubTraitSystem = 0; + + gGameOptions.fNewTraitSystem = ubTraitSystem; + + // Inventory Attachments (Default: New/New = 2) + UINT8 ubInventoryAttachmentSystem = (UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_INVENTORY_ATTACHMENTS, 2); + + // NIV is not allowed + if (!IsNIVModeValid(true)) + ubInventoryAttachmentSystem = 0; + + switch (ubInventoryAttachmentSystem) + { + // Old / Old + case 0: + gGameOptions.ubInventorySystem = INVENTORY_OLD; + gGameOptions.ubAttachmentSystem = ATTACHMENT_OLD; + break; + // New / Old + case 1: + gGameOptions.ubInventorySystem = INVENTORY_NEW; + gGameOptions.ubAttachmentSystem = ATTACHMENT_OLD; + break; + // New / New + case 2: + gGameOptions.ubInventorySystem = INVENTORY_NEW; + gGameOptions.ubAttachmentSystem = ATTACHMENT_NEW; + break; + } + + // Game Style (Default: Realistic = 0) + gGameOptions.ubGameStyle = (UINT8)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_GAME_STYLE, STYLE_REALISTIC); + + // Enemies Drop All Items (Default: Off = 0) + gGameOptions.fEnemiesDropAllItems = (BOOLEAN)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_ENEMIES_DROP_ALL_ITEMS, 0); + + // Extra Difficulty (Default: Save Anytime = 0) + gGameOptions.fIronManMode = (BOOLEAN)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_EXTRA_DIFFICULTY, 0); + + // Available Arsenal (Default: Tons of Guns = 1) + gGameOptions.fGunNut = (BOOLEAN)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_AVAILABLE_ARSENAL, 1); + + // Number of Terrorists (Default: Random = 0) + gGameOptions.fEnableAllTerrorists = (BOOLEAN)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_NUMBER_OF_TERRORISTS, 0); + + // Secret Weapon Caches (Default: Random = 0) + gGameOptions.fEnableAllWeaponCaches = (BOOLEAN)props.getIntProperty(JA2SP_INI_INITIAL_SECTION, JA2SP_SECRET_WEAPON_CACHES, 0); + + gGameOptions.fAirStrikes = FALSE; + gGameOptions.fTurnTimeLimit = FALSE; + + return (1); +} UINT32 GameInitOptionsScreenHandle( void ) { @@ -290,7 +530,7 @@ UINT32 GameInitOptionsScreenHandle( void ) if( gfGIOScreenEntry ) { -// PauseGame(); + GameInitOptionsScreenInit(); EnterGIOScreen(); gfGIOScreenEntry = FALSE; @@ -300,18 +540,12 @@ UINT32 GameInitOptionsScreenHandle( void ) GetGIOScreenUserInput(); - HandleGIOScreen(); // render buttons marked dirty MarkButtonsDirty( ); RenderButtons( ); - // render help -// RenderFastHelp( ); -// RenderButtonsFastHelp( ); - - ExecuteBaseDirtyRectQueue(); EndFrameBufferRender(); @@ -353,10 +587,8 @@ UINT32 GameInitOptionsScreenShutdown( void ) BOOLEAN EnterGIOScreen() { - VOBJECT_DESC VObjectDesc; - UINT16 cnt; - UINT16 usPosY; - + VOBJECT_DESC VObjectDesc, VObjectDesc2; + if( gfGIOButtonsAllocated ) return( TRUE ); @@ -380,13 +612,17 @@ BOOLEAN EnterGIOScreen() CHECKF(AddVideoObject(&VObjectDesc, &guiGIOMainBackGroundImage )); + VObjectDesc2.fCreateFlags=VOBJECT_CREATE_FROMFILE; + FilenameForBPP("INTERFACE\\GIOSmallFrame.sti", VObjectDesc2.ImageFile); + CHECKF(AddVideoObject(&VObjectDesc2, &guiGIOSMALLFRAME)); + //Ok button giGIODoneBtnImage = LoadButtonImage("INTERFACE\\PreferencesButtons.sti", -1,0,-1,2,-1 ); - guiGIODoneButton = CreateIconAndTextButton( giGIODoneBtnImage, gzGIOScreenText[GIO_OK_TEXT], OPT_BUTTON_FONT, + guiGIODoneButton = CreateIconAndTextButton( giGIODoneBtnImage, gzGIOScreenText[GIO_START_TEXT], OPT_BUTTON_FONT, OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, TEXT_CJUSTIFIED, - GIO_BTN_OK_X, GIO_BTN_OK_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + GIO_BTN_START_X, GIO_BTN_START_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, BtnGIODoneCallback); SpecifyButtonSoundScheme( guiGIODoneButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); @@ -398,188 +634,364 @@ BOOLEAN EnterGIOScreen() OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, TEXT_CJUSTIFIED, - GIO_CANCEL_X, GIO_BTN_OK_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + GIO_CANCEL_X, GIO_BTN_START_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, DEFAULT_MOVE_CALLBACK, BtnGIOCancelCallback ); SpecifyButtonSoundScheme( guiGIOCancelButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); - //MP button - if(is_networked) - { - MPgiGIOCancelBtnImage = UseLoadedButtonImage( giGIODoneBtnImage, -1,1,-1,3,-1 ); - MPguiGIOCancelButton = CreateIconAndTextButton( giGIOCancelBtnImage, gzGIOScreenText[GIO_LOAD_MP_GAME], OPT_BUTTON_FONT, - OPT_BUTTON_ON_COLOR, DEFAULT_SHADOW, - OPT_BUTTON_OFF_COLOR, DEFAULT_SHADOW, + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // DIFFICULTY SETTING + + giGIODifficultyButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giGIODifficultyButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giGIODifficultyButton[ 0 ] = QuickCreateButton( giGIODifficultyButtonImage[ 0 ], GIO_DIF_SETTING_X + 39, GIO_DIF_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnGIODifficultySelectionLeftCallback ); + + // right button - increment difficulty level + giGIODifficultyButton[ 1 ] = QuickCreateButton( giGIODifficultyButtonImage[ 1 ], GIO_DIF_SETTING_X + 158, GIO_DIF_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnGIODifficultySelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giGIODifficultyButton[0],0, 0 ); + MSYS_SetBtnUserData(giGIODifficultyButton[1],0, 1 ); + + iCurrentDifficulty = max( 0, gGameOptions.ubDifficultyLevel - 1); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // MAX IMP NUMBER SETTING + + giGIOIMPNumberButtonImage[ 0 ]= UseLoadedButtonImage( giGIODifficultyButtonImage[ 0 ],-1,0,-1,1,-1 ); + giGIOIMPNumberButtonImage[ 1 ]= UseLoadedButtonImage( giGIODifficultyButtonImage[ 1 ],-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giGIOIMPNumberButton[ 0 ] = QuickCreateButton( giGIOIMPNumberButtonImage[ 0 ], GIO_IMP_SETTING_X + 39, GIO_IMP_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnGIOIMPNumberSelectionLeftCallback ); + + // right button - increment difficulty level + giGIOIMPNumberButton[ 1 ] = QuickCreateButton( giGIOIMPNumberButtonImage[ 1 ], GIO_IMP_SETTING_X + 158, GIO_IMP_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnGIOIMPNumberSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giGIOIMPNumberButton[0],0, 0 ); + MSYS_SetBtnUserData(giGIOIMPNumberButton[1],0, 1 ); + + iCurrentIMPNumberSetting = gGameOptions.ubMaxIMPCharacters; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // OLD/NEW TARITS SETTING + + guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiTraitsOptionToggles[ GIO_TRAITS_OLD ] = CreateIconAndTextButton( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], gzGIOScreenText[ GIO_TRAITS_OLD_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, TEXT_CJUSTIFIED, - GIO_CANCEL_X-180, GIO_BTN_OK_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, - DEFAULT_MOVE_CALLBACK, MPBtnGIOCancelCallback ); - SpecifyButtonSoundScheme( guiGIOCancelButton, BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + (GIO_TRAITS_SETTING_X + 74), (GIO_TRAITS_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOOldTraitsCallback); - } - // - //Check box to toggle Difficulty settings - // - usPosY = GIO_DIF_SETTINGS_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; + guiTraitsOptionTogglesImage[ GIO_TRAITS_NEW ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiTraitsOptionToggles[ GIO_TRAITS_NEW ] = CreateIconAndTextButton( guiTraitsOptionTogglesImage[ GIO_TRAITS_NEW ], gzGIOScreenText[ GIO_TRAITS_NEW_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_TRAITS_SETTING_X), (GIO_TRAITS_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIONewTraitsCallback ); - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; - - else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM ) - ButtonList[ guiDifficultySettingsToggles[ GIO_DIFF_MED ] ]->uiFlags |= BUTTON_CLICKED_ON; - - else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD ) - ButtonList[ guiDifficultySettingsToggles[ GIO_DIFF_HARD ] ]->uiFlags |= BUTTON_CLICKED_ON; - - else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) - ButtonList[ guiDifficultySettingsToggles[ GIO_DIFF_INSANE ] ]->uiFlags |= BUTTON_CLICKED_ON; + SpecifyButtonSoundScheme( guiTraitsOptionToggles[ GIO_TRAITS_OLD ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiTraitsOptionToggles[ GIO_TRAITS_NEW ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiTraitsOptionToggles[ GIO_TRAITS_OLD ],0, 0 ); + MSYS_SetBtnUserData(guiTraitsOptionToggles[ GIO_TRAITS_NEW ],0, 1 ); + if( gGameOptions.fNewTraitSystem ) + ButtonList[ guiTraitsOptionToggles[ GIO_TRAITS_NEW ] ]->uiFlags |= BUTTON_CLICKED_ON; else - ButtonList[ guiDifficultySettingsToggles[ GIO_DIFF_MED ] ]->uiFlags |= BUTTON_CLICKED_ON; + ButtonList[ guiTraitsOptionToggles[ GIO_TRAITS_OLD ] ]->uiFlags |= BUTTON_CLICKED_ON; + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // GAME SETTING ( realistic, sci fi ) - // - //Check box to toggle Game settings ( realistic, sci fi ) - // + guiGameStyleTogglesImage[ GIO_REALISTIC ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiGameStyleToggles[ GIO_REALISTIC ] = CreateIconAndTextButton( guiGameStyleTogglesImage[ GIO_REALISTIC ], gzGIOScreenText[ GIO_REALISTIC_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_GAME_SETTING_X + 74), (GIO_GAME_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIORealisticStyleCallback); - usPosY = GIO_GAME_SETTINGS_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; - else // if(gGameOptions.ubGameStyle == STYLE_REALISTIC) - ButtonList[ guiGameStyleToggles[ GIO_REALISTIC ] ]->uiFlags |= BUTTON_CLICKED_ON; -// else -// ButtonList[ guiGameStyleToggles[ GIO_PLATINUM ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiGameStyleToggles[ GIO_REALISTIC ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // IRON MAN SETTING + + guiGameSaveTogglesImage[ GIO_CAN_SAVE ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiGameSaveToggles[ GIO_CAN_SAVE ] = CreateIconAndTextButton( guiGameSaveTogglesImage[ GIO_CAN_SAVE ], gzGIOScreenText[ GIO_SAVE_ANYWHERE_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_IRON_MAN_SETTING_X), (GIO_IRON_MAN_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOIronManOffCallback); + + guiGameSaveTogglesImage[ GIO_IRON_MAN ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiGameSaveToggles[ GIO_IRON_MAN ] = CreateIconAndTextButton( guiGameSaveTogglesImage[ GIO_IRON_MAN ], gzGIOScreenText[ GIO_IRON_MAN_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_IRON_MAN_SETTING_X + 74), (GIO_IRON_MAN_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOIronManOnCallback ); + + SpecifyButtonSoundScheme( guiGameSaveToggles[ GIO_CAN_SAVE ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiGameSaveToggles[ GIO_IRON_MAN ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiGameSaveToggles[ GIO_CAN_SAVE ],0, 0 ); + MSYS_SetBtnUserData(guiGameSaveToggles[ GIO_IRON_MAN ],0, 1 ); + + if( gGameOptions.fIronManMode ) + ButtonList[ guiGameSaveToggles[ GIO_IRON_MAN ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiGameSaveToggles[ GIO_CAN_SAVE ] ]->uiFlags |= BUTTON_CLICKED_ON; - // Madd - usPosY = GIO_BR_SETTING_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiTerroristsOptionToggles[ GIO_TERRORISTS_RANDOM ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // BOBBY RAY SETTING + + giGIOBRSettingButtonImage[ 0 ]= UseLoadedButtonImage( giGIODifficultyButtonImage[ 0 ], -1,0,-1,1,-1 ); + giGIOBRSettingButtonImage[ 1 ]= UseLoadedButtonImage( giGIODifficultyButtonImage[ 1 ], -1,2,-1,3,-1 ); + + // left button - decrement BR level + giGIOBRSettingButton[ 0 ] = QuickCreateButton( giGIOBRSettingButtonImage[ 0 ], GIO_BR_SETTING_X + 39, GIO_BR_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnGIOBRSettingLeftCallback ); + + // right button - increment BR level + giGIOBRSettingButton[ 1 ] = QuickCreateButton( giGIOBRSettingButtonImage[ 1 ], GIO_BR_SETTING_X + 158, GIO_BR_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnGIOBRSettingRightCallback ); + + // set user data + MSYS_SetBtnUserData(giGIOBRSettingButton[0],0, 0 ); + MSYS_SetBtnUserData(giGIOBRSettingButton[1],0, 1 ); + + // set initial value + switch ( gGameOptions.ubBobbyRay ) { case BR_GOOD: - ButtonList[ guiBROptionToggles[ GIO_BR_GOOD ] ]->uiFlags |= BUTTON_CLICKED_ON; + iCurrentBRSetting = GIO_BR_GOOD; break; case BR_GREAT: - ButtonList[ guiBROptionToggles[ GIO_BR_GREAT ] ]->uiFlags |= BUTTON_CLICKED_ON; + iCurrentBRSetting = GIO_BR_GREAT; break; case BR_EXCELLENT: - ButtonList[ guiBROptionToggles[ GIO_BR_EXCELLENT ] ]->uiFlags |= BUTTON_CLICKED_ON; + iCurrentBRSetting = GIO_BR_EXCELLENT; break; case BR_AWESOME: - ButtonList[ guiBROptionToggles[ GIO_BR_AWESOME ] ]->uiFlags |= BUTTON_CLICKED_ON; + iCurrentBRSetting = GIO_BR_AWESOME; + break; + default: + iCurrentBRSetting = GIO_BR_GOOD; // optimistically assume, we have selected the normal one break; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // ITEM PROGRESS SETTING + + giGIOProgressSettingButtonImage[ 0 ]= UseLoadedButtonImage( giGIODifficultyButtonImage[ 0 ], -1,0,-1,1,-1 ); + giGIOProgressSettingButtonImage[ 1 ]= UseLoadedButtonImage( giGIODifficultyButtonImage[ 1 ], -1,2,-1,3,-1 ); - // CHRISL: New inventory options - if (!is_networked) - { - if(IsNIVModeValid() == TRUE){ - usPosY = GIO_INV_SETTING_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + iCurrentInventorySetting = GIO_INV_OLD; break; case INVENTORY_NEW: - ButtonList[ guiINVOptionToggles[ GIO_INV_NEW ] ]->uiFlags |= BUTTON_CLICKED_ON; + iCurrentInventorySetting = GIO_INV_NEW; break; } } } - // JA2Gold: iron man buttons - usPosY = GIO_IRON_MAN_SETTING_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + guiDropAllOptionTogglesImage[ GIO_DROPALL_OFF ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiDropAllOptionToggles[ GIO_DROPALL_OFF ] = CreateIconAndTextButton( guiDropAllOptionTogglesImage[ GIO_DROPALL_OFF ], gzGIOScreenText[ GIO_DROPALL_OFF_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_DROPALL_SETTING_X), (GIO_DROPALL_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIODropAllOffCallback); + + guiDropAllOptionTogglesImage[ GIO_DROPALL_ON ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiDropAllOptionToggles[ GIO_DROPALL_ON ] = CreateIconAndTextButton( guiDropAllOptionTogglesImage[ GIO_DROPALL_ON ], gzGIOScreenText[ GIO_DROPALL_ON_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_DROPALL_SETTING_X + 74), (GIO_DROPALL_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIODropAllOnCallback ); + + SpecifyButtonSoundScheme( guiDropAllOptionToggles[ GIO_DROPALL_OFF ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiDropAllOptionToggles[ GIO_DROPALL_ON ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiDropAllOptionToggles[ GIO_DROPALL_OFF ],0, 0 ); + MSYS_SetBtnUserData(guiDropAllOptionToggles[ GIO_DROPALL_ON ],0, 1 ); + + if( gGameOptions.fEnemiesDropAllItems ) + ButtonList[ guiDropAllOptionToggles[ GIO_DROPALL_ON ] ]->uiFlags |= BUTTON_CLICKED_ON; else - ButtonList[ guiGameSaveToggles[ GIO_CAN_SAVE ] ]->uiFlags |= BUTTON_CLICKED_ON; + ButtonList[ guiDropAllOptionToggles[ GIO_DROPALL_OFF ] ]->uiFlags |= BUTTON_CLICKED_ON; + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // GUN SETTING + guiGunOptionTogglesImage[ GIO_REDUCED_GUNS ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiGunOptionToggles[ GIO_REDUCED_GUNS ] = CreateIconAndTextButton( guiGunOptionTogglesImage[ GIO_REDUCED_GUNS ], gzGIOScreenText[ GIO_REDUCED_GUNS_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_GUN_SETTING_X + 74), (GIO_GUN_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOGunSettingReducedCallback); - // - // Check box to toggle Gun options - // + guiGunOptionTogglesImage[ GIO_GUN_NUT ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiGunOptionToggles[ GIO_GUN_NUT ] = CreateIconAndTextButton( guiGunOptionTogglesImage[ GIO_GUN_NUT ], gzGIOScreenText[ GIO_GUN_NUT_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_GUN_SETTING_X), (GIO_GUN_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOGunSettingToGCallback ); - usPosY = GIO_GUN_SETTINGS_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; else ButtonList[ guiGunOptionToggles[ GIO_REDUCED_GUNS ] ]->uiFlags |= BUTTON_CLICKED_ON; -// JA2 Gold: no more timed turns - // - // Check box to toggle the timed turn option - // -/* - usPosY = GIO_TIMED_TURN_SETTING_Y - GIO_OFFSET_TO_TOGGLE_BOX_Y; - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // WEAPON CACHES SETTING + + guiWeaponCachesOptionTogglesImage[ GIO_CACHES_RANDOM ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiWeaponCachesOptionToggles[ GIO_CACHES_RANDOM ] = CreateIconAndTextButton( guiWeaponCachesOptionTogglesImage[ GIO_CACHES_RANDOM ], gzGIOScreenText[ GIO_CACHES_RANDOM_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_CACHES_SETTING_X), (GIO_CACHES_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOWeaponCachesRandomCallback); + + guiWeaponCachesOptionTogglesImage[ GIO_CACHES_ALL ] = UseLoadedButtonImage( guiTraitsOptionTogglesImage[ GIO_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiWeaponCachesOptionToggles[ GIO_CACHES_ALL ] = CreateIconAndTextButton( guiWeaponCachesOptionTogglesImage[ GIO_CACHES_ALL ], gzGIOScreenText[ GIO_CACHES_ALL_TEXT ], GIO_TOGGLE_TEXT_FONT, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + GIO_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (GIO_CACHES_SETTING_X + 74), (GIO_CACHES_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnGIOWeaponCachesAllCallback ); + + SpecifyButtonSoundScheme( guiWeaponCachesOptionToggles[ GIO_CACHES_RANDOM ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiWeaponCachesOptionToggles[ GIO_CACHES_ALL ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiWeaponCachesOptionToggles[ GIO_CACHES_RANDOM ],0, 0 ); + MSYS_SetBtnUserData(guiWeaponCachesOptionToggles[ GIO_CACHES_ALL ],0, 1 ); + + if( gGameOptions.fEnableAllWeaponCaches ) + ButtonList[ guiWeaponCachesOptionToggles[ GIO_CACHES_ALL ] ]->uiFlags |= BUTTON_CLICKED_ON; else - ButtonList[ guiTimedTurnToggles[ GIO_NO_TIMED_TURNS ] ]->uiFlags |= BUTTON_CLICKED_ON; -*/ - + ButtonList[ guiWeaponCachesOptionToggles[ GIO_CACHES_RANDOM ] ]->uiFlags |= BUTTON_CLICKED_ON; //Reset the exit screen @@ -595,6 +1007,679 @@ BOOLEAN EnterGIOScreen() return( TRUE ); } +void BtnGIODifficultySelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentDifficulty > 0 ) + { + PlayButtonSound( giGIODifficultyButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentDifficulty--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIODifficultyButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentDifficulty > 0 ) + { + PlayButtonSound( giGIODifficultyButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentDifficulty--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIODifficultyButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIODifficultySelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentDifficulty < 3 ) + { + PlayButtonSound( giGIODifficultyButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentDifficulty++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIODifficultyButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentDifficulty < 3 ) + { + PlayButtonSound( giGIODifficultyButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentDifficulty++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIODifficultyButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOBRSettingLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentBRSetting > 0 ) + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentBRSetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentBRSetting > 0 ) + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentBRSetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOBRSettingRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentBRSetting < 3 ) + { + PlayButtonSound( giGIOBRSettingButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentBRSetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOBRSettingButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentBRSetting < 3 ) + { + PlayButtonSound( giGIOBRSettingButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentBRSetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOBRSettingButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOIMPNumberSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentIMPNumberSetting > 1 ) + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentIMPNumberSetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentIMPNumberSetting > 1 ) + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentIMPNumberSetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOBRSettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOIMPNumberSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentIMPNumberSetting < (gGameExternalOptions.iIMPMaleCharacterCount + gGameExternalOptions.iIMPFemaleCharacterCount) ) + { + PlayButtonSound( giGIOIMPNumberButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentIMPNumberSetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOIMPNumberButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentIMPNumberSetting < (gGameExternalOptions.iIMPMaleCharacterCount + gGameExternalOptions.iIMPFemaleCharacterCount) ) + { + PlayButtonSound( giGIOIMPNumberButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentIMPNumberSetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOIMPNumberButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOInventorySettingLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentInventorySetting > GIO_INV_OLD ) + { + PlayButtonSound( giGIOInventorySettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentInventorySetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOInventorySettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentInventorySetting > GIO_INV_OLD ) + { + PlayButtonSound( giGIOInventorySettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentInventorySetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOInventorySettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOInventorySettingRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentInventorySetting < GIO_INV_NEW_NAS ) + { + PlayButtonSound( giGIOIMPNumberButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentInventorySetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOInventorySettingButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentInventorySetting < GIO_INV_NEW_NAS ) + { + PlayButtonSound( giGIOInventorySettingButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentInventorySetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOInventorySettingButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOProgressSettingLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentProgressSetting > 0 ) + { + PlayButtonSound( giGIOProgressSettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentProgressSetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOProgressSettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentProgressSetting > 0 ) + { + PlayButtonSound( giGIOProgressSettingButton[0], BUTTON_SOUND_CLICKED_ON ); + + iCurrentProgressSetting--; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOProgressSettingButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOProgressSettingRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT ) + { + if ( iCurrentProgressSetting < GIO_PROGRESS_VERY_FAST ) + { + PlayButtonSound( giGIOProgressSettingButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentProgressSetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOProgressSettingButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + if ( iCurrentProgressSetting < GIO_PROGRESS_VERY_FAST ) + { + PlayButtonSound( giGIOProgressSettingButton[1], BUTTON_SOUND_CLICKED_ON ); + + iCurrentProgressSetting++; + gfReRenderGIOScreen =TRUE; + } + else + { + PlayButtonSound( giGIOProgressSettingButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnGIOOldTraitsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_TRAITS_SETTING_X), (GIO_TRAITS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiTraitsOptionToggles[ GIO_TRAITS_NEW ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiTraitsOptionToggles[ GIO_TRAITS_OLD ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIONewTraitsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + if (!gGameExternalOptions.fReadProfileDataFromXML) + { + PlayButtonSound( guiTraitsOptionToggles[ GIO_TRAITS_NEW ], BUTTON_SOUND_DISABLED_CLICK ); + + DoGioMessageBox( MSG_BOX_BASIC_STYLE, zGioNewTraitsImpossibleText[0], GAME_INIT_OPTIONS_SCREEN, MSG_BOX_FLAG_OK, NewTraitsNotPossibleMessageBoxCallBack ); + } + else + { + RestoreExternBackgroundRect( (GIO_TRAITS_SETTING_X), (GIO_TRAITS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiTraitsOptionToggles[ GIO_TRAITS_OLD ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiTraitsOptionToggles[ GIO_TRAITS_NEW ], BUTTON_SOUND_CLICKED_ON ); + } + } +} + +void NewTraitsNotPossibleMessageBoxCallBack( UINT8 bExitValue ) +{ + /*if( bExitValue == MSG_BOX_RETURN_YES ) + { + gubGameOptionScreenHandler = GIO_NOTHING; + }*/ +} + +void BtnGIORealisticStyleCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_GAME_SETTING_X), (GIO_GAME_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiGameStyleToggles[ GIO_SCI_FI ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiGameStyleToggles[ GIO_REALISTIC ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIOScifiStyleCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_GAME_SETTING_X), (GIO_GAME_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiGameStyleToggles[ GIO_REALISTIC ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiGameStyleToggles[ GIO_SCI_FI ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnGIOIronManOffCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_IRON_MAN_SETTING_X), (GIO_IRON_MAN_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiGameSaveToggles[ GIO_IRON_MAN ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiGameStyleToggles[ GIO_CAN_SAVE ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIOIronManOnCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_IRON_MAN_SETTING_X), (GIO_IRON_MAN_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiGameSaveToggles[ GIO_CAN_SAVE ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiGameStyleToggles[ GIO_IRON_MAN ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnGIOTerroristsRandomCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_TERRORISTS_SETTING_X), (GIO_TERRORISTS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiTerroristsOptionToggles[ GIO_TERRORISTS_ALL ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiTerroristsOptionToggles[ GIO_TERRORISTS_RANDOM ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIOTerroristsAllCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_TERRORISTS_SETTING_X), (GIO_TERRORISTS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiTerroristsOptionToggles[ GIO_TERRORISTS_RANDOM ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiTerroristsOptionToggles[ GIO_TERRORISTS_ALL ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnGIODropAllOffCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_DROPALL_SETTING_X), (GIO_DROPALL_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiDropAllOptionToggles[ GIO_DROPALL_ON ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiDropAllOptionToggles[ GIO_DROPALL_OFF ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIODropAllOnCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_DROPALL_SETTING_X), (GIO_DROPALL_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiDropAllOptionToggles[ GIO_DROPALL_OFF ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiDropAllOptionToggles[ GIO_DROPALL_ON ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnGIOGunSettingReducedCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_GUN_SETTING_X), (GIO_GUN_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiGunOptionToggles[ GIO_GUN_NUT ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiGunOptionToggles[ GIO_REDUCED_GUNS ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIOGunSettingToGCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_GUN_SETTING_X), (GIO_GUN_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiGunOptionToggles[ GIO_REDUCED_GUNS ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiGunOptionToggles[ GIO_GUN_NUT ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnGIOWeaponCachesRandomCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_CACHES_SETTING_X), (GIO_CACHES_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiWeaponCachesOptionToggles[ GIO_CACHES_ALL ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiWeaponCachesOptionToggles[ GIO_CACHES_RANDOM ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnGIOWeaponCachesAllCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (GIO_CACHES_SETTING_X), (GIO_CACHES_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiWeaponCachesOptionToggles[ GIO_CACHES_RANDOM ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiWeaponCachesOptionToggles[ GIO_CACHES_ALL ], BUTTON_SOUND_CLICKED_ON ); + } +} BOOLEAN ExitGIOScreen() { @@ -606,55 +1691,96 @@ BOOLEAN ExitGIOScreen() //Delete the main options screen background DeleteVideoObjectFromIndex( guiGIOMainBackGroundImage ); - if(is_networked) - { - RemoveButton( MPguiGIOCancelButton ); - UnloadButtonImage( MPgiGIOCancelBtnImage ); - } + DeleteVideoObjectFromIndex( guiGIOSMALLFRAME ); + // Destroy Basic buttons RemoveButton( guiGIOCancelButton ); RemoveButton( guiGIODoneButton ); - - UnloadButtonImage( giGIOCancelBtnImage ); UnloadButtonImage( giGIODoneBtnImage ); + // Destroy Difficulty setting buttons + RemoveButton( giGIODifficultyButton[0] ); + RemoveButton( giGIODifficultyButton[1] ); + UnloadButtonImage( giGIODifficultyButtonImage[0] ); + UnloadButtonImage( giGIODifficultyButtonImage[1] ); - //Check box to toggle Difficulty settings - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -//Madd -void BtnBROptionTogglesCallback( GUI_BUTTON *btn, INT32 reason ) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -// CHRISL: -void BtnINVOptionTogglesCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnGameStyleTogglesCallback( GUI_BUTTON *btn, INT32 reason ) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnGameSaveTogglesCallback( GUI_BUTTON *btn, INT32 reason ) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { -// UINT8 ubButton = (UINT8)MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnGunOptionsTogglesCallback( GUI_BUTTON *btn, INT32 reason ) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -// JA2Gold: no more timed turns setting - -void BtnTimedTurnsTogglesCallback( GUI_BUTTON *btn, INT32 reason )//hayden : re-enabled -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - UINT8 ubButton = (UINT8)MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - - - - - void BtnGIODoneCallback(GUI_BUTTON *btn,INT32 reason) { if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) @@ -1195,26 +1970,17 @@ void BtnGIODoneCallback(GUI_BUTTON *btn,INT32 reason) { btn->uiFlags &= (~BUTTON_CLICKED_ON ); - if(!is_networked) - { //if the user doesnt have IRON MAN mode selected if( !DisplayMessageToUserAboutIronManMode() ) { //Confirm the difficulty setting DisplayMessageToUserAboutGameDifficulty(); } - } - else - { - gubGameOptionScreenHandler = GIO_EXIT; - } - InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); } } - void BtnGIOCancelCallback(GUI_BUTTON *btn,INT32 reason) { if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) @@ -1232,10 +1998,6 @@ void BtnGIOCancelCallback(GUI_BUTTON *btn,INT32 reason) } } - - - - void MPBtnGIOCancelCallback(GUI_BUTTON *btn,INT32 reason) { if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) @@ -1247,72 +2009,19 @@ void MPBtnGIOCancelCallback(GUI_BUTTON *btn,INT32 reason) { btn->uiFlags &= (~BUTTON_CLICKED_ON ); - //gubGameOptionScreenHandler = GIO_CANCEL; - - //// Select the game which is to be restored - //guiPreviousOptionScreen = guiCurrentScreen; - //guiMainMenuExitScreen = SAVE_LOAD_SCREEN; - //gbHandledMainMenu = 0; - //gfSaveGame = FALSE; - //gfMainMenuScreenExit = TRUE; - - /* guiPreviousOptionScreen = guiCurrentScreen; - SetPendingNewScreen( SAVE_LOAD_SCREEN ); - gubGameOptionScreenHandler = GIO_EXIT; - - gubGIOExitScreen = MAINMENU_SCREEN; - gfGIOScreenExit = TRUE; - fInterfacePanelDirty = DIRTYLEVEL2;*/ - - gubGameOptionScreenHandler = MP_LOAD; - - + gubGameOptionScreenHandler = MP_LOAD; InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); } } - -UINT8 GetCurrentDifficultyButtonSetting() +UINT8 GetCurrentTraitsOptionButtonSetting() { UINT8 cnt; - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - return( cnt ); - } - } - - return( 0 ); -} - - - -//Madd -UINT8 GetCurrentBROptionButtonSetting() -{ - UINT8 cnt; - - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - return( cnt ); - } - } - return( 0 ); -} - -// CHRISL: -UINT8 GetCurrentINVOptionButtonSetting() -{ - UINT8 cnt; - - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + if( ButtonList[ guiTraitsOptionToggles[ cnt ] ]->uiFlags & BUTTON_CLICKED_ON ) { return( cnt ); } @@ -1334,7 +2043,47 @@ UINT8 GetCurrentGameStyleButtonSetting() return( 0 ); } +UINT8 GetCurrentGameSaveButtonSetting() +{ + UINT8 cnt; + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +UINT8 GetCurrentTerroristsButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +UINT8 GetCurrentDropAllButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} UINT8 GetCurrentGunButtonSetting() { @@ -1350,7 +2099,19 @@ UINT8 GetCurrentGunButtonSetting() return( 0 ); } -// JA2 Gold: no timed turns +UINT8 GetCurrentWeaponCachesButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} UINT8 GetCurrentTimedTurnsButtonSetting() { @@ -1365,116 +2126,20 @@ UINT8 GetCurrentTimedTurnsButtonSetting() } return( 0 ); } -//hayden : re-enabled - -UINT8 GetCurrentGameSaveButtonSetting() -{ - UINT8 cnt; - - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - return( cnt ); - } - } - return( 0 ); -} - - - -void RestoreGIOButtonBackGrounds() -{ - UINT8 cnt; - UINT16 usPosY; - - - usPosY = GIO_DIF_SETTINGS_Y-GIO_OFFSET_TO_TOGGLE_BOX_Y; - //Check box to toggle Difficulty settings - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; } } + +void RenderGIOSmallSelectionFrame(INT16 sX, INT16 sY) +{ + + HVOBJECT hHandle; + + // get the video object + GetVideoObject(&hHandle, guiGIOSMALLFRAME); + + // blt to sX, sY relative to upper left corner + BltVideoObject(FRAME_BUFFER, hHandle, 0, sX, sY , VO_BLT_SRCTRANSPARENCY,NULL); + + return; +} \ No newline at end of file diff --git a/GameInitOptionsScreen.h b/GameInitOptionsScreen.h index 32a6c212..6300cc8a 100644 --- a/GameInitOptionsScreen.h +++ b/GameInitOptionsScreen.h @@ -6,7 +6,7 @@ UINT32 GameInitOptionsScreenInit( void ); UINT32 GameInitOptionsScreenHandle( void ); UINT32 GameInitOptionsScreenShutdown( void ); - +BOOLEAN SpIniExists(); #endif diff --git a/GameSettings.cpp b/GameSettings.cpp index ae301778..6a3561ea 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -39,10 +39,11 @@ #include "Text.h" #include "connect.h" +#include "sgp_logger.h" -#include "VFS/vfs.h" -#include "VFS/vfs_file_raii.h" -#include "VFS/File/vfs_file.h" +#include +#include +#include #define GAME_SETTINGS_FILE "Ja2_Settings.INI" @@ -52,12 +53,19 @@ #define AP_BP_CONSTANTS_FILE "APBPConstants.ini" +#define STOMP_SETTINGS_FILE "Skills_Settings.ini" // SANDRO - file for STOMP + +// HEADROCK HAM 4: This file contains all the settings required to tweak the new Shooting Mechanism. There's lots of them. +#define CTH_COEFFICIENTS_FILE "CTHConstants.ini" + #define CD_ROOT_DIR "DATA\\" GAME_SETTINGS gGameSettings; GAME_OPTIONS gGameOptions; // Snap: Options read from an INI file in the default of custom Data directory GAME_EXTERNAL_OPTIONS gGameExternalOptions; +SKILL_TRAIT_VALUES gSkillTraitValues; // SANDRO - added this one +CTH_CONSTANTS gGameCTHConstants; // HEADROCK HAM 4: CTH constants extern SGPFILENAME gCheckFilenames[]; extern CHAR8 gzErrorMsg[256]; @@ -80,6 +88,16 @@ bool UsingNewInventorySystem() return (gGameOptions.ubInventorySystem == INVENTORY_NEW); } +bool UsingNewAttachmentSystem() +{ + return (gGameOptions.ubAttachmentSystem == ATTACHMENT_NEW); +} + +bool UsingNewCTHSystem() +{ + return (gGameExternalOptions.fUseNCTH == TRUE); +} + std::string StringToLower(std::string strToConvert) {//change each element of the string to lower case for(unsigned int i=0;igetProfileStack()->getProfile(L"v1.13") != NULL) { - return TRUE; + isValid = TRUE; } - return FALSE; -#endif + else + isValid = FALSE; + + // Also check the resolution if needed. + if(checkRes == true && iResolution == 0) + isValid = FALSE; + + return isValid; } BOOLEAN LoadGameSettings() -{ +{ try { CIniReader iniReader(GAME_SETTINGS_FILE, TRUE); // force path even for non existing files - gGameSettings.bLastSavedGameSlot = iniReader.ReadInteger("JA2 Game Settings","bLastSavedGameSlot" , -1 , -1 , NUM_SAVE_GAMES ); + gGameSettings.bLastSavedGameSlot = iniReader.ReadInteger("JA2 Game Settings","bLastSavedGameSlot" , -1 , -1 , NUM_SLOT ); gGameSettings.ubMusicVolumeSetting = iniReader.ReadInteger("JA2 Game Settings","ubMusicVolumeSetting" , MIDVOLUME , 0 , HIGHVOLUME ); gGameSettings.ubSoundEffectsVolume = iniReader.ReadInteger("JA2 Game Settings","ubSoundEffectsVolume" , MIDVOLUME , 0 , HIGHVOLUME ); gGameSettings.ubSpeechVolume = iniReader.ReadInteger("JA2 Game Settings","ubSpeechVolume" , MIDVOLUME , 0 , HIGHVOLUME ); @@ -146,22 +162,25 @@ BOOLEAN LoadGameSettings() gGameSettings.fOptions[TOPTION_3D_CURSOR] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_3D_CURSOR" , FALSE ); gGameSettings.fOptions[TOPTION_CTH_CURSOR] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_CTH_CURSOR" , TRUE ); gGameSettings.fOptions[TOPTION_GL_BURST_CURSOR] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_GL_BURST_CURSOR" , TRUE ); - gGameSettings.fOptions[TOPTION_DROP_ALL] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_DROP_ALL" , FALSE ); - gGameSettings.fOptions[TOPTION_GL_HIGH_ANGLE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_GL_HIGH_ANGLE" , FALSE ); - gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_AIM_LEVEL_RESTRICTION" , TRUE ); + gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALLOW_TAUNTS" , TRUE ); // changed from drop all - SANDRO + gGameSettings.fOptions[TOPTION_GL_HIGH_ANGLE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_GL_HIGH_ANGLE" , FALSE ); + gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALLOW_REAL_TIME_SNEAK" , FALSE ); // Changed from aim levels restriction - SANDRO gGameSettings.fOptions[TOPTION_SPACE_SELECTS_NEXT_SQUAD] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_SPACE_SELECTS_NEXT_SQUAD" , TRUE ); gGameSettings.fOptions[TOPTION_SHOW_ITEM_SHADOW] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_SHOW_ITEM_SHADOW" , TRUE ); gGameSettings.fOptions[TOPTION_SHOW_WEAPON_RANGE_IN_TILES] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_SHOW_WEAPON_RANGE_IN_TILES" , TRUE ); gGameSettings.fOptions[TOPTION_TRACERS_FOR_SINGLE_FIRE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_TRACERS_FOR_SINGLE_FIRE" , FALSE ); gGameSettings.fOptions[TOPTION_RAIN_SOUND] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_RAIN_SOUND" , TRUE ); gGameSettings.fOptions[TOPTION_ALLOW_CROWS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALLOW_CROWS" , TRUE ); - gGameSettings.fOptions[TOPTION_ALLOW_SOLDIER_TOOLTIPS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALLOW_SOLDIER_TOOLTIPS" , TRUE ); // Changed from random IMP personality - SANDRO + gGameSettings.fOptions[TOPTION_ALLOW_SOLDIER_TOOLTIPS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALLOW_SOLDIER_TOOLTIPS" , TRUE ); gGameSettings.fOptions[TOPTION_USE_AUTO_SAVE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_USE_AUTO_SAVE" , FALSE ); gGameSettings.fOptions[TOPTION_SILENT_SKYRIDER] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_SILENT_SKYRIDER" , FALSE ); gGameSettings.fOptions[TOPTION_LOW_CPU_USAGE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_LOW_CPU_USAGE" , FALSE ); gGameSettings.fOptions[TOPTION_ENHANCED_DESC_BOX] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ENHANCED_DESC_BOX" , FALSE ); gGameSettings.fOptions[TOPTION_TOGGLE_TURN_MODE] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_TOGGLE_TURN_MODE" , FALSE ); gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_STAT_PROGRESS_BARS" , FALSE ); // HEADROCK HAM 3.6: Progress Bars + gGameSettings.fOptions[TOPTION_REPORT_MISS_MARGIN] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_REPORT_MISS_MARGIN" , FALSE ); // HEADROCK HAM 4: Shot offset report + gGameSettings.fOptions[TOPTION_ALT_MAP_COLOR] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALT_MAP_COLOR" , FALSE ); // HEADROCK HAM 4: Strategic Map Colors + gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_ALTERNATE_BULLET_GRAPHICS" , FALSE ); gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_CHEAT_MODE_OPTIONS_HEADER" , FALSE ); gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_FORCE_BOBBY_RAY_SHIPMENTS" , FALSE ); gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_END] = iniReader.ReadBoolean("JA2 Game Settings","TOPTION_CHEAT_MODE_OPTIONS_END" , FALSE ); @@ -187,7 +206,7 @@ BOOLEAN LoadGameSettings() // //Do checking to make sure the settings are valid // - if( gGameSettings.bLastSavedGameSlot < 0 || gGameSettings.bLastSavedGameSlot >= NUM_SAVE_GAMES ) + if( gGameSettings.bLastSavedGameSlot < 0 || gGameSettings.bLastSavedGameSlot >= NUM_SLOT ) gGameSettings.bLastSavedGameSlot = -1; if( gGameSettings.ubMusicVolumeSetting > HIGHVOLUME ) @@ -229,7 +248,7 @@ BOOLEAN LoadGameSettings() return( TRUE ); } - catch(CBasicException &ex) + catch(vfs::Exception) { // file does not exist, InitGamesettings() and then return. // InitGamesettings() will also call SaveGameSettings(). @@ -246,19 +265,6 @@ BOOLEAN SaveGameSettings() gGameSettings.ubSpeechVolume = (UINT8)GetSpeechVolume( ); gGameSettings.ubMusicVolumeSetting = (UINT8)MusicGetVolume( ); -#ifndef USE_VFS - char gameSettingsFilePath[MAX_PATH]; - FILE *file_pointer; - - sprintf(gameSettingsFilePath, "%s\\%s", gCustomDataCat.GetRootDir().c_str(), GAME_SETTINGS_FILE); - fopen_s( &file_pointer, gameSettingsFilePath, "w" ); - if( !file_pointer ) - { - //?fclose( file_pointer ); - return FALSE; - } -#endif - std::stringstream settings; const char endl[] = "\r\n"; settings << ";******************************************************************************************************************************" << endl; @@ -325,22 +331,25 @@ BOOLEAN SaveGameSettings() settings << "TOPTION_3D_CURSOR = " << (gGameSettings.fOptions[TOPTION_3D_CURSOR] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_CTH_CURSOR = " << (gGameSettings.fOptions[TOPTION_CTH_CURSOR] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_GL_BURST_CURSOR = " << (gGameSettings.fOptions[TOPTION_GL_BURST_CURSOR] ? "TRUE" : "FALSE" ) << endl; - settings << "TOPTION_DROP_ALL = " << (gGameSettings.fOptions[TOPTION_DROP_ALL] ? "TRUE" : "FALSE" ) << endl; + settings << "TOPTION_ALLOW_TAUNTS = " << (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] ? "TRUE" : "FALSE" ) << endl; // changed from drop all - SANDRO settings << "TOPTION_GL_HIGH_ANGLE = " << (gGameSettings.fOptions[TOPTION_GL_HIGH_ANGLE] ? "TRUE" : "FALSE" ) << endl; - settings << "TOPTION_AIM_LEVEL_RESTRICTION = " << (gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] ? "TRUE" : "FALSE" ) << endl; + settings << "TOPTION_ALLOW_REAL_TIME_SNEAK = " << (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] ? "TRUE" : "FALSE" ) << endl; // changed from restrict aim levels - SANDRO settings << "TOPTION_SPACE_SELECTS_NEXT_SQUAD = " << (gGameSettings.fOptions[TOPTION_SPACE_SELECTS_NEXT_SQUAD] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_SHOW_ITEM_SHADOW = " << (gGameSettings.fOptions[TOPTION_SHOW_ITEM_SHADOW] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_SHOW_WEAPON_RANGE_IN_TILES = " << (gGameSettings.fOptions[TOPTION_SHOW_WEAPON_RANGE_IN_TILES] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_TRACERS_FOR_SINGLE_FIRE = " << (gGameSettings.fOptions[TOPTION_TRACERS_FOR_SINGLE_FIRE] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_RAIN_SOUND = " << (gGameSettings.fOptions[TOPTION_RAIN_SOUND] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_ALLOW_CROWS = " << (gGameSettings.fOptions[TOPTION_ALLOW_CROWS] ? "TRUE" : "FALSE" ) << endl; - settings << "TOPTION_ALLOW_SOLDIER_TOOLTIPS = " << (gGameSettings.fOptions[TOPTION_ALLOW_SOLDIER_TOOLTIPS] ? "TRUE" : "FALSE" ) << endl; // changed from random IMP personality - SANDRO + settings << "TOPTION_ALLOW_SOLDIER_TOOLTIPS = " << (gGameSettings.fOptions[TOPTION_ALLOW_SOLDIER_TOOLTIPS] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_USE_AUTO_SAVE = " << (gGameSettings.fOptions[TOPTION_USE_AUTO_SAVE] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_SILENT_SKYRIDER = " << (gGameSettings.fOptions[TOPTION_SILENT_SKYRIDER] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_LOW_CPU_USAGE = " << (gGameSettings.fOptions[TOPTION_LOW_CPU_USAGE] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_ENHANCED_DESC_BOX = " << (gGameSettings.fOptions[TOPTION_ENHANCED_DESC_BOX] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_TOGGLE_TURN_MODE = " << (gGameSettings.fOptions[TOPTION_TOGGLE_TURN_MODE] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_STAT_PROGRESS_BARS = " << (gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] ? "TRUE" : "FALSE" ) << endl; // HEADROCK HAM 3.6: Progress Bars + settings << "TOPTION_REPORT_MISS_MARGIN = " << (gGameSettings.fOptions[TOPTION_REPORT_MISS_MARGIN] ? "TRUE" : "FALSE" ) << endl; // HEADROCK HAM 4: Shot offset report + settings << "TOPTION_ALT_MAP_COLOR = " << (gGameSettings.fOptions[TOPTION_ALT_MAP_COLOR] ? "TRUE" : "FALSE" ) << endl; // HEADROCK HAM 4: Alt Map Colors + settings << "TOPTION_ALTERNATE_BULLET_GRAPHICS = " << (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_CHEAT_MODE_OPTIONS_HEADER = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_HEADER] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_FORCE_BOBBY_RAY_SHIPMENTS = " << (gGameSettings.fOptions[TOPTION_FORCE_BOBBY_RAY_SHIPMENTS] ? "TRUE" : "FALSE" ) << endl; settings << "TOPTION_CHEAT_MODE_OPTIONS_END = " << (gGameSettings.fOptions[TOPTION_CHEAT_MODE_OPTIONS_END] ? "TRUE" : "FALSE" ) << endl; @@ -362,26 +371,21 @@ BOOLEAN SaveGameSettings() settings << "TOPTION_TRACKING_MODE = " << (gGameSettings.fOptions[TOPTION_TRACKING_MODE] ? "TRUE" : "FALSE" ) << endl; settings << "NUM_ALL_GAME_OPTIONS = " << (gGameSettings.fOptions[NUM_ALL_GAME_OPTIONS] ? "TRUE" : "FALSE" ) << endl; -#ifndef USE_VFS - fprintf_s (file_pointer , settings.str().c_str()); - fclose( file_pointer ); -#else try { vfs::COpenWriteFile wfile(GAME_SETTINGS_FILE,true,true); - wfile.file().write(settings.str().c_str(), settings.str().length()); + wfile->write(settings.str().c_str(), settings.str().length()); } - catch(CBasicException& ex) + catch(vfs::Exception& ex) { - logException(ex); + SGP_WARNING(ex.what()); vfs::CFile file(GAME_SETTINGS_FILE); if(file.openWrite(true,true)) { vfs::COpenWriteFile wfile( vfs::tWritableFile::cast(&file)); - TRYCATCH_RETHROW(file.write(settings.str().c_str(), settings.str().length()),L""); + SGP_TRYCATCH_RETHROW(file.write(settings.str().c_str(), settings.str().length()),L""); } } -#endif return( TRUE ); @@ -428,9 +432,9 @@ void InitGameSettings() //Madd: gGameSettings.fOptions[ TOPTION_GL_BURST_CURSOR ] = TRUE; - gGameSettings.fOptions[ TOPTION_DROP_ALL ] = FALSE; + gGameSettings.fOptions[ TOPTION_ALLOW_TAUNTS ] = TRUE; // changed - SANDRO gGameSettings.fOptions[ TOPTION_GL_HIGH_ANGLE ] = FALSE; - gGameSettings.fOptions[ TOPTION_AIM_LEVEL_RESTRICTION ] = TRUE; + gGameSettings.fOptions[ TOPTION_ALLOW_REAL_TIME_SNEAK ] = FALSE; // changed - SANDRO //lalien gGameSettings.fOptions[ TOPTION_SPACE_SELECTS_NEXT_SQUAD ] = TRUE; @@ -439,7 +443,7 @@ void InitGameSettings() gGameSettings.fOptions[ TOPTION_TRACERS_FOR_SINGLE_FIRE ] = FALSE; gGameSettings.fOptions[ TOPTION_RAIN_SOUND ] = TRUE; gGameSettings.fOptions[ TOPTION_ALLOW_CROWS ] = TRUE; - gGameSettings.fOptions[ TOPTION_ALLOW_SOLDIER_TOOLTIPS ] = TRUE; // changed - SANDRO + gGameSettings.fOptions[ TOPTION_ALLOW_SOLDIER_TOOLTIPS ] = TRUE; gGameSettings.fOptions[ TOPTION_USE_AUTO_SAVE ] = FALSE; gGameSettings.fOptions[ TOPTION_SILENT_SKYRIDER ] = FALSE; gGameSettings.fOptions[ TOPTION_LOW_CPU_USAGE ] = FALSE; @@ -451,6 +455,13 @@ void InitGameSettings() // HEADROCK HAM 3.6: gGameSettings.fOptions[ TOPTION_STAT_PROGRESS_BARS ] = FALSE; + // HEADROCK HAM 4: + gGameSettings.fOptions[ TOPTION_ALT_MAP_COLOR ] = FALSE; + + gGameSettings.fOptions[ TOPTION_ALTERNATE_BULLET_GRAPHICS ] = FALSE; + + gGameSettings.fOptions[ TOPTION_REPORT_MISS_MARGIN ] = FALSE; + // arynn: Cheat/Debug Menu gGameSettings.fOptions[ TOPTION_CHEAT_MODE_OPTIONS_HEADER ] = FALSE; gGameSettings.fOptions[ TOPTION_FORCE_BOBBY_RAY_SHIPMENTS ] = FALSE; // force all pending Bobby Ray shipments @@ -492,7 +503,7 @@ void InitGameOptions() memset( &gGameOptions, 0, sizeof( GAME_OPTIONS ) ); //Init the game options - + if (is_networked) gGameOptions.ubBobbyRay = BR_AWESOME;// hayden, was BR_GOOD; else @@ -508,10 +519,16 @@ void InitGameOptions() gGameOptions.ubDifficultyLevel = DIF_LEVEL_MEDIUM; //CHRISL: override default inventory mode when in low res - if(IsNIVModeValid() == FALSE) + if(IsNIVModeValid(true) == FALSE) + { gGameOptions.ubInventorySystem = INVENTORY_OLD; + gGameOptions.ubAttachmentSystem = ATTACHMENT_OLD; + } else + { gGameOptions.ubInventorySystem = INVENTORY_NEW; + gGameOptions.ubAttachmentSystem = ATTACHMENT_OLD; + } if (is_networked) gGameOptions.fTurnTimeLimit = TRUE;//hayden @@ -519,6 +536,19 @@ void InitGameOptions() gGameOptions.fTurnTimeLimit = FALSE; gGameOptions.fIronManMode = FALSE; + + // following added by SANDRO + gGameOptions.ubMaxIMPCharacters = (gGameExternalOptions.iIMPMaleCharacterCount + gGameExternalOptions.iIMPFemaleCharacterCount); + + if (gGameExternalOptions.fReadProfileDataFromXML) + gGameOptions.fNewTraitSystem = TRUE; + else + gGameOptions.fNewTraitSystem = FALSE; + + gGameOptions.ubProgressSpeedOfItemsChoices = ITEM_PROGRESS_NORMAL; + gGameOptions.fEnableAllTerrorists = FALSE; + gGameOptions.fEnemiesDropAllItems = FALSE; + gGameOptions.fEnableAllWeaponCaches = FALSE; } @@ -545,16 +575,6 @@ void LoadGameExternalOptions() //Kaiden: Setting Ja2_Options.ini file to be read CIniReader iniReader(GAME_EXTERNAL_OPTIONS_FILE); - - // WANNE: FILE TRANSFER: We disable reading from ja2_options.ini until we get file transfer working - if(is_networked) - { -#ifndef USE_VFS - //memset(&iniReader, 0, sizeof (CIniReader) );//disable ini in mp (taking default values) - iniReader.Clear(); -#endif - } - //################# System Limit Settings ################# // WDS - make number of mercenaries, etc. be configurable. Note: Changing one of these can render savegames unloadable. @@ -574,7 +594,7 @@ void LoadGameExternalOptions() gGameExternalOptions.fUseDifficultyBasedProfDat = iniReader.ReadBoolean("Data File Settings", "USE_DIFFICULTY_BASED_PROF_DAT", TRUE); // HEADROCK PROFEX/3.6: Activate this to read Profile data from MercProfiles.XML and MercOpinions.XML - gGameExternalOptions.fReadProfileDataFromXML = iniReader.ReadBoolean("Data File Settings","READ_PROFILE_DATA_FROM_XML", FALSE); + gGameExternalOptions.fReadProfileDataFromXML = iniReader.ReadBoolean("Data File Settings","READ_PROFILE_DATA_FROM_XML", TRUE); // HEADROCK PROFEX/3.6: Activate this to write Profile data to MercProfiles Out.XML and MercOpinions Out.XML. This can be used to convert PROF.DAT to XML format. gGameExternalOptions.fWriteProfileDataToXML = iniReader.ReadBoolean("Data File Settings","WRITE_PROFILE_DATA_TO_XML", FALSE); @@ -585,7 +605,8 @@ void LoadGameExternalOptions() //################# Merc Recruitment Settings ################# // WDS: Allow flexible numbers of IMPs of each sex - gGameExternalOptions.iMaxIMPCharacters = iniReader.ReadInteger("Recruitment Settings","MAX_IMP_CHARACTERS",1, 1, NUM_PROFILES); + // SANDRO - moved to the game itself + //gGameExternalOptions.iMaxIMPCharacters = iniReader.ReadInteger("Recruitment Settings","MAX_IMP_CHARACTERS",1, 1, NUM_PROFILES); gGameExternalOptions.iIMPMaleCharacterCount = iniReader.ReadInteger("Recruitment Settings","IMP_MALE_CHARACTER_COUNT", COUNT_STANDARD_MALE_SLOTS, 1, NUM_PROFILES); gGameExternalOptions.iIMPFemaleCharacterCount = iniReader.ReadInteger("Recruitment Settings","IMP_FEMALE_CHARACTER_COUNT", COUNT_STANDARD_FEMALE_SLOTS, 1, NUM_PROFILES); @@ -646,19 +667,62 @@ void LoadGameExternalOptions() } gGameExternalOptions.iaIMPSlots[gGameExternalOptions.iIMPFemaleCharacterCount+gGameExternalOptions.iIMPMaleCharacterCount+1] = -1; + // silversurfer: read early recruitment options 1=immediately (control Omerta), 2=early (control 1, 2, 3 towns including Omerta) + // 3=normal (control 3, 4, 5 towns including Omerta), 4=after liberating Omerta and solving the "Deliver Food Quest" for Miguel + gGameExternalOptions.ubEarlyRebelsRecruitment[0] = iniReader.ReadInteger("Recruitment Settings","EARLY_REBELS_RECRUITMENT", 3, 1, 4); + switch (gGameExternalOptions.ubEarlyRebelsRecruitment[0]) + { + case 2: + { + gGameExternalOptions.ubEarlyRebelsRecruitment[1] = 1; // FACT_PLAYER_OWNS_2_TOWNS_INCLUDING_OMERTA + gGameExternalOptions.ubEarlyRebelsRecruitment[2] = 2; // FACT_PLAYER_OWNS_3_TOWNS_INCLUDING_OMERTA + gGameExternalOptions.ubEarlyRebelsRecruitment[3] = 3; // FACT_PLAYER_OWNS_4_TOWNS_INCLUDING_OMERTA + break; + } + case 3: + { + gGameExternalOptions.ubEarlyRebelsRecruitment[1] = 3; // FACT_PLAYER_OWNS_2_TOWNS_INCLUDING_OMERTA + gGameExternalOptions.ubEarlyRebelsRecruitment[2] = 4; // FACT_PLAYER_OWNS_3_TOWNS_INCLUDING_OMERTA + gGameExternalOptions.ubEarlyRebelsRecruitment[3] = 5; // FACT_PLAYER_OWNS_4_TOWNS_INCLUDING_OMERTA + break; + } + case 4: + { + gGameExternalOptions.ubEarlyRebelsRecruitment[1] = 3; // FACT_PLAYER_OWNS_2_TOWNS_INCLUDING_OMERTA + gGameExternalOptions.ubEarlyRebelsRecruitment[2] = 4; // FACT_PLAYER_OWNS_3_TOWNS_INCLUDING_OMERTA + gGameExternalOptions.ubEarlyRebelsRecruitment[3] = 5; // FACT_PLAYER_OWNS_4_TOWNS_INCLUDING_OMERTA + break; + } + default: + break; + } + //I.M.P Character generation - gGameExternalOptions.iStartAttribute = iniReader.ReadInteger("Recruitment Settings","IMP_INITIAL_ATTRIBUTES",55, 1, 100); - gGameExternalOptions.iImpAttributePoints = iniReader.ReadInteger("Recruitment Settings","IMP_INITIAL_POINTS",40, 1, 100); + // SANDRO - some changes here + gGameExternalOptions.iIMPProfileCost = iniReader.ReadInteger("Recruitment Settings","IMP_PROFILE_COST",3000, 0, 50000); + gGameExternalOptions.fDynamicIMPProfileCost = iniReader.ReadBoolean("Recruitment Settings","DYNAMIC_IMP_PROFILE_COST",FALSE); + gGameExternalOptions.iImpAttributePoints = iniReader.ReadInteger("Recruitment Settings","IMP_INITIAL_POINTS",500, 1, 5000); gGameExternalOptions.iMinAttribute = iniReader.ReadInteger("Recruitment Settings","IMP_MIN_ATTRIBUTE",35, 1, 99); gGameExternalOptions.iMaxZeroBonus = iniReader.ReadInteger("Recruitment Settings","IMP_BONUS_POINTS_FOR_ZERO_ATTRIBUTE",15, 0, 100); + // if attribute points set too low... + if ( gGameExternalOptions.iImpAttributePoints < ((gGameExternalOptions.iMinAttribute * 5) + (gGameExternalOptions.iMaxZeroBonus * 5)) ) + { + gGameExternalOptions.iImpAttributePoints = ((gGameExternalOptions.iMinAttribute * 5) + (gGameExternalOptions.iMaxZeroBonus * 5)); + } + gGameExternalOptions.iMaxAttribute = iniReader.ReadInteger("Recruitment Settings","IMP_MAX_ATTRIBUTE",90, gGameExternalOptions.iMinAttribute+1, 100); gGameExternalOptions.iIMPStartingLevelCostMultiplier = iniReader.ReadInteger("Recruitment Settings","IMP_STARTING_LEVEL_COST_MULTIPLIER", 5, 0, 100); gGameExternalOptions.iBonusPointsForDisability = iniReader.ReadInteger("Recruitment Settings","IMP_BONUS_POINTS_FOR_DISABILITY",20, 0, 500); gGameExternalOptions.iBonusPointsPerSkillNotTaken = iniReader.ReadInteger("Recruitment Settings","IMP_BONUS_POINTS_PER_SKILL_NOT_TAKEN",25, 0, 500); - + // DBrot: Expert choices + gGameExternalOptions.fExpertsGetDifferentChoices = iniReader.ReadBoolean("Recruitment Settings","EXPERTS_GET_DIFFERENT_CHOICES",FALSE); //Merc settings - gGameExternalOptions.fMercDayOne = iniReader.ReadBoolean("Recruitment Settings","MERC_WEBSITE_IMMEDIATELY_AVAILABLE",FALSE); - gGameExternalOptions.fAllMercsAvailable = iniReader.ReadBoolean("Recruitment Settings","MERC_WEBSITE_ALL_MERCS_AVAILABLE",FALSE); + gGameExternalOptions.fMercDayOne = iniReader.ReadBoolean("Recruitment Settings","MERC_WEBSITE_IMMEDIATELY_AVAILABLE",FALSE); + gGameExternalOptions.fAllMercsAvailable = iniReader.ReadBoolean("Recruitment Settings","MERC_WEBSITE_ALL_MERCS_AVAILABLE",FALSE); + //tais: mercs can go on assignment; 0 = default behaviour, 1 = all mercs available at start, 2 = no mercs go on other assignments... period! + gGameExternalOptions.fMercsOnAssignment = iniReader.ReadInteger("Recruitment Settings","MERCS_CAN_BE_ON_ASSIGNMENT",0,0,2); + + //Merc Death Settings: gGameExternalOptions.gfMercsDieOnAssignment = iniReader.ReadBoolean("Recruitment Settings","MERCS_CAN_DIE_ON_ASSIGNMENT",TRUE); @@ -701,6 +765,9 @@ void LoadGameExternalOptions() gGameExternalOptions.usHelicopterBaseCostPerGreenTile = iniReader.ReadInteger("Financial Settings","HELICOPTER_BASE_COST_PER_GREEN_TILE", 100, 0, 60000); gGameExternalOptions.usHelicopterBaseCostPerRedTile = iniReader.ReadInteger("Financial Settings","HELICOPTER_BASE_COST_PER_RED_TILE", 1000, 0, 60000); + //tais: percentage that the merc's salary rises when he/she levels up + gGameExternalOptions.gMercLevelUpSalaryIncreasePercentage = (FLOAT)iniReader.ReadInteger("Financial Settings","MERC_LEVEL_UP_SALARY_INCREASE_PERCENTAGE",25, 0, 1000); + //################# Troubleshooting Settings ################# gGameExternalOptions.gubDeadLockDelay = (UINT8) iniReader.ReadInteger("Troubleshooting Settings","DEAD_LOCK_DELAY",15, 5, 50); @@ -721,12 +788,20 @@ void LoadGameExternalOptions() gGameExternalOptions.gfUseExternalLoadscreens = iniReader.ReadBoolean("Graphics Settings","USE_EXTERNALIZED_LOADSCREENS", FALSE); + //tais: enable/disable New Starting Gear Interface (0 = disabled, classic style; 1 = enabled, new 21 item view and up to 5 gearkit selection) + gGameExternalOptions.gfUseNewStartingGearInterface = iniReader.ReadBoolean("Graphics Settings","USE_NEW_STARTING_GEAR_INTERFACE", FALSE); + + // WANNE: Moved to options screen //afp - use a different graphic for bullets? - gGameExternalOptions.gbBulletTracer = iniReader.ReadBoolean("Graphics Settings","ALTERNATE_BULLET_GRAPHICS",FALSE); + //gGameExternalOptions.gbBulletTracer = iniReader.ReadBoolean("Graphics Settings","ALTERNATE_BULLET_GRAPHICS",FALSE); // Are enemy females restricted to Blackshirts only? gGameExternalOptions.fRestrictFemaleEnemiesExceptElite = iniReader.ReadBoolean("Graphics Settings","RESTRICT_FEMALE_ENEMIES_EXCEPT_ELITE",FALSE); + // *** ddd - BEGIN + // New setting to allow thin progressbar + gGameExternalOptions.fSmallSizeProgressbar = iniReader.ReadBoolean("Graphics Settings", "SMALL_SIZE_PB", FALSE); + // *** ddd - END //################# Sound Settings ################# @@ -751,6 +826,11 @@ void LoadGameExternalOptions() // WDS - Automatically flag mines gGameExternalOptions.automaticallyFlagMines = iniReader.ReadBoolean("Tactical Interface Settings","AUTOMATICALLY_FLAG_MINES_WHEN_SPOTTED", FALSE); + // silversurfer: don't play quote when mine spotted? + gGameExternalOptions.fMineSpottedNoTalk = iniReader.ReadBoolean("Tactical Interface Settings","MINES_SPOTTED_NO_TALK", FALSE); + + //DBrot: Stand up after battle? + gGameExternalOptions.fStandUpAfterBattle = iniReader.ReadBoolean("Tactical Interface Settings","STAND_UP_AFTER_BATTLE", TRUE); // Tactical militia command gGameExternalOptions.fAllowTacticalMilitiaCommand = iniReader.ReadBoolean("Tactical Interface Settings","ALLOW_TACTICAL_MILITIA_COMMAND",0); @@ -781,8 +861,13 @@ void LoadGameExternalOptions() break; } - // HEADROCK HAM 3.6: If activated, the game does not switch focus to a merc who spots an enemy in real-time mode. This fixes issues with Real-Time Sneak. - gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak = iniReader.ReadBoolean("Tactical Interface Settings","NO_AUTO_FOCUS_CHANGE_IN_REALTIME_SNEAK", FALSE); + //legion by Jazz + gGameExternalOptions.fShowTacticalFaceGear = iniReader.ReadBoolean("Tactical Interface Settings","SHOW_TACTICAL_FACE_GEAR",FALSE); + gGameExternalOptions.fShowTacticalFaceIcons = iniReader.ReadBoolean("Tactical Interface Settings","SHOW_TACTICAL_FACE_ICONS",FALSE); + gGameExternalOptions.bTacticalFaceIconStyle = iniReader.ReadInteger("Tactical Interface Settings","TACTICAL_FACE_ICON_STYLE", 0, 0, 3); + + // Camo portraits by Jazz + gGameExternalOptions.fShowCamouflageFaces = iniReader.ReadBoolean("Tactical Interface Settings","SHOW_CAMOUFLAGE_FACES", FALSE); //################# Tactical Difficulty Settings ################# @@ -794,6 +879,21 @@ void LoadGameExternalOptions() gGameExternalOptions.iPlayerAPBonus = (INT8) iniReader.ReadInteger("Tactical Difficulty Settings","PLAYER_AP_BONUS",0,__max(-APBPConstants[AP_MINIMUM],-128),127); + // Percentage bonus to total enemy CtH on every hit - applies during tactical combat only + gGameExternalOptions.sEnemyAdminCtHBonusPercent = iniReader.ReadInteger("Tactical Difficulty Settings", "ADMIN_CTH_BONUS_PERCENT", 0, -100, 500); + gGameExternalOptions.sEnemyRegularCtHBonusPercent = iniReader.ReadInteger("Tactical Difficulty Settings", "REGULAR_CTH_BONUS_PERCENT", 0, -100, 500); + gGameExternalOptions.sEnemyEliteCtHBonusPercent = iniReader.ReadInteger("Tactical Difficulty Settings", "ELITE_CTH_BONUS_PERCENT", 10, -100, 500); + + // Damage the enemz suffer is reduced by this percentage - applies during tactical combat only + gGameExternalOptions.sEnemyAdminDamageResistance = iniReader.ReadInteger("Tactical Difficulty Settings", "ADMIN_DAMAGE_RESISTANCE", 0, -50, 95); + gGameExternalOptions.sEnemyRegularDamageResistance = iniReader.ReadInteger("Tactical Difficulty Settings", "REGULAR_DAMAGE_RESISTANCE", 0, -50, 95); + gGameExternalOptions.sEnemyEliteDamageResistance = iniReader.ReadInteger("Tactical Difficulty Settings", "ELITE_DAMAGE_RESISTANCE", 0, -50, 95); + + // SANDRO - Function to assign traits to enemy soldiers or militia + gGameExternalOptions.fAssignTraitsToEnemy = iniReader.ReadBoolean("Tactical Difficulty Settings", "ASSIGN_SKILL_TRAITS_TO_ENEMY", FALSE); + gGameExternalOptions.fAssignTraitsToMilitia = iniReader.ReadBoolean("Tactical Difficulty Settings", "ASSIGN_SKILL_TRAITS_TO_MILITIA", FALSE); + gGameExternalOptions.bAssignedTraitsRarity = iniReader.ReadInteger("Tactical Difficulty Settings", "ASSIGNED_SKILL_TRAITS_RARITY ", 0, -100, 100); + // HEADROCK HAM B2.8: At "1", Militia will drop their equipment similar to enemies, IF killed by non-player character. At "2" they drop whenever killed. gGameExternalOptions.ubMilitiaDropEquipment = iniReader.ReadInteger("Tactical Difficulty Settings","MILITIA_DROP_EQUIPMENT", 0, 0, 2 ); @@ -811,13 +911,17 @@ void LoadGameExternalOptions() gGameExternalOptions.usLevelSubpointsToImprove = iniReader.ReadInteger("Tactical Difficulty Settings","LEVEL_SUBPOINTS_TO_IMPROVE", 350, 1, 6500); // Alternate algorithm for choosing equipment level. Mostly disregards soldier's class and puts less emphasis on distance from Sector P3. - gGameExternalOptions.fSlowProgressForEnemyItemsChoice = iniReader.ReadBoolean("Tactical Difficulty Settings", "SLOW_PROGRESS_FOR_ENEMY_ITEMS_CHOICE", TRUE); + // SANDRO - moved into the game + //gGameExternalOptions.fSlowProgressForEnemyItemsChoice = iniReader.ReadBoolean("Tactical Difficulty Settings", "SLOW_PROGRESS_FOR_ENEMY_ITEMS_CHOICE", TRUE); // The_Bob - real time sneaking code 01/06/09 // Suport disabling real time sneaking via external .ini file - gGameExternalOptions.fAllowRealTimeSneak = iniReader.ReadBoolean("Tactical Difficulty Settings","ALLOW_REAL_TIME_SNEAK", FALSE); + // SANDRO - revisited and moved to preferences + // gGameExternalOptions.fAllowRealTimeSneak = iniReader.ReadBoolean("Tactical Difficulty Settings","ALLOW_REAL_TIME_SNEAK", FALSE); // Silence the RT sneaking messages gGameExternalOptions.fQuietRealTimeSneak = iniReader.ReadBoolean("Tactical Difficulty Settings","QUIET_REAL_TIME_SNEAK", FALSE); + // HEADROCK HAM 3.6: If activated, the game does not switch focus to a merc who spots an enemy in real-time mode. This fixes issues with Real-Time Sneak. + gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak = iniReader.ReadBoolean("Tactical Difficulty Settings","NO_AUTO_FOCUS_CHANGE_IN_REALTIME_SNEAK", FALSE); // HEADROCK HAM 3.2: If activated, reinforcements (militia/enemy) arrive in the battle with 0 APs. This makes them less of a diablo-ex-machina. 0 = Diabled. 2 = Enemies. 3 = Militia. 1 = both gGameExternalOptions.ubReinforcementsFirstTurnFreeze = iniReader.ReadInteger("Tactical Difficulty Settings","REINFORCEMENTS_ARRIVE_WITH_ZERO_AP", 0, 0, 3); @@ -825,15 +929,24 @@ void LoadGameExternalOptions() // HEADROCK HAM 3.6: Militia can now place blue flags when they spot a landmine. gGameExternalOptions.fMilitiaPlaceBlueFlags = iniReader.ReadBoolean("Tactical Difficulty Settings","MILITIA_CAN_PLACE_FLAGS_ON_MINES", FALSE); - // WANNE: Added INI file Option for enemy ambushes, so we also have the option to play vanilla ja2 ambush settings - gGameExternalOptions.fEnableChanceOfEnemyAmbushesOnInsaneDifficult = iniReader.ReadBoolean("Tactical Difficulty Settings", "ENABLE_CHANCE_OF_ENEMY_AMBUSHES_ON_INSANE_DIFFICULT", TRUE); - // HEADROCK HAM 3.6: Non-Combat Bodytypes shouldn't become hostile gGameExternalOptions.fCanTrueCiviliansBecomeHostile = iniReader.ReadBoolean("Tactical Difficulty Settings","CAN_TRUE_CIVILIANS_BECOME_HOSTILE", TRUE); // HEADROCK HAM 3.6: Militia become hostile when attacked. 0 = No. 1 = If killed. 2 = If attacked (JA2 Default) gGameExternalOptions.ubCanMilitiaBecomeHostile = iniReader.ReadInteger("Tactical Difficulty Settings","CAN_MILITIA_BECOME_HOSTILE", 2, 0, 2); + // SANDRO - Mercs stronger during autoresolve setting + gGameExternalOptions.sMercsAutoresolveOffenseBonus = iniReader.ReadInteger("Tactical Difficulty Settings", "MERCS_OFFENSE_IN_AUTORESOLVE_BATTLES_BONUS",15, -100, 500); + gGameExternalOptions.sMercsAutoresolveDeffenseBonus = iniReader.ReadInteger("Tactical Difficulty Settings", "MERCS_DEFFENSE_IN_AUTORESOLVE_BATTLES_BONUS",30, -100, 500); + + // WANNE: Added INI file Option for enemy ambushes, so we also have the option to play vanilla ja2 ambush settings + // SANDRO - changed this so on any difficulty there is a chance to beambushed. Hoever this chance is calculated differently to not lead to instant load game like before + gGameExternalOptions.fEnableChanceOfEnemyAmbushes = iniReader.ReadBoolean("Tactical Difficulty Settings", "ENABLE_CHANCE_OF_ENEMY_AMBUSHES", TRUE); + gGameExternalOptions.bChanceModifierEnemyAmbushes = iniReader.ReadInteger("Tactical Difficulty Settings","ENEMY_AMBUSHES_CHANCE_MODIFIER ", 0, -100, 100); + + // SANDRO - Special NPCs strength increased by percent + gGameExternalOptions.usSpecialNPCStronger = iniReader.ReadInteger("Tactical Difficulty Settings", "SPECIAL_NPCS_STRONGER",0, 0, 200); + //################# Tactical Vision Settings ################# @@ -844,7 +957,6 @@ void LoadGameExternalOptions() gGameExternalOptions.gfAllowLimitedVision = iniReader.ReadBoolean("Tactical Vision Settings","ALLOW_TUNNEL_VISION",0); - //################# Tactical Tooltip Settings ################# // ShadoWarrior: Tooltip changes (start) @@ -859,6 +971,7 @@ void LoadGameExternalOptions() gGameExternalOptions.fEnableSoldierTooltipAttitude = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_ATTITUDE", TRUE); gGameExternalOptions.fEnableSoldierTooltipActionPoints = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_ACTIONPOINTS", TRUE); gGameExternalOptions.fEnableSoldierTooltipHealth = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_HEALTH", TRUE); + gGameExternalOptions.fEnableSoldierTooltipTraits = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_TRAITS", TRUE); // added by SANDRO gGameExternalOptions.fEnableSoldierTooltipHelmet = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_HELMET", TRUE); gGameExternalOptions.fEnableSoldierTooltipVest = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_VEST", TRUE); gGameExternalOptions.fEnableSoldierTooltipLeggings = iniReader.ReadBoolean("Tactical Tooltip Settings", "SOLDIER_TOOLTIP_DISPLAY_LEGGINGS", TRUE); @@ -880,6 +993,7 @@ void LoadGameExternalOptions() gGameExternalOptions.ubUDTModifier = (UINT8) iniReader.ReadInteger("Tactical Tooltip Settings", "DYNAMIC_TOOLTIP_RANGE_MODIFIER", 50); gGameExternalOptions.gfAllowUDTDetail = iniReader.ReadBoolean("Tactical Tooltip Settings","ALLOW_DYNAMIC_TOOLTIP_DETAIL_LEVEL",0); + //################# Tactical Gameplay Settings ################## // HEADROCK HAM B1: Set minimum and maximum CTH @@ -899,30 +1013,121 @@ void LoadGameExternalOptions() // HEADROCK HAM B2.5: Realistic tracers - CTH increased by this amount whenever a tracer is fired. 0 = off. gGameExternalOptions.ubCTHBumpPerTracer = iniReader.ReadInteger("Tactical Gameplay Settings","CTH_BUMP_PER_TRACER", 30, 0, 100 ); + // CHRISL: Exeternalize the minimum range at which tracers can improve autofire hit chance + gGameExternalOptions.ubMinRangeTracerEffect = iniReader.ReadInteger("Tactical Gameplay Settings","MIN_RANGE_FOR_TRACER", 10); + // HEADROCK HAM 3.5: Limit bonus from tracers based on range to target. This is a multiplier factor - higher means harder to aim with tracers. gGameExternalOptions.ubRangeDifficultyAimingWithTracers = iniReader.ReadInteger("Tactical Gameplay Settings","RANGE_EFFECT_ON_MAX_TRACER_CTH_BONUS", 3, 1, 10); // HEADROCK HAM B2.6: Increased aiming costs? gGameExternalOptions.fIncreasedAimingCost = iniReader.ReadBoolean("Tactical Gameplay Settings","INCREASE_AIMING_COSTS", FALSE); + // CHRISL: Converts the AutoFireToHitBonus value to a percentage for CTH calculations + gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier = iniReader.ReadInteger("Tactical Gameplay Settings","AUTOFIRE_TOHIT_BONUS_MULTIPLIER", 0, 0, 10); + // HEADROCK HAM 3.1: Divisor for the AP-to-Ready cost charge on first aiming click, when extra aiming costs are enabled. 0 = No ready-time-based charge. gGameExternalOptions.ubFirstAimReadyCostDivisor = iniReader.ReadInteger("Tactical Gameplay Settings","FIRST_AIM_READY_COST_DIVISOR", 0, 0, 255); + // SANDRO - moved this here from preferences and renamed to actually match its effect + gGameExternalOptions.fAimLevelRestriction = iniReader.ReadBoolean("Tactical Gameplay Settings","ALLOW_EXTRA_AIM_LEVELS", TRUE); + // HEADROCK HAM B2.6: Dynamically determine Max-Aiming based also on weapon, bipod, etc? gGameExternalOptions.fDynamicAimingTime = iniReader.ReadBoolean("Tactical Gameplay Settings","DYNAMIC_AIMING_LIMITS", FALSE); + // allow old behaviour + gGameExternalOptions.fAimLevelsDependOnDistance = iniReader.ReadBoolean("Tactical Gameplay Settings", "AIM_LEVELS_DEPEND_ON_DISTANCE", TRUE); + + //WarmSteel - These determine in which group each scope belongs. Needed for dynamic aiming limits. + gGameExternalOptions.sVeryHighPowerScope = iniReader.ReadInteger("Tactical Gameplay Settings","VERY_HIGH_POWER_SCOPE_AIM_THRESHOLD", 18, 0, 255); + gGameExternalOptions.sHighPowerScope = iniReader.ReadInteger("Tactical Gameplay Settings","HIGH_POWER_SCOPE_AIM_THRESHOLD", 13, 0, 255); + gGameExternalOptions.sMediumPowerScope = iniReader.ReadInteger("Tactical Gameplay Settings","MEDIUM_POWER_SCOPE_AIM_THRESHOLD", 8, 0, 255); + // HEADROCK HAM B2.6: Controls how much effect target movement has on aiming gGameExternalOptions.iMovementEffectOnAiming = (float)iniReader.ReadDouble("Tactical Gameplay Settings","CTH_PENALTY_FOR_TARGET_MOVEMENT", 1.5, 0.0, 255.0); // HEADROCK HAM 3.3: Externalized maximum possible penalty for hitting a moving target. JA2 Default = 30. gGameExternalOptions.usMaxCTHPenaltyForMovingTarget = iniReader.ReadInteger("Tactical Gameplay Settings","MAX_CTH_PENALTY_FOR_TARGET_MOVEMENT", 30, 0, 300); + // CHRISL: HAM4-NCTH + gGameExternalOptions.fUseNCTH = iniReader.ReadBoolean("Tactical Gameplay Settings", "USE_NCTH", FALSE, false); + // HEADROCK HAM 3.2: Critical Headshots may cause blindness. Rolls 1 to X change of being blinded. 0 = disabled. - gGameExternalOptions.ubChanceBlindedByHeadshot = iniReader.ReadInteger("Tactical Gameplay Settings","CHANCE_BLINDED_BY_HEADSHOT", 0, 0, 10); + gGameExternalOptions.ubChanceBlindedByHeadshot = iniReader.ReadInteger("Tactical Gameplay Settings","CHANCE_BLINDED_BY_HEADSHOT", 0, 0, 100); // HEADROCK HAM 3.2: Critical Legshots cause additional AP loss gGameExternalOptions.fCriticalLegshotCausesAPLoss = iniReader.ReadBoolean("Tactical Gameplay Settings","CRITICAL_LEGSHOT_CAUSES_AP_LOSS", FALSE); + //legion by Jazz + gGameExternalOptions.fCanJumpThroughWindows = iniReader.ReadBoolean("Tactical Gameplay Settings","CAN_JUMP_THROUGH_WINDOWS", FALSE); + gGameExternalOptions.fCanClimbOnWalls = iniReader.ReadBoolean("Tactical Gameplay Settings","CAN_CLIMB_ON_WALLS", FALSE); + + //legion by Jazz + gGameExternalOptions.fIndividualHiddenPersonNames = iniReader.ReadBoolean("Tactical Gameplay Settings","INDIVIDUAL_HIDDEN_PERSON_NAMES", FALSE); + + //Enemy Names by Jazz + gGameExternalOptions.fEnemyNames = iniReader.ReadBoolean("Tactical Gameplay Settings","INDIVIDUAL_ENEMY_NAMES",FALSE); + + //Civ Names by Jazz + gGameExternalOptions.fCivGroupName = iniReader.ReadBoolean("Tactical Gameplay Settings","INDIVIDUAL_CIVILIAN_NAMES",FALSE); + + //Enemy Rank by Jazz + gGameExternalOptions.fEnemyRank = iniReader.ReadBoolean("Tactical Gameplay Settings","INDIVIDUAL_ENEMY_RANK",FALSE); + + // *** ddd - BEGIN + gGameExternalOptions.fExtMouseKeyEnabled = iniReader.ReadBoolean("Tactical Interface Settings", "ENABLE_EXT_MOUSE_KEYS", FALSE); + + // New setting to change stamina + gGameExternalOptions.uStaminaHit = iniReader.ReadInteger("Tactical Interface Settings", "STAMINA_HIT", 10000); + + // Alternative system for aiming - progressive method depending on marksmash of Merc + gGameExternalOptions.bAltAimEnabled = iniReader.ReadBoolean("Tactical Interface Settings","ALT_AIMING_ENABLED",FALSE); + + // Use aimed burst + gGameExternalOptions.bAimedBurstEnabled = iniReader.ReadBoolean("Tactical Interface Settings","USE_AIMED_BURST",FALSE); + + // Penalcy for aimed burst + gGameExternalOptions.uAimedBurstPenalty = iniReader.ReadInteger("Tactical Interface Settings","AIMING_BURST_PENALTY",2); + + // We could see all what can see militia + gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa = iniReader.ReadBoolean("Tactical Interface Settings","WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA",TRUE); + + // Gun supressor can deterioration + gGameExternalOptions.bAllowWearSuppressor = iniReader.ReadBoolean("Tactical Interface Settings","ALLOW_WEAR_SUPPRESSOR",FALSE); + + // Civils don't make too much actions (for faster civils turn) + gGameExternalOptions.bLazyCivilians = iniReader.ReadBoolean("Tactical Interface Settings","ALLOW_LAZY_CIVILIANS",FALSE); + + // Chance to Say Annoying Phrase (you can just turn of it by button in game) + gGameExternalOptions.iChanceSayAnnoyingPhrase = iniReader.ReadInteger("Tactical Interface Settings","CHANCE_SAY_ANNOYING_PHRASE",100); + + // New enemy AI for night battles + gGameExternalOptions.bNewTacticalAIBehavior = iniReader.ReadBoolean("Tactical Interface Settings","NEW_AI_TACTICAL",FALSE); + + // Heahshot penalty + gGameExternalOptions.uShotHeadPenalty = iniReader.ReadFloat("Tactical Interface Settings","SHOT_HEAD_PENALTY",3,0,100); + + // Modifer of damage for HEADSHOT + gGameExternalOptions.fShotHeadDivisor = iniReader.ReadFloat("Tactical Interface Settings","SHOT_HEAD_DIVISOR",1.5,1,10); + + // Penalty for fire when you don't see enemy (when you see enemy because his see militya or ather merc) + gGameExternalOptions.iPenaltyShootUnSeen = iniReader.ReadInteger("Tactical Interface Settings","SHOOT_UNSEEN_PENALTY",0,0,255); + + // CtH/2 if the target are out of gun range or invisible for this merc + gGameExternalOptions.fOutOfGunRangeOrSight = iniReader.ReadFloat("Tactical Interface Settings","OUT_OF_SIGHT_OR_GUN_RANGE",2,1,100); + // *** ddd - END + + // SANDRO - Improved camo applying and camo can be removed + gGameExternalOptions.fCamoRemoving = iniReader.ReadBoolean("Tactical Gameplay Settings", "CAMO_REMOVING", TRUE); + + // SANDRO - Enhanced close combat system + gGameExternalOptions.fEnhancedCloseCombatSystem = iniReader.ReadBoolean("Tactical Gameplay Settings", "ENHANCED_CLOSE_COMBAT_SYSTEM", FALSE); + + // SANDRO - give special Exp for completing quests + gGameExternalOptions.usAwardSpecialExpForQuests = iniReader.ReadInteger("Tactical Gameplay Settings", "AWARD_SPECIAL_EXP_POINTS_FOR_COMPLETING_QUESTS", 100, 0, 5000); + + //tais: soldiers always wear any armour.. + gGameExternalOptions.fSoldiersWearAnyArmour = iniReader.ReadBoolean("Tactical Gameplay Settings", "SOLDIERS_ALWAYS_WEAR_ANY_ARMOR", FALSE); + //################# Tactical Cover System Settings ################## // CPT: Cover System Settings @@ -930,9 +1135,9 @@ void LoadGameExternalOptions() gGameExternalOptions.ubStealthEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_STEALTH_EFFECTIVENESS", 50, 0, 100); gGameExternalOptions.ubCamouflageEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_CAMOUFLAGE_EFFECTIVENESS", 50, 0, 100); gGameExternalOptions.ubStanceEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_STANCE_EFFECTIVENESS", 10, 0, 100); - gGameExternalOptions.ubLBEEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_LBE_EFFECTIVENESS", 50, 0, 100); - gGameExternalOptions.ubMovementEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_MOVEMENT_EFFECTIVENESS", 50, 0, 100); - gGameExternalOptions.ubTreeCoverEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_TREE_EFFECTIVENESS", 50, 0, 100); + gGameExternalOptions.ubLBEEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_LBE_EFFECTIVENESS", 20, 0, 100); + gGameExternalOptions.ubMovementEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_MOVEMENT_EFFECTIVENESS", 20, 0, 100); + gGameExternalOptions.ubTreeCoverEffectiveness = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_TREE_EFFECTIVENESS", 20, 0, 100); gGameExternalOptions.ubCoverDisplayUpdateWait = iniReader.ReadInteger("Tactical Cover System Settings", "COVER_SYSTEM_UPDATE_DELAY", 500, -1, 10000); //################# Tactical Suppression Fire Settings ################## @@ -1099,7 +1304,7 @@ void LoadGameExternalOptions() gGameExternalOptions.fEnableCrepitus = iniReader.ReadBoolean("Strategic Event Settings", "ENABLE_CREPITUS", TRUE); // HEADROCK HAM 3.1: Select which mine will run out. 0 = no mine. 1 = San Mona (unused), 2 = Drassen, 3 = Alma, 4 = Cambria, 5 = Chitzena, 6 = Grumm. - gGameExternalOptions.bWhichMineRunsOut = iniReader.ReadInteger("Strategic Event Settings","WHICH_MINE_SHUTS_DOWN", -1, -1, 6); + gGameExternalOptions.bWhichMineRunsOut = iniReader.ReadInteger("Strategic Event Settings","WHICH_MINE_SHUTS_DOWN", -1, -1, 256); //################# Strategic Gameplay Settings ################## @@ -1109,8 +1314,9 @@ void LoadGameExternalOptions() // Allow reinforcements only between City sectors? gGameExternalOptions.gfAllowReinforcementsOnlyInCity = iniReader.ReadBoolean("Strategic Gameplay Settings","ALLOW_REINFORCEMENTS_ONLY_IN_CITIES",FALSE); - gGameExternalOptions.fEnableAllTerrorists = iniReader.ReadBoolean("Strategic Gameplay Settings", "ENABLE_ALL_TERRORISTS", FALSE); - gGameExternalOptions.fEnableAllWeaponCaches = iniReader.ReadBoolean("Strategic Gameplay Settings", "ENABLE_ALL_WEAPON_CACHES", FALSE); + // SANDRO - moved into the game start screen + //gGameExternalOptions.fEnableAllTerrorists = iniReader.ReadBoolean("Strategic Gameplay Settings", "ENABLE_ALL_TERRORISTS", FALSE); + //gGameExternalOptions.fEnableAllWeaponCaches = iniReader.ReadBoolean("Strategic Gameplay Settings", "ENABLE_ALL_WEAPON_CACHES", FALSE); // Kaiden: Vehicle Inventory change - Added INI file Option VEHICLE_INVENTORY gGameExternalOptions.fVehicleInventory = iniReader.ReadBoolean("Strategic Gameplay Settings", "VEHICLE_INVENTORY", TRUE); @@ -1129,6 +1335,11 @@ void LoadGameExternalOptions() // HEADROCK HAM 3.6: Controls how important the character's stats are, in insuring he/she gets better results (or smaller damage) from using facilities. The higher this is, the more dangerous all facilities are. gGameExternalOptions.ubFacilityDangerRate = iniReader.ReadInteger("Strategic Gameplay Settings","FACILITY_DANGER_RATE", 50, 0, 100); + // 2Points: Use new repair algorithm (Items are priorized based on type and damage to item, starting from equipped weapons, going to armor, then inventory) + gGameExternalOptions.fAdditionalRepairMode = iniReader.ReadBoolean("Strategic Gameplay Settings", "ADDITIONAL_REPAIR_MODE", FALSE); + + // CHRISL: Determine how Skyrider should handle landing in enemy occupied sectors + gGameExternalOptions.ubSkyriderHotLZ = iniReader.ReadInteger("Strategic Gameplay Settings", "ALLOW_SKYRIDER_HOT_LZ", 0); //################# Bobby Ray Settings ################## @@ -1149,6 +1360,7 @@ void LoadGameExternalOptions() gGameExternalOptions.iExplosivesDamageModifier = iniReader.ReadInteger("Item Property Settings","EXPLOSIVES_DAMAGE_MODIFIER",100, 0, 1000); gGameExternalOptions.iMeleeDamageModifier = iniReader.ReadInteger("Item Property Settings","MELEE_DAMAGE_MODIFIER",100, 0, 1000); gGameExternalOptions.iGunDamageModifier = iniReader.ReadInteger("Item Property Settings","GUN_DAMAGE_MODIFIER",100, 0, 1000); + gGameExternalOptions.iGunRangeModifier = iniReader.ReadInteger("Item Property Settings","GUN_RANGE_MODIFIER",100, 0, 1000); // Enables the "Coverage" value of armor items. gGameExternalOptions.fEnableArmorCoverage = iniReader.ReadBoolean("Item Property Settings", "ENABLE_ARMOR_COVERAGE", FALSE); // ShadoWarrior for Captain J's armor coverage @@ -1164,7 +1376,10 @@ void LoadGameExternalOptions() // HEADROCK HAM 3.2: Set a divisor for the CtH of Mortar weapons. gGameExternalOptions.ubMortarCTHDivisor = iniReader.ReadInteger("Item Property Settings","MORTAR_CTH_DIVISOR", 1, 1, 255); - + // WarmSteel: NAS + gGameExternalOptions.fUseDefaultSlots = iniReader.ReadBoolean("Item Property Settings","USE_DEFAULT_SLOTS_WHEN_MISSING",FALSE); + gGameExternalOptions.usAttachmentDropRate = iniReader.ReadInteger("Item Property Settings","ATTACHMENT_DROP_RATE",10, 0, 100); + gGameExternalOptions.iMaxEnemyAttachments = iniReader.ReadInteger("Item Property Settings","MAX_ENEMY_ATTACHMENTS",6, 2, MAX_ATTACHMENTS); //################# Strategic Enemy AI Settings ################## @@ -1319,12 +1534,43 @@ void LoadGameExternalOptions() gGameExternalOptions.fAllowMobileReinforceSAM = iniReader.ReadBoolean("Mobile Militia Movement Settings","ALLOW_MOBILE_MILITIA_REINFORCE_SAM_GARRISONS", FALSE); + // SANDRO - added several bonuses for militia + //################# Militia Strength Settings ################## + + // These applies for autoresolve only + gGameExternalOptions.sGreenMilitiaAutoresolveStrength = iniReader.ReadInteger("Militia Strength Settings", "GREEN_MILITIA_AUTORESOLVE_STRENGTH_BONUS", 0, -100, 500); + gGameExternalOptions.sRegularMilitiaAutoresolveStrength = iniReader.ReadInteger("Militia Strength Settings", "REGULAR_MILITIA_AUTORESOLVE_STRENGTH_BONUS", 0, -100, 500); + gGameExternalOptions.sVeteranMilitiaAutoresolveStrength = iniReader.ReadInteger("Militia Strength Settings", "VETERAN_MILITIA_AUTORESOLVE_STRENGTH_BONUS", 10, -100, 500); + + // Flat bonus to militia APs - applies during tactical combat only + gGameExternalOptions.bGreenMilitiaAPsBonus = iniReader.ReadInteger("Militia Strength Settings", "GREEN_MILITIA_APS_BONUS", 0, -75, 75); + gGameExternalOptions.bRegularMilitiaAPsBonus = iniReader.ReadInteger("Militia Strength Settings", "REGULAR_MILITIA_APS_BONUS", 0, -75, 75); + gGameExternalOptions.bVeteranMilitiaAPsBonus = iniReader.ReadInteger("Militia Strength Settings", "VETERAN_MILITIA_APS_BONUS", 5, -75, 75); + + // Percentage bonus to total militia CtH on every hit - applies during tactical combat only + gGameExternalOptions.sGreenMilitiaCtHBonusPercent = iniReader.ReadInteger("Militia Strength Settings", "GREEN_MILITIA_CTH_BONUS_PERCENT", 0, -100, 500); + gGameExternalOptions.sRegularMilitiaCtHBonusPercent = iniReader.ReadInteger("Militia Strength Settings", "REGULAR_MILITIA_CTH_BONUS_PERCENT", 0, -100, 500); + gGameExternalOptions.sVeteranMilitiaCtHBonusPercent = iniReader.ReadInteger("Militia Strength Settings", "VETERAN_MILITIA_CTH_BONUS_PERCENT", 10, -100, 500); + + // Damage the militia suffer is reduced by this percentage - applies during tactical combat only + gGameExternalOptions.bGreenMilitiaDamageResistance = iniReader.ReadInteger("Militia Strength Settings", "GREEN_MILITIA_DAMAGE_RESISTANCE", 0, -50, 95); + gGameExternalOptions.bRegularMilitiaDamageResistance = iniReader.ReadInteger("Militia Strength Settings", "REGULAR_MILITIA_DAMAGE_RESISTANCE", 0, -50, 95); + gGameExternalOptions.bVeteranMilitiaDamageResistance = iniReader.ReadInteger("Militia Strength Settings", "VETERAN_MILITIA_DAMAGE_RESISTANCE", 0, -50, 95); + + // Modifier increasing militia equipment quality on creation - applies during tactical combat only + gGameExternalOptions.bGreenMilitiaEquipmentQualityModifier = iniReader.ReadInteger("Militia Strength Settings", "GREEN_MILITIA_EQUIPMENT_QUALITY_MODIFIER", 0, -5, 10); + gGameExternalOptions.bRegularMilitiaEquipmentQualityModifier = iniReader.ReadInteger("Militia Strength Settings", "REGULAR_MILITIA_EQUIPMENT_QUALITY_MODIFIER", 0, -5, 10); + gGameExternalOptions.bVeteranMilitiaEquipmentQualityModifier = iniReader.ReadInteger("Militia Strength Settings", "VETERAN_MILITIA_EQUIPMENT_QUALITY_MODIFIER", 1, -5, 10); + + //################# Shopkeeper Inventory Settings ################## // WDS - Improve Tony's and Devin's inventory like BR's gGameExternalOptions.tonyUsesBRSetting = iniReader.ReadBoolean("Shopkeeper Inventory Settings","TONY_USES_BOBBY_RAYS_SETTING", FALSE); gGameExternalOptions.devinUsesBRSetting = iniReader.ReadBoolean("Shopkeeper Inventory Settings","DEVIN_USES_BOBBY_RAYS_SETTING", FALSE); + // chance that Tony will be in his office - silversurfer/SANDRO + gGameExternalOptions.ubChanceTonyAvailable = iniReader.ReadInteger("Shopkeeper Inventory Settings","CHANCE_TONY_AVAILABLE", 80, 0, 100); //################# Strategic Assignment Settings ################## @@ -1358,7 +1604,7 @@ void LoadGameExternalOptions() gGameExternalOptions.ubHighActivityLevel = iniReader.ReadInteger("Strategic Assignment Settings","NATURAL_HEALING_SPEED_DIVISOR_AT_HIGH_ACTIVITY_LEVEL",12, 1, 100); gGameExternalOptions.ubDoctoringRateDivisor = iniReader.ReadInteger("Strategic Assignment Settings","DOCTORING_RATE_DIVISOR",2400, 1200, 24000); - gGameExternalOptions.ubHospitalHealingRate = iniReader.ReadInteger("Strategic Assignment Settings","HOSPITAL_HEALING_RATE",5, 1, 10); + gGameExternalOptions.ubHospitalHealingRate = iniReader.ReadInteger("Strategic Assignment Settings","HOSPITAL_HEALING_RATE",5, 1, 12); gGameExternalOptions.ubBaseMedicalSkillToDealWithEmergency = iniReader.ReadInteger("Strategic Assignment Settings","BASE_MEDICAL_SKILL_TO_DEAL_WITH_EMERGENCY",20, 0, 100); gGameExternalOptions.ubMultiplierForDifferenceInLifeValueForEmergency = iniReader.ReadInteger("Strategic Assignment Settings","MULTIPLIER_FOR_DIFFERENCE_IN_LIFE_VALUE_FOR_EMERGENCY",4, 1, 10); gGameExternalOptions.ubPointCostPerHealthBelowOkLife = iniReader.ReadInteger("Strategic Assignment Settings","POINT_COST_PER_HEALTH_BELOW_OKLIFE",2, 1, 5);//OKLIFE = 15 @@ -1366,19 +1612,274 @@ void LoadGameExternalOptions() ////////// REPAIR ////////// gGameExternalOptions.ubRepairCostPerJam = iniReader.ReadInteger("Strategic Assignment Settings","REPAIR_POINT_COST_TO_FIX_WEAPON_JAM",2, 1, 10); - gGameExternalOptions.ubRepairRateDivisor = iniReader.ReadInteger("Strategic Assignment Settings","REPAIR_RATE_DIVISOR",2500, 1250, 25000); + gGameExternalOptions.ubRepairRateDivisor = iniReader.ReadInteger("Strategic Assignment Settings","REPAIR_RATE_DIVISOR",2500, 500, 25000); gGameExternalOptions.ubAssignmentUnitsPerDay = iniReader.ReadInteger("Strategic Assignment Settings","REPAIR_SESSIONS_PER_DAY",24, 1, 96); - - // WANNE: This is just a debug setting. Only in debug version we should check if propert is set in the ja2_options.ini, + + //SaveGame slot by Jazz + // WANNE: No need to make it external to switch between old/new. We always use the new save/load screen with more save slots + //gGameExternalOptions.fSaveGameSlot = iniReader.ReadBoolean("Extension","SAVE_GAMES_SLOT",FALSE); + gGameExternalOptions.fSaveGameSlot = TRUE; + + // WANNE: This is just a debug setting. Only in debug version we set that property to TRUE. // In Release version this should always be set to FALSE - //dnl ch51 081009 JA2 Debug Settings + // dnl ch51 081009 JA2 Debug Settings #ifdef _DEBUG gGameExternalOptions.fEnableInventoryPoolQ = TRUE; #else gGameExternalOptions.fEnableInventoryPoolQ = FALSE; -#endif +#endif } + +// SANDRO - externalization of all skill trait values and STOMP settings into separate file +void LoadSkillTraitsExternalSettings() +{ + CIniReader iniReader(STOMP_SETTINGS_FILE); + + gSkillTraitValues.ubMaxNumberOfTraits = iniReader.ReadInteger("Generic Traits Settings","MAX_NUMBER_OF_TRAITS", 3, 2, 30); + gSkillTraitValues.ubNumberOfMajorTraitsAllowed = iniReader.ReadInteger("Generic Traits Settings","NUMBER_OF_MAJOR_TRAITS_ALLOWED", 2, 2, 20); + + // GENERIC SETTINGS + gSkillTraitValues.bCtHModifierAssaultRifles = iniReader.ReadInteger("Generic Traits Settings","ASSAULT_RIFLES_CTH_MODIFIER", -5, -100, 100); + gSkillTraitValues.bCtHModifierSniperRifles = iniReader.ReadInteger("Generic Traits Settings","SNIPER_RIFLES_CTH_MODIFIER", -10, -100, 100); + gSkillTraitValues.bCtHModifierRifles = iniReader.ReadInteger("Generic Traits Settings","RIFLES_CTH_MODIFIER", -5, -100, 100); + gSkillTraitValues.bCtHModifierSMGs = iniReader.ReadInteger("Generic Traits Settings","SMGS_CTH_MODIFIER", -5, -100, 100); + gSkillTraitValues.bCtHModifierLMGs = iniReader.ReadInteger("Generic Traits Settings","LMGS_CTH_MODIFIER", -10, -100, 100); + gSkillTraitValues.bCtHModifierShotguns = iniReader.ReadInteger("Generic Traits Settings","SHOTGUNS_CTH_MODIFIER", -5, -100, 100); + gSkillTraitValues.bCtHModifierPistols = iniReader.ReadInteger("Generic Traits Settings","PISTOLS_CTH_MODIFIER", -5, -100, 100); + gSkillTraitValues.bCtHModifierMachinePistols = iniReader.ReadInteger("Generic Traits Settings","MACHINE_PISTOLS_CTH_MODIFIER", -5, -100, 100); + gSkillTraitValues.bCtHModifierRocketLaunchers = iniReader.ReadInteger("Generic Traits Settings","ROCKET_LAUNCHERS_CTH_MODIFIER", -25, -100, 100); + gSkillTraitValues.bCtHModifierGrenadeLaunchers = iniReader.ReadInteger("Generic Traits Settings","GRENADE_LAUNCHERS_CTH_MODIFIER", -25, -100, 100); + gSkillTraitValues.sCtHModifierMortar = iniReader.ReadInteger("Generic Traits Settings","MORTAR_CTH_MODIFIER", -60, -500, 500); + gSkillTraitValues.bCtHModifierThrowingKnives = iniReader.ReadInteger("Generic Traits Settings","THROWING_KNIVES_CTH_MODIFIER", -15, -100, 100); + gSkillTraitValues.bCtHModifierThrowingGrenades = iniReader.ReadInteger("Generic Traits Settings","THROWING_GRENADES_CTH_MODIFIER", -10, -100, 100); + gSkillTraitValues.bCtHModifierHtHAttack = iniReader.ReadInteger("Generic Traits Settings","HTH_ATTACK_CTH_MODIFIER", -15, -100, 100); + gSkillTraitValues.bModifierDodgeHtHChance = iniReader.ReadInteger("Generic Traits Settings","CHANCE_TO_DODGE_HTH_MODIFIER", -10, -100, 100); + gSkillTraitValues.bCtHModifierKnifeAttack = iniReader.ReadInteger("Generic Traits Settings","KNIFE_ATTACK_CTH_MODIFIER", -10, -100, 100); + gSkillTraitValues.bModifierDodgeKnifeChance = iniReader.ReadInteger("Generic Traits Settings","CHANCE_TO_DODGE_KNIFE_MODIFIER", -10, -100, 100); + gSkillTraitValues.bCtHModifierRobot = iniReader.ReadInteger("Generic Traits Settings","ROBOT_CTH_MODIFIER", -10, -100, 100); + gSkillTraitValues.ubCtHPenaltyDualShot = iniReader.ReadInteger("Generic Traits Settings","DUAL_SHOT_CTH_PENALTY", 25, 0, 100); + gSkillTraitValues.bPercentModifierHtHBreathLoss = iniReader.ReadInteger("Generic Traits Settings","PERCENT_BREATH_LOSS_ON_HTH_ATTACK_MODIFIER", -25, -100, 100); + gSkillTraitValues.bPercentModifierBladesBreathLoss = iniReader.ReadInteger("Generic Traits Settings","PERCENT_BREATH_LOSS_ON_KNIFE_ATTACK_MODIFIER", -25, -100, 100); + gSkillTraitValues.bPercentModifierBluntBreathLoss = iniReader.ReadInteger("Generic Traits Settings","PERCENT_BREATH_LOSS_ON_BLUNT_MELEE_ATTACK_MODIFIER", -40, -100, 100); + gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches = iniReader.ReadInteger("Generic Traits Settings","MODIFIER_FOR_APS_ADDED_ON_AIMED_HTH_ATTACKS", 3, 1, 10); + gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes = iniReader.ReadInteger("Generic Traits Settings","MODIFIER_FOR_APS_ADDED_ON_AIMED_BLADE_ATTACKS", 3, 1, 10); + gSkillTraitValues.bSpeedModifierDoctoring = iniReader.ReadInteger("Generic Traits Settings","DOCTORING_SPEED_MODIFIER", -40, -100, 100); + gSkillTraitValues.bSpeedModifierBandaging = iniReader.ReadInteger("Generic Traits Settings","BANDAGING_SPEED_MODIFIER", -30, -100, 100); + gSkillTraitValues.bSpeedModifierRepairing = iniReader.ReadInteger("Generic Traits Settings","REPAIRING_SPEED_MODIFIER", -20, -100, 100); + gSkillTraitValues.bSpeedModifierTrainingMilitia = iniReader.ReadInteger("Generic Traits Settings","TRAIN_MILITIA_MODIFIER", -10, -100, 100); + gSkillTraitValues.bSpeedModifierTeachingOthers = iniReader.ReadInteger("Generic Traits Settings","TEACHING_OTHERS_MODIFIER", -15, -100, 100); + gSkillTraitValues.bCheckModifierLockpicking = iniReader.ReadInteger("Generic Traits Settings","LOCKPICKING_CHECK_MODIFIER", -10, -100, 100); + gSkillTraitValues.bCheckModifierAttachDetonators = iniReader.ReadInteger("Generic Traits Settings","ATTACHING_DETONATORS_CHECK_MODIFIER", -15, -100, 100); + gSkillTraitValues.bCheckModifierSetExplosives = iniReader.ReadInteger("Generic Traits Settings","SET_EXPLOSIVES_CHECK_MODIFIER", -15, -100, 100); + gSkillTraitValues.bCheckModifierDisarmExplosiveTraps = iniReader.ReadInteger("Generic Traits Settings","DISARM_EXPLOSIVE_TRAPS_CHECK_MODIFIER", -15, -100, 100); + gSkillTraitValues.bCheckModifierDisarmElectronicTraps = iniReader.ReadInteger("Generic Traits Settings","DISARM_ELECTRONIC_TRAPS_CHECK_MODIFIER", -15, -100, 100); + gSkillTraitValues.bCheckModifierAttachSpecialItems = iniReader.ReadInteger("Generic Traits Settings","ATTACH_SPECIAL_ITEMS_CHECK_MODIFIER", -15, -100, 100); + gSkillTraitValues.bTanksDamageResistanceModifier = iniReader.ReadInteger("Generic Traits Settings","TANKS_DAMAGE_RESISTANCE_MODIFIER", 40, -100, 95); + gSkillTraitValues.ubDamageNeededToLoseStats = iniReader.ReadInteger("Generic Traits Settings","DAMAGE_NEEDED_TO_LOSE_STATS", 15, 0, 100); + + // AUTO WEAPONS + gSkillTraitValues.ubAWBonusCtHAssaultRifles = iniReader.ReadInteger("Auto Weapons","BONUS_CTH_ASSAULT_RIFLES", 5, 0, 100); + gSkillTraitValues.ubAWBonusCtHSMGs = iniReader.ReadInteger("Auto Weapons","BONUS_CTH_SMGS", 5, 0, 100); + gSkillTraitValues.ubAWBonusCtHLMGs = iniReader.ReadInteger("Auto Weapons","BONUS_CTH_LMGS", 5, 0, 100); + gSkillTraitValues.ubAWAutoFirePenaltyReduction = iniReader.ReadInteger("Auto Weapons","AUTOFIRE_PENALTY_REDUCTION", 40, 0, 100); + gSkillTraitValues.ubAWUnwantedBulletsReduction = iniReader.ReadInteger("Auto Weapons","UNWANTED_BULLETS_REDUCTION", 4, 0, 40); + gSkillTraitValues.ubAWFiringSpeedBonusLMGs = iniReader.ReadInteger("Auto Weapons","FIRING_SPEED_BONUS_LMGS", 10, 0, 45); + gSkillTraitValues.ubAWPercentReadyLMGReduction = iniReader.ReadInteger("Auto Weapons","PERCENT_AP_READY_LMG_REDUCTION", 10, 0, 45); + + // HEAVY WEAPONS + gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction = iniReader.ReadInteger("Heavy Weapons","GRENADE_LAUNCHERS_FIRE_AP_REDUCTION", 20, 0, 45); + gSkillTraitValues.ubHWRocketLaunchersAPsReduction = iniReader.ReadInteger("Heavy Weapons","ROCKET_LAUNCHERS_FIRE_AP_REDUCTION", 20, 0, 45); + gSkillTraitValues.ubHWBonusCtHGrenadeLaunchers = iniReader.ReadInteger("Heavy Weapons","BONUS_CTH_GRENADE_LAUNCHERS", 25, 0, 100); + gSkillTraitValues.ubHWBonusCtHRocketLaunchers = iniReader.ReadInteger("Heavy Weapons","BONUS_CTH_ROCKET_LAUNCHERS", 25, 0, 100); + gSkillTraitValues.ubHWMortarAPsReduction = iniReader.ReadInteger("Heavy Weapons","MORTAR_FIRE_AP_REDUCTION", 10, 0, 45); + gSkillTraitValues.ubHWMortarCtHPenaltyReduction = iniReader.ReadInteger("Heavy Weapons","MORTAR_CTH_PENALTY_REDUCTION", 50, 0, 100); + gSkillTraitValues.ubHWDamageTanksBonusPercent = iniReader.ReadInteger("Heavy Weapons","DAMAGE_TO_TANKS_PERCENT_BONUS", 30, 0, 200); + gSkillTraitValues.ubHWDamageBonusPercentForHW = iniReader.ReadInteger("Heavy Weapons","HW_DAMAGE_PERCENT_BONUS", 15, 0, 100); + + // SNIPER + gSkillTraitValues.ubSNBonusCtHRifles = iniReader.ReadInteger("Sniper","BONUS_CTH_RIFLES", 5, 0, 100); + gSkillTraitValues.ubSNBonusCtHSniperRifles = iniReader.ReadInteger("Sniper","BONUS_CTH_SNIPER_RIFLES", 10, 0, 100); + gSkillTraitValues.ubSNEffRangeToTargetReduction = iniReader.ReadInteger("Sniper","EFFECTIVE_RANGE_TO_TARGET_REDUCTION", 5, 0, 45); + gSkillTraitValues.ubSNAimingBonusPerClick = iniReader.ReadInteger("Sniper","AIMING_BONUS_PER_CLICK_RIFLES", 10, 0, 50); + gSkillTraitValues.ubSNDamageBonusPerClick = iniReader.ReadInteger("Sniper","GUN_DAMAGE_BONUS_PER_CLICK", 5, 0, 50); + gSkillTraitValues.ubSNDamageBonusFromNumClicks = iniReader.ReadInteger("Sniper","GUN_DAMAGE_BONUS_FROM_NUM_CLICKS", 4, 0, 8); + gSkillTraitValues.ubSNChamberRoundAPsReduction = iniReader.ReadInteger("Sniper","CHAMBER_ROUND_APS_REDUCTION", 25, 0, 45); + gSkillTraitValues.ubSNAimClicksAdded = iniReader.ReadInteger("Sniper","POSSIBLE_AIM_CLICK_ADDED_RIFLES", 1, 0, 3); + + // RANGER + gSkillTraitValues.ubRABonusCtHRifles = iniReader.ReadInteger("Ranger","BONUS_CTH_RIFLES", 5, 0, 100); + gSkillTraitValues.ubRABonusCtHShotguns = iniReader.ReadInteger("Ranger","BONUS_CTH_SHOTGUNS", 10, 0, 100); + gSkillTraitValues.ubRAPumpShotgunsAPsReduction = iniReader.ReadInteger("Ranger","PUMP_SHOTGUNS_APS_REDUCTION", 25, 0, 45); + gSkillTraitValues.ubRAGroupTimeSpentForTravellingFoot = iniReader.ReadInteger("Ranger","GROUP_TIME_SPENT_FOR_TRAVELLING_BY_FOOT_REDUCTION", 20, 0, 100); + gSkillTraitValues.ubRAGroupTimeSpentForTravellingVehicle = iniReader.ReadInteger("Ranger","GROUP_TIME_SPENT_FOR_TRAVELLING_IN_VEHICLE_REDUCTION", 10, 0, 100); + gSkillTraitValues.ubRAMaxBonusesToTravelSpeed = iniReader.ReadInteger("Ranger","MAX_STACKABLE_LESS_TRAVEL_TIME_BONUSES", 2, 0, 20); + gSkillTraitValues.ubRABreathForTravellingReduction = iniReader.ReadInteger("Ranger","ENERGY_SPENT_TRAVEL_REDUCTION", 30, 0, 100); + gSkillTraitValues.ubRAWeatherPenaltiesReduction = iniReader.ReadInteger("Ranger","WEATHER_PENALTIES_REDUCTION", 50, 0, 100); + //gSkillTraitValues.ubRACamoEffectivenessBonus = iniReader.ReadInteger("Ranger","CAMO_EFFECTIVENESS_BONUS_PERCENT", 10, 0, 100); + gSkillTraitValues.ubRACamoWornountSpeedReduction = iniReader.ReadInteger("Ranger","CAMO_WORNOUT_SPEED_REDUCTION", 50, 0, 100); + + // GUNSLINGER + gSkillTraitValues.ubGSFiringSpeedBonusPistols = iniReader.ReadInteger("Gunslinger","FIRING_SPEED_BONUS_PISTOLS", 15, 0, 45); + gSkillTraitValues.ubGSEffectiveRangeBonusPistols = iniReader.ReadInteger("Gunslinger","FEFFECTIVE_RANGE_BONUS_PISTOLS", 10, 0, 100); + gSkillTraitValues.ubGSBonusCtHPistols = iniReader.ReadInteger("Gunslinger","BONUS_CTH_PISTOLS", 10, 0, 100); + gSkillTraitValues.ubGSBonusCtHMachinePistols = iniReader.ReadInteger("Gunslinger","BONUS_CTH_MACHINE_PISTOLS", 5, 0, 100); + gSkillTraitValues.ubGSCtHMPExcludeAuto = iniReader.ReadBoolean("Gunslinger","CTH_MP_EXCLUDE_AUTOFIRE", TRUE); + gSkillTraitValues.ubGSAimingBonusPerClick = iniReader.ReadInteger("Gunslinger","AIMING_BONUS_PER_CLICK_HANDGUNS", 5, 0, 100); + gSkillTraitValues.ubGSPercentReadyPistolsReduction = iniReader.ReadInteger("Gunslinger","PERCENT_AP_READY_PISTOLS_REDUCTION", 15, 0, 50); + gSkillTraitValues.ubGSRealoadSpeedHandgunsBonus = iniReader.ReadInteger("Gunslinger","RELOAD_SPEED_HANDGUNS_BONUS", 25, 0, 45); + gSkillTraitValues.ubGSAimClicksAdded = iniReader.ReadInteger("Gunslinger","POSSIBLE_AIM_CLICK_ADDED_HANDGUNS", 1, 0, 3); + + // MARTIAL ARTS + gSkillTraitValues.ubMAPunchAPsReduction = iniReader.ReadInteger("Martial Arts","PUNCH_APS_REDUCTION", 15, 0, 50); + gSkillTraitValues.ubMABonusCtHBareHands = iniReader.ReadInteger("Martial Arts","BONUS_CTH_BARE_HANDS", 30, 0, 100); + gSkillTraitValues.ubMABonusCtHBrassKnuckles = iniReader.ReadInteger("Martial Arts","BONUS_CTH_KNUCKLES", 25, 0, 100); + gSkillTraitValues.ubMABonusDamageHandToHand = iniReader.ReadInteger("Martial Arts","BONUS_HTH_DAMAGE", 30, 0, 250); + gSkillTraitValues.ubMABonusBreathDamageHandToHand = iniReader.ReadInteger("Martial Arts","BONUS_HTH_BREATH_DAMAGE", 30, 0, 250); + gSkillTraitValues.usMALostBreathRegainPenalty = iniReader.ReadInteger("Martial Arts","LOST_BREATH_REGAIN_PENALTY", 50, 0, 10000); + gSkillTraitValues.usMAAimedPunchDamageBonus = iniReader.ReadInteger("Martial Arts","AIMED_PUNCH_DAMAGE_BONUS", 75, 0, 3000); + gSkillTraitValues.bMAAimedPunchCtHModifier = iniReader.ReadInteger("Martial Arts","AIMED_PUNCH_CTH_MODIFIER", 0, -100, 100); + gSkillTraitValues.ubMAChanceToDodgeHtH = iniReader.ReadInteger("Martial Arts","BONUS_CHANCE_TO_DODGE_HTH", 35, 0, 250); + gSkillTraitValues.ubMAOnTopCTDHtHBareHanded = iniReader.ReadInteger("Martial Arts","ONTOP_BONUS_CTD_HTH_WITH_BARE_HANDS", 5, 0, 250); + gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles = iniReader.ReadInteger("Martial Arts","ONTOP_BONUS_CTD_HTH_WITH_KNUCKLES", 0, 0, 250); + gSkillTraitValues.ubMAChanceToDodgeMelee = iniReader.ReadInteger("Martial Arts","BONUS_CHANCE_TO_DODGE_MELEE", 20, 0, 250); + gSkillTraitValues.ubMAReducedAPsToSteal = iniReader.ReadInteger("Martial Arts","APS_TO_STEAL_WEAPON_REDUCTION", 25, 0, 50); + gSkillTraitValues.ubMAAPsChangeStanceReduction = iniReader.ReadInteger("Martial Arts","APS_CHANGE_STANCE_REDUCTION", 25, 0, 100); + gSkillTraitValues.ubMAApsTurnAroundReduction = iniReader.ReadInteger("Martial Arts","APS_TURN_AROUND_REDUCTION", 25, 0, 100); + gSkillTraitValues.ubMAAPsClimbOrJumpReduction = iniReader.ReadInteger("Martial Arts","APS_CLIMB_OR_JUMP_REDUCTION", 25, 0, 100); + gSkillTraitValues.ubMAChanceToCkickDoors = iniReader.ReadInteger("Martial Arts","CHANCE_KICK_DOORS_BONUS", 25, 0, 250); + gSkillTraitValues.fPermitExtraAnimationsOnlyToMA = iniReader.ReadBoolean("Martial Arts","PERMIT_EXTRA_ANIMATIONS_TO_EXPERT_MARTIAL_ARTS_ONLY", TRUE); + + // SQUADLEADER + gSkillTraitValues.usSLRadiusNormal = iniReader.ReadInteger("Squadleader","BONUSES_RADIUS_NORMAL", 10, 2, 1000); + gSkillTraitValues.usSLRadiusExtendedEar = iniReader.ReadInteger("Squadleader","BONUSES_RADIUS_EXTENDED_EAR", 20, 2, 1000); + if( gSkillTraitValues.usSLRadiusExtendedEar < gSkillTraitValues.usSLRadiusNormal ) { gSkillTraitValues.usSLRadiusExtendedEar = gSkillTraitValues.usSLRadiusNormal; } + gSkillTraitValues.ubSLMaxBonuses = iniReader.ReadInteger("Squadleader","MAX_STACKABLE_BONUSES", 3, 1, 30); + gSkillTraitValues.ubSLBonusAPsPercent = iniReader.ReadInteger("Squadleader","BONUS_APS_PERCENT_IN_RADIUS", 5, 0, 100); + gSkillTraitValues.ubSLEffectiveLevelInRadius = iniReader.ReadInteger("Squadleader","EFFECTIVE_LEVEL_OF_OTHERS_IN_RADIUS", 1, 0, 10); + gSkillTraitValues.ubSLEffectiveLevelAsStandby = iniReader.ReadInteger("Squadleader","EFFECTIVE_LEVEL_AS_STANDBY", 1, 0, 10); + gSkillTraitValues.ubSLOverallSuppresionBonusPercent = iniReader.ReadInteger("Squadleader","OVERALL_SUPRESSION_BONUS_PERCENT", 20, 0, 100); + gSkillTraitValues.ubSLMoraleGainBonus = iniReader.ReadInteger("Squadleader","MORALE_GAIN_BONUS", 1, 0, 20); + gSkillTraitValues.ubSLMoraleLossReduction = iniReader.ReadInteger("Squadleader","MORALE_LOSS_REDUCTION", 1, 0, 20); + gSkillTraitValues.ubSLFearResistance = iniReader.ReadInteger("Squadleader","SL_FEAR_RESISTANCE", 50, 0, 100); + gSkillTraitValues.ubSLDeathMoralelossMultiplier = iniReader.ReadInteger("Squadleader","SL_DEATH_MORALE_LOSS_MULTIPLIER", 1, 0, 10); + + // TECHNICIAN + gSkillTraitValues.usTERepairSpeedBonus = iniReader.ReadInteger("Technician","REPAIR_SPEED_BONUS_PERCENT", 25, 0, 1000); + gSkillTraitValues.usTELockpickingBonus = iniReader.ReadInteger("Technician","LOCKPICKING_BONUS", 30, 0, 1000); + gSkillTraitValues.usTEDisarmElTrapBonus = iniReader.ReadInteger("Technician","DISARMING_ELECTRONIC_TRAPS_BONUS", 40, 0, 1000); + gSkillTraitValues.usTEAttachingItemsBonus = iniReader.ReadInteger("Technician","COMBINING_ITEMS_BONUS", 40, 0, 1000); + gSkillTraitValues.ubTEUnjamGunBonus = iniReader.ReadInteger("Technician","UNJAMMING_GUN_BONUS", 20, 0, 250); + gSkillTraitValues.ubTERepairElectronicsPenaltyReduction = iniReader.ReadInteger("Technician","REPAIR_ELECTRONICS_PENALTY_REDUCTION", 50, 0, 100); + gSkillTraitValues.ubTEChanceToDetectTrapsBonus = iniReader.ReadInteger("Technician","EFFECTIVE_LEVEL_TO_FIND_TRAPS_BONUS", 2, 0, 10); + gSkillTraitValues.ubTECtHControlledRobotBonus = iniReader.ReadInteger("Technician","ROBOT_CTH_BONUS", 10, 0, 100); + gSkillTraitValues.ubTETraitsNumToRepairRobot = iniReader.ReadInteger("Technician","NUMBER_TRAITS_TO_BE_ABLE_TO_REPAIR_THE_ROBOT", 1, 0, 2); + gSkillTraitValues.ubTERepairRobotPenaltyReduction = iniReader.ReadInteger("Technician","REPAIR_SPEED_ROBOT_PENALTY_REDUCTION", 30, 0, 100); + if (gSkillTraitValues.ubTETraitsNumToRepairRobot == 2) {gSkillTraitValues.ubTERepairRobotPenaltyReduction /= 2; } + + // DOCTOR + gSkillTraitValues.ubDONumberTraitsNeededForSurgery = iniReader.ReadInteger("Doctor","NUMBER_OF_TRAITS_NEEDED_FOR_SURGERY", 1, 0, 2); + gSkillTraitValues.ubDOSurgeryHealPercentBase = iniReader.ReadInteger("Doctor","BASE_PERCENT_SURGERY_HEAL", 10, 0, 100); + gSkillTraitValues.ubDOSurgeryHealPercentOnTop = iniReader.ReadInteger("Doctor","ONTOP_PERCENT_SURGERY_HEAL_PER_TRAIT", 20, 0, 100); + gSkillTraitValues.usDOSurgeryMedBagConsumption = iniReader.ReadInteger("Doctor","MEDICAL_BAG_CONSUMPTION_BY_SURGERY", 100, 0, 1000); + gSkillTraitValues.usDOSurgeryMaxBreathLoss = iniReader.ReadInteger("Doctor","MAX_ENERGY_LOSS_FOR_LIFE_HEALED", 100, 0, 500); + gSkillTraitValues.usDORepairStatsRateBasic = iniReader.ReadInteger("Doctor","REPAIR_STATS_RATE_BASIC", 20, 0, 1000); + gSkillTraitValues.usDORepairStatsRateOnTop = iniReader.ReadInteger("Doctor","REPAIR_STATS_RATE_ONTOP", 40, 0, 1000); + gSkillTraitValues.ubDORepStPenaltyIfAlsoHealing = iniReader.ReadInteger("Doctor","REPAIR_STATS_RATE_REDUCTION_IF_ALSO_HEALING", 50, 0, 100); + gSkillTraitValues.ubDOHealingPenaltyIfAlsoStatRepair = iniReader.ReadInteger("Doctor","HEALING_RATE_REDUCTION_IF_ALSO_REPAIRING_STATS", 50, 0, 100); + gSkillTraitValues.fDORepStShouldThrowMessage = iniReader.ReadBoolean("Doctor","SHOW_MESSAGE_ABOUT_STATS_REGAINED", TRUE ); + gSkillTraitValues.usDODoctorAssignmentBonus = iniReader.ReadInteger("Doctor","DOCTOR_ASSIGNMENT_BONUS_PERCENT", 25, 0, 500); + gSkillTraitValues.ubDOBandagingSpeedPercent = iniReader.ReadInteger("Doctor","BANDAGING_SPEED_PERCENT", 30, 0, 250); + gSkillTraitValues.ubDONaturalRegenBonus = iniReader.ReadInteger("Doctor","NATURAL_REGENERATION_IN_SECTOR_BONUS", 10, 0, 250); + gSkillTraitValues.ubDOMaxRegenBonuses = iniReader.ReadInteger("Doctor","MAX_NATURAL_REGEN_BONUSES", 4, 1, 50); + + // AMBIDEXTROUS + gSkillTraitValues.ubAMPenaltyDoubleReduction = iniReader.ReadInteger("Ambidextrous","PENALTY_TO_SHOOT_DOUBLE_GUNS_REDUCTION", 100, 0, 100); + gSkillTraitValues.ubAMReloadSpeedMagazines = iniReader.ReadInteger("Ambidextrous","RELOAD_SPEED_WITH_MAGAZINE_BONUS", 20, 0, 90); + gSkillTraitValues.ubAMReloadSpeedLoose = iniReader.ReadInteger("Ambidextrous","RELOAD_SPEED_WITH_LOOSE_ROUNDS_BONUS", 33, 0, 90); + gSkillTraitValues.ubAMPickItemsAPsReduction = iniReader.ReadInteger("Ambidextrous","PICK_ITEM_AP_REDUCTION", 33, 0, 90); + gSkillTraitValues.ubAMWorkBackpackAPsReduction = iniReader.ReadInteger("Ambidextrous","WORK_BACKPACK_AP_REDUCTION", 33, 0, 90); + gSkillTraitValues.ubAMHandleDoorsAPsReduction = iniReader.ReadInteger("Ambidextrous","HANDLE_DOORS_AP_REDUCTION", 33, 0, 90); + gSkillTraitValues.ubAMHandleBombsAPsReduction = iniReader.ReadInteger("Ambidextrous","HANDLE_BOMBS_AP_REDUCTION", 33, 0, 90); + gSkillTraitValues.ubAMAttachingItemsAPsReduction = iniReader.ReadInteger("Ambidextrous","ATTACH_ITEMS_AP_REDUCTION", 33, 0, 90); + + // MELEE + gSkillTraitValues.ubMEBladesAPsReduction = iniReader.ReadInteger("Melee","BLADE_ATTACK_APS_REDUCTION", 20, 0, 100); + gSkillTraitValues.ubMECtHBladesBonus = iniReader.ReadInteger("Melee","CTH_BLADES_BONUS", 40, 0, 100); + gSkillTraitValues.ubMECtHBluntBonus = iniReader.ReadInteger("Melee","CTH_BLUNT_WEAPONS_BONUS", 30, 0, 200); + gSkillTraitValues.ubMEDamageBonusBlades = iniReader.ReadInteger("Melee","DAMAGE_BONUS_BLADES", 30, 0, 250); + gSkillTraitValues.ubMEDamageBonusBlunt = iniReader.ReadInteger("Melee","DAMAGE_BONUS_BLUNT_WEAPONS", 30, 0, 250); + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus = iniReader.ReadInteger("Melee","AIMED_MELEE_ATTACK_DAMAGE_BONUS", 50, 0, 1000); + gSkillTraitValues.ubMEDodgeBladesBonus = iniReader.ReadInteger("Melee","BONUS_CHANCE_TO_DODGE_BLADES", 30, 0, 200); + gSkillTraitValues.ubMECtDBladesOnTopWithBladeInHands = iniReader.ReadInteger("Melee","ONTOP_CHANCE_TO_DODGE_BLADES_WITH_BLADE", 20, 0, 200); + gSkillTraitValues.ubMEDodgeBluntBonus = iniReader.ReadInteger("Melee","BONUS_CHANCE_TO_DODGE_BLUNT_WEAPONS", 20, 0, 200); + gSkillTraitValues.ubMECtDBluntOnTopWithBladeInHands = iniReader.ReadInteger("Melee","ONTOP_CHANCE_TO_DODGE_BLUNT_WITH_BLADE", 10, 0, 200); + + // THROWING + gSkillTraitValues.ubTHBladesAPsReduction = iniReader.ReadInteger("Throwing","THROW_BLADE_APS_REDUCTION", 20, 0, 90); + gSkillTraitValues.ubTHBladesMaxRange = iniReader.ReadInteger("Throwing","TH_BLADES_RANGE_BONUS", 15, 0, 200); + gSkillTraitValues.ubTHBladesCtHBonus = iniReader.ReadInteger("Throwing","TH_BLADES_CTH_BONUS", 25, 0, 100); + gSkillTraitValues.ubTHBladesCtHBonusPerClick = iniReader.ReadInteger("Throwing","TH_BLADES_CTH_BONUS_PER_AIM_CLICK", 5, 0, 100); + gSkillTraitValues.ubTHBladesDamageBonus = iniReader.ReadInteger("Throwing","TH_BLADES_DAMAGE_BONUS", 20, 0, 250); + gSkillTraitValues.ubTHBladesDamageBonusPerClick = iniReader.ReadInteger("Throwing","TH_BLADES_DAMAGE_BONUS_PER_AIM_CLICK", 10, 0, 100); + gSkillTraitValues.ubTHBladesSilentCriticalHitChance = iniReader.ReadInteger("Throwing","TH_BLADES_SILENT_CRITICAL_HIT_CHANCE", 20, 0, 100); + gSkillTraitValues.ubTHBladesCriticalHitMultiplierBonus = iniReader.ReadInteger("Throwing","SILENT_CRITICAL_HIT_MULTIPLIER_BONUS", 1, 0, 50); + gSkillTraitValues.ubTHBladesAimClicksAdded = iniReader.ReadInteger("Throwing","POSSIBLE_AIM_CLICK_ADDED_TH_KNIVES", 1, 0, 5); + + // NIGHT OPS + gSkillTraitValues.ubNOeSightRangeBonusInDark = iniReader.ReadInteger("Night Ops","SIGHT_RANGE_BONUS_IN_DARK", 1, 0, 100); + gSkillTraitValues.ubNOHearingRangeBonus = iniReader.ReadInteger("Night Ops","BASIC_HEARING_RANGE_BONUS", 1, 0, 100); + gSkillTraitValues.ubNOHearingRangeBonusInDark = iniReader.ReadInteger("Night Ops","ONTOP_HEARING_RANGE_BONUS_IN_DARK", 2, 0, 100); + gSkillTraitValues.ubNOIterruptsBonusInDark = iniReader.ReadInteger("Night Ops","INTERRUPTS_BONUS_IN_DARK", 2, 0, 10); + gSkillTraitValues.ubNONeedForSleepReduction = iniReader.ReadInteger("Night Ops","NEED_FOR_SLEEP_REDUCTION", 3, 0, 10); + + // STEALTHY + gSkillTraitValues.ubSTStealthModeSpeedBonus = iniReader.ReadInteger("Stealthy","STEALTH_MODE_SPEED_BONUS", 50, 0, 100); + gSkillTraitValues.ubSTBonusToMoveQuietly = iniReader.ReadInteger("Stealthy","BONUS_TO_MOVE_STEALTHILY", 40, 0, 250); + gSkillTraitValues.ubSTStealthBonus = iniReader.ReadInteger("Stealthy","STEALTH_BONUS", 25, 0, 200); + gSkillTraitValues.ubSTStealthPenaltyForMovingReduction = iniReader.ReadInteger("Stealthy","CHANCE_TO_BE_SPOTTED_FOR_MOVING_REDUCTION", 25, 0, 100); + + // ATHLETICS + gSkillTraitValues.ubATAPsMovementReduction = iniReader.ReadInteger("Athletics","APS_NEED_FOR_MOVEMENT_REDUCTION", 33, 0, 90); + gSkillTraitValues.ubATBPsMovementReduction = iniReader.ReadInteger("Athletics","BPS_SPENT_FOR_MOVEMENT_REDUCTION", 33, 0, 90); + + // BODYBUILDING + gSkillTraitValues.ubBBDamageResistance = iniReader.ReadInteger("Bodybuilding","DAMAGE_RESISTANCE", 20, 0, 90); + gSkillTraitValues.ubBBCarryWeightBonus = iniReader.ReadInteger("Bodybuilding","CARRY_WEIGHT_BONUS", 30, 0, 250); + gSkillTraitValues.ubBBBreathLossForHtHImpactReduction = iniReader.ReadInteger("Bodybuilding","BREATH_LOSS_FOR_HTH_HIT_REDUCTION", 50, 0, 100); + gSkillTraitValues.usBBIncreasedNeededDamageToFallDown = iniReader.ReadInteger("Bodybuilding","INCREASE_DAMAGE_NEEDED_TO_FALL_DOWN_IF_HIT_TO_LEGS", 100, 0, 500); + + // DEMOLITIONS + gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction = iniReader.ReadInteger("Demolitions","APS_NEEDED_TO_THROW_GRENADES_REDUCTION", 25, 0, 90); + gSkillTraitValues.ubDEMaxRangeToThrowGrenades = iniReader.ReadInteger("Demolitions","MAX_RANGE_TO_THROW_GRENADES", 20, 0, 250); + gSkillTraitValues.ubDECtHWhenThrowingGrenades = iniReader.ReadInteger("Demolitions","CTH_WHEN_THROWING_GRENADES", 30, 0, 100); + gSkillTraitValues.ubDEDamageOfBombsAndMines = iniReader.ReadInteger("Demolitions","DAMAGE_OF_PLACED_BOMBS_AND_MINES", 25, 0, 250); + gSkillTraitValues.ubDEAttachDetonatorCheckBonus = iniReader.ReadInteger("Demolitions","ATTACH_DETONATOR_CHECK_BONUS", 50, 0, 250); + gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus = iniReader.ReadInteger("Demolitions","PLANT_AND_REMOVE_BOMBS_AND_MINES_BONUS", 50, 0, 250); + gSkillTraitValues.ubDEPlacedBombLevelBonus = iniReader.ReadInteger("Demolitions","PLACED_BOMBS_AND_MINES_DETECTION_DIFFICULTY_BONUS", 5, 0, 15); + gSkillTraitValues.ubDEShapedChargeDamageMultiplier = iniReader.ReadInteger("Demolitions","SHAPED_CHARGE_DAMAGE_MULTIPLIER", 3, 1, 50); + + // TEACHING + gSkillTraitValues.ubTGBonusToTrainMilitia = iniReader.ReadInteger("Teaching","BONUS_TO_TRAIN_MILITIA", 40, 0, 250); + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia = iniReader.ReadInteger("Teaching","EFFECTIVE_LEADERSHIP_FOR_MILITIA_TRAINING", 40, 0, 250); + gSkillTraitValues.ubTGBonusToTeachOtherMercs = iniReader.ReadInteger("Teaching","BONUS_TO_TEACH_OTHER_MERCS", 40, 0, 250); + gSkillTraitValues.ubTGEffectiveSkillValueForTeaching = iniReader.ReadInteger("Teaching","EFFECTIVE_SKILL_VALUE_TO_TEACH_OTHERS_BONUS", 25, 0, 100); + gSkillTraitValues.ubTGBonusOnPractising = iniReader.ReadInteger("Teaching","BONUS_ON_PRACTISING", 25, 0, 250); + + // SCOUTING + gSkillTraitValues.ubSCSightRangebonusWithScopes = iniReader.ReadInteger("Scouting","SIGHT_RANGE_INCREASED_WITH_SCOPES", 10, 0, 250); + gSkillTraitValues.usSCSightRangebonusWithBinoculars = iniReader.ReadInteger("Scouting","SIGHT_RANGE_INCREASED_WITH_BINOCULARS", 40, 0, 1000); + gSkillTraitValues.ubSCTunnelVisionReducedWithBinoculars = iniReader.ReadInteger("Scouting","TUNNEL_VISION_REDUCED_WITH_BINOCULARS", 20, 0, 250); + gSkillTraitValues.fSCCanDetectEnemyPresenseAround = iniReader.ReadBoolean("Scouting","CAN_DETECT_ENEMY_PRESENSE_IN_SECTORS_AROUND", TRUE); + gSkillTraitValues.fSCCanDetermineEnemyNumbersAround = iniReader.ReadBoolean("Scouting","CAN_DETERMINE_ENEMY_NUMBERS_IN_SECTORS_AROUND", TRUE); + gSkillTraitValues.fSCDetectionInDiagonalSectors = iniReader.ReadBoolean("Scouting","ALLOW_DETECTION_IN_DIAGONAL_SECTORS", TRUE); + gSkillTraitValues.fSCPreventsTheEnemyToAmbushMercs = iniReader.ReadBoolean("Scouting","PREVENTS_ENEMY_AMBUSHES", TRUE); + gSkillTraitValues.fSCPreventsBloodcatsAmbushes = iniReader.ReadBoolean("Scouting","PREVENTS_BLOODCATS_AMBUSHES", TRUE); + gSkillTraitValues.fSCThrowMessageIfAmbushPrevented = iniReader.ReadBoolean("Scouting","SHOW_MESSAGE_IF_AMBUSH_PREVENTED", TRUE); + +} + + INT16 DynamicAdjustAPConstants(INT16 iniReadValue, INT16 iniDefaultValue, BOOLEAN reverse) { //CHRISL: This function will dynamically adjust all the APBPConstant values based on the AP_MAXIMUM value. This way @@ -1404,10 +1905,10 @@ void LoadGameAPBPConstants() //CHRISL: To allow for dynamic settings, we need to switch AP_MAXIMUM and AP_MINIMUM so that only the max value needs // to be changed to effect the entire system. This will require a change in the ENUM so that we can use a loop to // modify the remaining values. - APBPConstants[AP_MAXIMUM] = iniReader.ReadInteger("APConstants","AP_MAXIMUM",100); + APBPConstants[AP_MAXIMUM] = iniReader.ReadInteger("APConstants","AP_MAXIMUM",100, 25, 250); //CHRISL: Once we've loaded the AP_MAXIMUM value, we can use it to modifiy all the remaining values - APBPConstants[AP_MINIMUM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_MINIMUM",40),40); + APBPConstants[AP_MINIMUM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_MINIMUM",40, 10, 100),40); APBPConstants[AP_MONSTER_MAXIMUM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_MONSTER_MAXIMUM",160),160); APBPConstants[AP_VEHICLE_MAXIMUM] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_VEHICLE_MAXIMUM",200),200); APBPConstants[MAX_AP_CARRIED] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","MAX_AP_CARRIED",20),20); @@ -1545,12 +2046,12 @@ void LoadGameAPBPConstants() APBPConstants[BP_GET_WOUNDED] = iniReader.ReadInteger("BPConstants","BP_GET_WOUNDED",50); APBPConstants[BP_FALL_DOWN] = iniReader.ReadInteger("BPConstants","BP_FALL_DOWN",250); APBPConstants[BP_OPEN_DOOR] = iniReader.ReadInteger("BPConstants","BP_OPEN_DOOR",30); - APBPConstants[BP_PICKLOCK] = iniReader.ReadInteger("BPConstants","BP_PICKLOCK",-250); - APBPConstants[BP_EXAMINE_DOOR] = iniReader.ReadInteger("BPConstants","BP_EXAMINE_DOOR",-250); + APBPConstants[BP_PICKLOCK] = iniReader.ReadInteger("BPConstants","BP_PICKLOCK",50); + APBPConstants[BP_EXAMINE_DOOR] = iniReader.ReadInteger("BPConstants","BP_EXAMINE_DOOR",20); APBPConstants[BP_BOOT_DOOR] = iniReader.ReadInteger("BPConstants","BP_BOOT_DOOR",200); APBPConstants[BP_USE_CROWBAR] = iniReader.ReadInteger("BPConstants","BP_USE_CROWBAR",350); APBPConstants[BP_UNLOCK_DOOR] = iniReader.ReadInteger("BPConstants","BP_UNLOCK_DOOR",50); - APBPConstants[BP_EXPLODE_DOOR] = iniReader.ReadInteger("BPConstants","BP_EXPLODE_DOOR",-250); + APBPConstants[BP_EXPLODE_DOOR] = iniReader.ReadInteger("BPConstants","BP_EXPLODE_DOOR",40); APBPConstants[BP_UNTRAP_DOOR] = iniReader.ReadInteger("BPConstants","BP_UNTRAP_DOOR",150); APBPConstants[BP_LOCK_DOOR] = iniReader.ReadInteger("BPConstants","BP_LOCK_DOOR",50); APBPConstants[BP_USEWIRECUTTERS] = iniReader.ReadInteger("BPConstants","BP_USEWIRECUTTERS",200); @@ -1561,11 +2062,144 @@ void LoadGameAPBPConstants() APBPConstants[BP_BACK_PACK] = iniReader.ReadInteger("APConstants","BP_JUMP_OVER",50); APBPConstants[BP_WORK_ZIPPER] = iniReader.ReadInteger("APConstants","BP_WORK_ZIPPER",250); APBPConstants[BP_UNJAM] = iniReader.ReadInteger("APConstants","BP_WORK_ZIPPER",0); + + APBPConstants[AP_JUMPWINDOW] = DynamicAdjustAPConstants(iniReader.ReadInteger("APConstants","AP_JUMPWINDOW",40),40); SetupMaxActionPointsAnimation(); #undef ReadInteger } +// HEADROCK HAM 4: Read the various coefficients for the new CTH and Shooting systems from an INI file. +void LoadCTHConstants() +{ + + //Kaiden: Setting Ja2_Options.ini file to be read + CIniReader iniReader(CTH_COEFFICIENTS_FILE); + + gGameCTHConstants.NORMAL_SHOOTING_DISTANCE = iniReader.ReadInteger("General","NORMAL_SHOOTING_DISTANCE",100, 1, 10000); + gGameCTHConstants.DEGREES_MAXIMUM_APERTURE = iniReader.ReadFloat("General", "DEGREES_MAXIMUM_APERTURE", 15.0, 0.0, 22.5); + gGameCTHConstants.GRAVITY_COEFFICIENT = iniReader.ReadFloat("General", "GRAVITY_COEFFICIENT", 2.0, 0.001f, 100.0); + gGameCTHConstants.VERTICAL_BIAS = iniReader.ReadFloat("General", "VERTICAL_BIAS", 1.0f, 0.01f, 2.0f); + gGameCTHConstants.SCOPE_RANGE_MULTIPLIER = iniReader.ReadFloat("General", "SCOPE_RANGE_MULTIPLIER", 0.7f, 0.5f, 1.5f); + + //////////////////////////////////////////////////////////// + // Coefficients for factors affecting Base CTH + //////////////////////////////////////////////////////////// + + gGameCTHConstants.BASE_EXP = iniReader.ReadFloat("Base CTH","BASE_EXP",3.0, 0.0, 100.0); + gGameCTHConstants.BASE_MARKS = iniReader.ReadFloat("Base CTH","BASE_MARKS",1.0, 0.0, 100.0); + gGameCTHConstants.BASE_WIS = iniReader.ReadFloat("Base CTH","BASE_WIS",1.0, 0.0, 100.0); + gGameCTHConstants.BASE_DEX = iniReader.ReadFloat("Base CTH","BASE_DEX",1.0, 0.0, 100.0); + + gGameCTHConstants.BASE_LOW_MORALE = iniReader.ReadFloat("Base CTH","BASE_LOW_MORALE",-1.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_HIGH_MORALE = iniReader.ReadFloat("Base CTH","BASE_HIGH_MORALE",2.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_PSYCHO = iniReader.ReadFloat("Base CTH","BASE_PSYCHO",-3.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_SHOOTING_UPWARDS = iniReader.ReadFloat("Base CTH","BASE_SHOOTING_UPWARDS",-15.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_INJURY = iniReader.ReadFloat("Base CTH","BASE_INJURY",-30.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DRUNK[0] = iniReader.ReadFloat("Base CTH","BASE_DRUNK_TIPSY",-5.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DRUNK[1] = iniReader.ReadFloat("Base CTH","BASE_DRUNK",-20.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DRUNK[2] = iniReader.ReadFloat("Base CTH","BASE_DRUNK_WASTED",-50.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DRUNK[3] = iniReader.ReadFloat("Base CTH","BASE_DRUNK_HUNGOVER",-10.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_FATIGUE = iniReader.ReadFloat("Base CTH","BASE_FATIGUE",-15.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_SAME_TARGET = iniReader.ReadFloat("Base CTH","BASE_SAME_TARGET",5.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_GASSED = iniReader.ReadFloat("Base CTH","BASE_GASSED",-15.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_BEING_BANDAGED = iniReader.ReadFloat("Base CTH","BASE_BEING_BANDAGED",-5.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_SHOCK = iniReader.ReadFloat("Base CTH","BASE_SHOCK",-150.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_AGILE_TARGET = iniReader.ReadFloat("Base CTH","BASE_AGILE_TARGET",-5.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_TARGET_INVISIBLE = iniReader.ReadFloat("Base CTH","BASE_TARGET_INVISIBLE",-100.0, -1000.0, 1000.0); + + gGameCTHConstants.BASE_DRAW_COST = iniReader.ReadFloat("Base CTH","BASE_DRAW_COST",-2.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_TWO_GUNS = iniReader.ReadFloat("Base CTH","BASE_TWO_GUNS",3.5, -1000.0, 1000.0); + gGameCTHConstants.BASE_ONE_HANDED = iniReader.ReadFloat("Base CTH","BASE_ONE_HANDED",2.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_CROUCHING_STANCE = iniReader.ReadFloat("Base CTH","BASE_CROUCHING_STANCE",2.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_PRONE_STANCE = iniReader.ReadFloat("Base CTH","BASE_PRONE_STANCE",3.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_HEAVY_WEAPON = iniReader.ReadFloat("Base CTH","BASE_HEAVY_WEAPON",2.0, -1000.0, 1000.0); + + gGameCTHConstants.BASE_DIFFICULTY[0] = -100.0; + gGameCTHConstants.BASE_DIFFICULTY[1] = iniReader.ReadFloat("Base CTH","BASE_DIFFICULTY_NOVICE",-30.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DIFFICULTY[2] = iniReader.ReadFloat("Base CTH","BASE_DIFFICULTY_EXPERIENCED",0.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DIFFICULTY[3] = iniReader.ReadFloat("Base CTH","BASE_DIFFICULTY_EXPERT",20.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DIFFICULTY[4] = iniReader.ReadFloat("Base CTH","BASE_DIFFICULTY_INSANE",50.0, -1000.0, 1000.0); + gGameCTHConstants.BASE_DIFFICULTY[5] = 100.0; + + //////////////////////////////////////////////////////////// + // Coefficients for factors affecting Aiming CTH + //////////////////////////////////////////////////////////// + + gGameCTHConstants.AIM_EXP = iniReader.ReadFloat("Aiming CTH","AIM_EXP",1.0, 0.0, 100.0); + gGameCTHConstants.AIM_MARKS = iniReader.ReadFloat("Aiming CTH","AIM_MARKS",3.0, 0.0, 100.0); + gGameCTHConstants.AIM_WIS = iniReader.ReadFloat("Aiming CTH","AIM_WIS",1.0, 0.0, 100.0); + gGameCTHConstants.AIM_DEX = iniReader.ReadFloat("Aiming CTH","AIM_DEX",2.0, 0.0, 100.0); + + gGameCTHConstants.AIM_TOO_CLOSE_SCOPE = iniReader.ReadFloat("Aiming CTH","AIM_TOO_CLOSE_SCOPE",-4.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_GUN_CONDITION = iniReader.ReadFloat("Aiming CTH","AIM_GUN_CONDITION",-2.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_LOW_MORALE = iniReader.ReadFloat("Aiming CTH","AIM_LOW_MORALE",-2.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_HIGH_MORALE = iniReader.ReadFloat("Aiming CTH","AIM_HIGH_MORALE",1.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_PSYCHO = iniReader.ReadFloat("Aiming CTH","AIM_PSYCHO",-5.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_VISIBILITY = iniReader.ReadFloat("Aiming CTH","AIM_VISIBILITY",-1.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_SHOOTING_UPWARDS = iniReader.ReadFloat("Aiming CTH","AIM_SHOOTING_UPWARDS",-20.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_INJURY = iniReader.ReadFloat("Aiming CTH","AIM_INJURY",-60.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DRUNK[0] = iniReader.ReadFloat("Aiming CTH","AIM_DRUNK_TIPSY",-10.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DRUNK[1] = iniReader.ReadFloat("Aiming CTH","AIM_DRUNK",-40.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DRUNK[2] = iniReader.ReadFloat("Aiming CTH","AIM_DRUNK_WASTED",-90.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DRUNK[3] = iniReader.ReadFloat("Aiming CTH","AIM_DRUNK_HUNGOVER",-15.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_FATIGUE = iniReader.ReadFloat("Aiming CTH","AIM_FATIGUE",-40.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_GASSED = iniReader.ReadFloat("Aiming CTH","AIM_GASSED",-80.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_BEING_BANDAGED = iniReader.ReadFloat("Aiming CTH","AIM_BEING_BANDAGED",-20.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_SHOCK = iniReader.ReadFloat("Aiming CTH","AIM_SHOCK",-150.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_TARGET_INVISIBLE = iniReader.ReadFloat("Aiming CTH","AIM_TARGET_INVISIBLE",-50.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_SNIPER_SKILL = iniReader.ReadFloat("Aiming CTH","AIM_SNIPER_SKILL",25.0, -100.0, 100.0); + + gGameCTHConstants.AIM_DRAW_COST = iniReader.ReadFloat("Aiming CTH","AIM_DRAW_COST",-2.5, -1000.0, 1000.0); + gGameCTHConstants.AIM_STANDING_STANCE = iniReader.ReadFloat("Aiming CTH","AIM_STANDING_STANCE",2.5, -1000.0, 1000.0); + gGameCTHConstants.AIM_CROUCHING_STANCE = iniReader.ReadFloat("Aiming CTH","AIM_CROUCHING_STANCE",1.5, -1000.0, 1000.0); + gGameCTHConstants.AIM_PRONE_STANCE = iniReader.ReadFloat("Aiming CTH","AIM_PRONE_STANCE",1.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_TWO_GUNS = iniReader.ReadFloat("Aiming CTH","AIM_TWO_GUNS",4.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_ONE_HANDED = iniReader.ReadFloat("Aiming CTH","AIM_ONE_HANDED",2.5, -1000.0, 1000.0); + gGameCTHConstants.AIM_HEAVY_WEAPON = iniReader.ReadFloat("Aiming CTH","AIM_HEAVY_WEAPON",2.0, -1000.0, 1000.0); + + gGameCTHConstants.AIM_DIFFICULTY[0] = -100.0; + gGameCTHConstants.AIM_DIFFICULTY[1] = iniReader.ReadFloat("Aiming CTH","AIM_DIFFICULTY_NOVICE",-30.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DIFFICULTY[2] = iniReader.ReadFloat("Aiming CTH","AIM_DIFFICULTY_EXPERIENCED",0.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DIFFICULTY[3] = iniReader.ReadFloat("Aiming CTH","AIM_DIFFICULTY_EXPERT",20.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DIFFICULTY[4] = iniReader.ReadFloat("Aiming CTH","AIM_DIFFICULTY_INSANE",50.0, -1000.0, 1000.0); + gGameCTHConstants.AIM_DIFFICULTY[5] = 100.0; + + //////////////////////////////////////////////////////////// + // Coefficients for factors affecting the Shooting Mechanism + //////////////////////////////////////////////////////////// + + gGameCTHConstants.MOVEMENT_MRK = iniReader.ReadFloat("Shooting Mechanism","MOVEMENT_MRK",3.0, 0.0, 100.0); + gGameCTHConstants.MOVEMENT_WIS = iniReader.ReadFloat("Shooting Mechanism","MOVEMENT_WIS",2.0, 0.0, 100.0); + gGameCTHConstants.MOVEMENT_DEX = iniReader.ReadFloat("Shooting Mechanism","MOVEMENT_DEX",1.0, 0.0, 100.0); + gGameCTHConstants.MOVEMENT_EXP_LEVEL = iniReader.ReadFloat("Shooting Mechanism","MOVEMENT_EXP_LEVEL",2.0, 0.0, 100.0); + gGameCTHConstants.MOVEMENT_TRACKING_DIFFICULTY = iniReader.ReadInteger("Shooting Mechanism","MOVEMENT_TRACKING_DIFFICULTY",20, 0, 1000); + gGameCTHConstants.MOVEMENT_PENALTY_PER_TILE = iniReader.ReadFloat("Shooting Mechanism","MOVEMENT_PENALTY_PER_TILE",1.0, 0.0, 10.0); + + gGameCTHConstants.PRE_RECOIL_WIS = iniReader.ReadFloat("Shooting Mechanism","PRE_RECOIL_WIS",2.0, 0.0, 100.0); + gGameCTHConstants.PRE_RECOIL_EXP_LEVEL = iniReader.ReadFloat("Shooting Mechanism","PRE_RECOIL_EXP_LEVEL",3.0, 0.0, 100.0); + gGameCTHConstants.PRE_RECOIL_AUTO_WEAPONS_SKILL = iniReader.ReadFloat("Shooting Mechanism","PRE_RECOIL_AUTO_WEAPONS_SKILL",2.0, 1.0, 100.0); + + gGameCTHConstants.RECOIL_MAX_COUNTER_STR = iniReader.ReadFloat("Shooting Mechanism","RECOIL_MAX_COUNTER_STR",3.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_MAX_COUNTER_AGI = iniReader.ReadFloat("Shooting Mechanism","RECOIL_MAX_COUNTER_AGI",1.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_MAX_COUNTER_EXP_LEVEL = iniReader.ReadFloat("Shooting Mechanism","RECOIL_MAX_COUNTER_EXP_LEVEL",1.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_MAX_COUNTER_FORCE = iniReader.ReadFloat("Shooting Mechanism","RECOIL_MAX_COUNTER_FORCE",5.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_MIN_ERROR = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_MIN",1.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_DEX = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_DEX",3.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_WIS = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_WIS",1.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_AGI = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_AGI",1.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_EXP_LEVEL = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_EXP_LEVEL",2.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_AUTO_WEAPONS_DIVISOR = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_AUTO_WEAPONS_DIVISOR",2.0, 1.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_TRACER_BONUS = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_ACCURACY_TRACER_BONUS",10.0, -1000.0, 1000.0); + gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AGI = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_FREQUENCY_AGI",3.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_EXP_LEVEL = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_FREQUENCY_EXP_LEVEL",2.0, 0.0, 100.0); + gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AUTO_WEAPONS_DIVISOR = iniReader.ReadFloat("Shooting Mechanism","RECOIL_COUNTER_FREQUENCY_AUTO_WEAPONS_DIVISOR",2.0, -1000.0, 1000.0); + + gGameCTHConstants.MAX_BULLET_DEV = iniReader.ReadFloat("Shooting Mechanism","MAX_BULLET_DEV ",10.0, -1000.0, 1000.0); + + +} + void FreeGameExternalOptions() { if (gGameExternalOptions.iaIMPSlots != NULL) // OJW - 20081129 - Fix memory leak when calling LoadGameExternalOptions twice diff --git a/GameSettings.h b/GameSettings.h index 30a4bdb2..be92359b 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -38,9 +38,9 @@ enum //Madd: TOPTION_GL_BURST_CURSOR, - TOPTION_DROP_ALL, + TOPTION_ALLOW_TAUNTS, // changed from drop all - SANDRO TOPTION_GL_HIGH_ANGLE, - TOPTION_AIM_LEVEL_RESTRICTION, + TOPTION_ALLOW_REAL_TIME_SNEAK, // changed from aim levels restriction - SANDRO //lalien TOPTION_SPACE_SELECTS_NEXT_SQUAD, @@ -49,7 +49,7 @@ enum TOPTION_TRACERS_FOR_SINGLE_FIRE, TOPTION_RAIN_SOUND, TOPTION_ALLOW_CROWS, - TOPTION_ALLOW_SOLDIER_TOOLTIPS, // Changed from TOPTION_USE_RANDOM_PERSONALITY - SANDRO + TOPTION_ALLOW_SOLDIER_TOOLTIPS, TOPTION_USE_AUTO_SAVE, TOPTION_SILENT_SKYRIDER, TOPTION_LOW_CPU_USAGE, @@ -61,6 +61,15 @@ enum // HEADROCK HAM 3.6: TOPTION_STAT_PROGRESS_BARS, + // HEADROCK HAM 4: + TOPTION_REPORT_MISS_MARGIN, + + // HEADROCK HAM 4: + TOPTION_ALT_MAP_COLOR, + + // WANNE: Moved alternate bullets graphics (tracers) to options + TOPTION_ALTERNATE_BULLET_GRAPHICS, + // arynn: Debug/Cheat TOPTION_CHEAT_MODE_OPTIONS_HEADER, TOPTION_FORCE_BOBBY_RAY_SHIPMENTS, // force all pending Bobby Ray shipments @@ -113,7 +122,13 @@ typedef struct enum { INVENTORY_OLD = 0, - INVENTORY_NEW = 1 + INVENTORY_NEW = 1, +}; + +enum +{ + ATTACHMENT_OLD = 0, + ATTACHMENT_NEW = 1, }; @@ -144,6 +159,16 @@ enum BR_AWESOME = 10, }; +// Added by SANDRO +enum +{ + ITEM_PROGRESS_VERY_SLOW = 0, + ITEM_PROGRESS_SLOW, + ITEM_PROGRESS_NORMAL, + ITEM_PROGRESS_FAST, + ITEM_PROGRESS_VERY_FAST, +}; + typedef struct { BOOLEAN fGunNut; @@ -154,11 +179,21 @@ typedef struct BOOLEAN fIronManMode; UINT8 ubBobbyRay; UINT8 ubInventorySystem; - UINT8 ubFiller[6]; + UINT8 ubAttachmentSystem; + // SANDRO - added variables + UINT8 ubMaxIMPCharacters; + BOOLEAN fNewTraitSystem; + BOOLEAN fEnableAllTerrorists; + BOOLEAN fEnemiesDropAllItems; + UINT8 ubProgressSpeedOfItemsChoices; + BOOLEAN fEnableAllWeaponCaches; + //UINT8 ubFiller[]; } GAME_OPTIONS; bool UsingNewInventorySystem(); +bool UsingNewAttachmentSystem(); +bool UsingNewCTHSystem(); BOOLEAN IsNIVModeValid(bool checkRes = true); // Snap: Options read from an INI file in the default of custom Data directory @@ -178,19 +213,20 @@ typedef struct // WDS: Allow flexible numbers of IMPs of each sex INT32 iIMPMaleCharacterCount; // Count of how many there are INT32 iIMPFemaleCharacterCount; - INT32 iMaxIMPCharacters; // Limit of how many to allow + //INT32 iMaxIMPCharacters; // Limit of how many to allow // // iaIMPSlots is an array of the slots (in prof.dat) to use for IMPs. // INT32 *iaIMPSlots; + // SANDRO was here - some changes done + INT32 iIMPProfileCost; + BOOLEAN fDynamicIMPProfileCost; INT32 iMinAttribute; INT32 iMaxAttribute; INT32 iImpAttributePoints; INT32 iMaxZeroBonus; - INT32 iStartAttribute; - // These 3 added - SANDRO INT32 iIMPStartingLevelCostMultiplier; INT32 iBonusPointsForDisability; INT32 iBonusPointsPerSkillNotTaken; @@ -225,22 +261,49 @@ typedef struct BOOLEAN fMercDayOne; BOOLEAN fAllMercsAvailable; - - //BOOLEAN fPers_att; - - // These 2 removed - SANDRO - //INT8 iCustomPersonality; - //INT8 iCustomAttitude; + + // tais: Any AIM merc on assignment? + UINT8 fMercsOnAssignment; + // tais: Soldiers wear any armour + UINT8 fSoldiersWearAnyArmour; INT8 iEasyAPBonus; INT8 iExperiencedAPBonus; INT8 iExpertAPBonus; INT8 iInsaneAPBonus; INT8 iPlayerAPBonus; + + //////////////////////////////////// + // added by SANDRO + INT16 sEnemyAdminCtHBonusPercent; + INT16 sEnemyRegularCtHBonusPercent; + INT16 sEnemyEliteCtHBonusPercent; + + INT8 sEnemyAdminDamageResistance; + INT8 sEnemyRegularDamageResistance; + INT8 sEnemyEliteDamageResistance; + + BOOLEAN fAssignTraitsToEnemy; + BOOLEAN fAssignTraitsToMilitia; + INT8 bAssignedTraitsRarity; + + BOOLEAN fCamoRemoving; + BOOLEAN fEnhancedCloseCombatSystem; + + UINT16 usAwardSpecialExpForQuests; + //////////////////////////////////// + // Kaiden: Vehicle Inventory change - Added for INI Option BOOLEAN fVehicleInventory; - BOOLEAN fEnableChanceOfEnemyAmbushesOnInsaneDifficult; + /////////////////////////////////////// + // changed/added these - SANDRO + UINT8 sMercsAutoresolveOffenseBonus; + UINT8 sMercsAutoresolveDeffenseBonus; + BOOLEAN fEnableChanceOfEnemyAmbushes; + INT8 bChanceModifierEnemyAmbushes; + UINT8 usSpecialNPCStronger; + /////////////////////////////////////// // System settings UINT8 gubDeadLockDelay; @@ -285,7 +348,22 @@ typedef struct //UINT32 guiMaxMilitiaSquadSize; //UINT32 guiMaxMilitiaSquadSizeBattle; - //BOOLEAN gfAllowSoldierToolTips; // moved to prefereces - SANDRO + // SANDRO - added some variables + INT16 sGreenMilitiaAutoresolveStrength; + INT16 sRegularMilitiaAutoresolveStrength; + INT16 sVeteranMilitiaAutoresolveStrength; + INT8 bGreenMilitiaAPsBonus; + INT8 bRegularMilitiaAPsBonus; + INT8 bVeteranMilitiaAPsBonus; + INT16 sGreenMilitiaCtHBonusPercent; + INT16 sRegularMilitiaCtHBonusPercent; + INT16 sVeteranMilitiaCtHBonusPercent; + INT8 bGreenMilitiaDamageResistance; + INT8 bRegularMilitiaDamageResistance; + INT8 bVeteranMilitiaDamageResistance; + INT8 bGreenMilitiaEquipmentQualityModifier; + INT8 bRegularMilitiaEquipmentQualityModifier; + INT8 bVeteranMilitiaEquipmentQualityModifier; // WDS - Improve Tony's and Devin's inventory like BR's BOOLEAN tonyUsesBRSetting; @@ -335,9 +413,6 @@ typedef struct UINT32 ubGameProgressMinimum; INT32 bGameProgressModifier; - // WDS - Advanced start - //UINT32 ubIMPStartingLevel; // removed - SANDRO - // Event settings UINT32 ubGameProgressStartMadlabQuest; UINT32 ubGameProgressMikeAvailable; @@ -357,6 +432,7 @@ typedef struct INT32 iExplosivesDamageModifier; INT32 iGunDamageModifier; + INT32 iGunRangeModifier; INT32 iMeleeDamageModifier; UINT32 ubEasyEnemyStartingAlertLevel; @@ -414,6 +490,10 @@ typedef struct BOOLEAN gfUseExternalLoadscreens; + //tais: nsgi + BOOLEAN gfUseNewStartingGearInterface; + // DBrot: Seperate Starting items for Experts + BOOLEAN fExpertsGetDifferentChoices; BOOLEAN gfUseAutoSave; //Merc Assignment settings @@ -448,8 +528,9 @@ typedef struct //Misc settings BOOLEAN fAmmoDynamicWeight; //Pulmu BOOLEAN fEnableCrepitus; - BOOLEAN fEnableAllWeaponCaches; - BOOLEAN fEnableAllTerrorists; + // SANDRO was here - removed these two + //BOOLEAN fEnableAllWeaponCaches; + //BOOLEAN fEnableAllTerrorists; BOOLEAN gfRevealItems; BOOLEAN fEnableArmorCoverage; // ShadoWarrior for Captain J's armor coverage @@ -465,6 +546,7 @@ typedef struct BOOLEAN fEnableSoldierTooltipAttitude; BOOLEAN fEnableSoldierTooltipActionPoints; BOOLEAN fEnableSoldierTooltipHealth; + BOOLEAN fEnableSoldierTooltipTraits; // added by SANDRO BOOLEAN fEnableSoldierTooltipHelmet; BOOLEAN fEnableSoldierTooltipVest; BOOLEAN fEnableSoldierTooltipLeggings; @@ -495,8 +577,8 @@ typedef struct // Lesh: slow enemy items choice progress BOOLEAN fSlowProgressForEnemyItemsChoice; -//afp - use bullet tracers -BOOLEAN gbBulletTracer; + //afp - use bullet tracers + BOOLEAN gbBulletTracer; // CHRISL: option to allow Slay to remain as a hired PC BOOLEAN fEnableSlayForever; @@ -510,10 +592,42 @@ BOOLEAN gbBulletTracer; // HEADROCK: Enhanced Item Description Box ON/OFF // WANNE: Changed from BOOLEAN to INT32! INT32 iEnhancedDescriptionBox; + + //WarmSteel - New Attachment System? + BOOLEAN fUseDefaultSlots; + UINT32 usAttachmentDropRate; + INT16 iMaxEnemyAttachments; + //** ddd + //enable ext mouse key + BOOLEAN fExtMouseKeyEnabled; + // for small progress bar + BOOLEAN fSmallSizeProgressbar; + // stamina multiplier (for all weapons eg knife fist gun + INT32 uStaminaHit; + //enable ext mouse key + BOOLEAN bAltAimEnabled; + BOOLEAN bAimedBurstEnabled; + INT16 uAimedBurstPenalty; + BOOLEAN bWeSeeWhatMilitiaSeesAndViceVersa; + BOOLEAN bAllowWearSuppressor; + BOOLEAN bLazyCivilians; + INT16 iChanceSayAnnoyingPhrase; + BOOLEAN bNewTacticalAIBehavior; + FLOAT uShotHeadPenalty; + FLOAT fShotHeadDivisor; + INT16 iPenaltyShootUnSeen; + + FLOAT fOutOfGunRangeOrSight; // WANNE: Always use "prof.dat". BOOLEAN fUseDifficultyBasedProfDat; + // 2Points: Use new repair algorithm + BOOLEAN fAdditionalRepairMode; + + // CHRISL: Skyrider and enemy occupied sectors + UINT8 ubSkyriderHotLZ; + // CPT: Cover System Settings UINT8 ubStealthTraitCoverValue; UINT8 ubStealthEffectiveness; @@ -566,12 +680,26 @@ BOOLEAN gbBulletTracer; // HEADROCK HAM B2.5: Realistic tracers - CTH increased by this amount whenever a tracer is fired. 0 = off. UINT8 ubCTHBumpPerTracer; + // CHRISL: Exeternalize the minimum range at which tracers can improve autofire hit chance + UINT16 ubMinRangeTracerEffect; + // HEADROCK HAM B2.6: Increased aiming costs? BOOLEAN fIncreasedAimingCost; + // added by SANDRO + BOOLEAN fAimLevelRestriction; + // HEADROCK HAM B2.6: Dynamically determine Max-Aiming based also on weapon, bipod, etc? BOOLEAN fDynamicAimingTime; + // allow old behaviour + BOOLEAN fAimLevelsDependOnDistance; + + //WarmSteel - These determine in which group each scope belongs. Needed for dynamic aiming limits. + INT16 sVeryHighPowerScope; + INT16 sHighPowerScope; + INT16 sMediumPowerScope; + // HEADROCK HAM B2.6: Controls how much effect target movement has on aiming FLOAT iMovementEffectOnAiming; @@ -661,6 +789,9 @@ BOOLEAN gbBulletTracer; // HEADROCK HAM 3: If enabled, tooltipping over Bobby Ray's weapons will show a list of possible attachments to those weapons. BOOLEAN fBobbyRayTooltipsShowAttachments; + // CHRISL: Converts the AutoFireToHitBonus value to a percentage for CTH calculations + UINT8 ubFlatAFTHBtoPrecentMultiplier; + // HEADROCK HAM 3.1: Divisor for the AP-to-Ready cost charge on first aiming click, when extra aiming costs are enabled. 0 = No ready-time-based charge. UINT8 ubFirstAimReadyCostDivisor; @@ -706,6 +837,9 @@ BOOLEAN gbBulletTracer; // HEADROCK HAM 3.3: Externalized maximum possible penalty for hitting a moving target. JA2 Default = 30. UINT16 usMaxCTHPenaltyForMovingTarget; + // CHRISL: HAM4-NCTH + BOOLEAN fUseNCTH; + // HEADROCK HAM 3.3: Increases tolerance while moving. UINT8 ubTilesMovedPerBonusTolerancePoint; @@ -800,15 +934,388 @@ BOOLEAN gbBulletTracer; // HEADROCK HAM 3.6: If activated, the game does not switch focus to a merc who spots an enemy in real-time mode. This fixes issues with Real-Time Sneak. BOOLEAN fNoAutoFocusChangeInRealtimeSneak; + UINT8 ubEarlyRebelsRecruitment[4]; // early recruitment of Miguel and Carlos + // silversurfer: don't play quote when merc spots a mine? TRUE = shut up! FALSE = tell me that you found a mine! + BOOLEAN fMineSpottedNoTalk; + // The_Bob - real time sneaking code 01/06/09 // Suport disabling/silencing real time sneaking via external .ini file - BOOLEAN fAllowRealTimeSneak; + //BOOLEAN fAllowRealTimeSneak; // SANDRO - moved to preferences BOOLEAN fQuietRealTimeSneak; -//dnl ch51 081009 JA2 Debug Settings - BOOLEAN fEnableInventoryPoolQ; + //legion by Jazz + BOOLEAN fCanJumpThroughWindows; + BOOLEAN fCanClimbOnWalls; + + //legion by Jazz + BOOLEAN fIndividualHiddenPersonNames; + + //SAveGame Slot by Jazz + BOOLEAN fSaveGameSlot; + + //dnl ch51 081009 JA2 Debug Settings + BOOLEAN fEnableInventoryPoolQ; + + //legion by Jazz + BOOLEAN fShowTacticalFaceGear; //legion 2 + BOOLEAN fShowTacticalFaceIcons; //legion 2 + INT8 bTacticalFaceIconStyle; + + //Enemy Names Group Legion 2 by Jazz + BOOLEAN fEnemyNames; + + //Civ Names Group Legion 2 by Jazz + BOOLEAN fCivGroupName; + + //Enemy Rank Legion 2 by Jazz + BOOLEAN fEnemyRank; + + BOOLEAN fShowCamouflageFaces; + + FLOAT gMercLevelUpSalaryIncreasePercentage; + + UINT8 ubChanceTonyAvailable; // silversurfer/SANDRO + + BOOLEAN fStandUpAfterBattle; } GAME_EXTERNAL_OPTIONS; +typedef struct +{ + UINT8 ubMaxNumberOfTraits; + UINT8 ubNumberOfMajorTraitsAllowed; + + // GENERIC SETTINGS + INT8 bCtHModifierAssaultRifles; + INT8 bCtHModifierSniperRifles; + INT8 bCtHModifierRifles; + INT8 bCtHModifierSMGs; + INT8 bCtHModifierLMGs; + INT8 bCtHModifierShotguns; + INT8 bCtHModifierPistols; + INT8 bCtHModifierMachinePistols; + INT8 bCtHModifierRocketLaunchers; + INT8 bCtHModifierGrenadeLaunchers; + INT16 sCtHModifierMortar; + INT8 bCtHModifierThrowingKnives; + INT8 bCtHModifierThrowingGrenades; + INT8 bCtHModifierHtHAttack; + INT8 bModifierDodgeHtHChance; + INT8 bCtHModifierKnifeAttack; + INT8 bModifierDodgeKnifeChance; + INT8 bCtHModifierRobot; + UINT8 ubCtHPenaltyDualShot; + INT8 bPercentModifierHtHBreathLoss; + INT8 bPercentModifierBladesBreathLoss; + INT8 bPercentModifierBluntBreathLoss; + UINT8 ubModifierForAPsAddedOnAimedPunches; + UINT8 ubModifierForAPsAddedOnAimedBladedAttackes; + INT8 bSpeedModifierDoctoring; + INT8 bSpeedModifierBandaging; + INT8 bSpeedModifierRepairing; + INT8 bSpeedModifierTrainingMilitia; + INT8 bSpeedModifierTeachingOthers; + INT8 bCheckModifierLockpicking; + INT8 bCheckModifierAttachDetonators; + INT8 bCheckModifierSetExplosives; + INT8 bCheckModifierDisarmExplosiveTraps; + INT8 bCheckModifierDisarmElectronicTraps; + INT8 bCheckModifierAttachSpecialItems; + INT8 bTanksDamageResistanceModifier; + UINT8 ubDamageNeededToLoseStats; + + // AUTO WEAPONS + UINT8 ubAWBonusCtHAssaultRifles; + UINT8 ubAWBonusCtHSMGs; + UINT8 ubAWBonusCtHLMGs; + UINT8 ubAWAutoFirePenaltyReduction; + UINT8 ubAWUnwantedBulletsReduction; + UINT8 ubAWFiringSpeedBonusLMGs; + UINT8 ubAWPercentReadyLMGReduction; + + // HEAVY WEAPONS + UINT8 ubHWGrenadeLaunchersAPsReduction; + UINT8 ubHWRocketLaunchersAPsReduction; + UINT8 ubHWBonusCtHGrenadeLaunchers; + UINT8 ubHWBonusCtHRocketLaunchers; + UINT8 ubHWMortarAPsReduction; + UINT8 ubHWMortarCtHPenaltyReduction; + UINT8 ubHWDamageTanksBonusPercent; + UINT8 ubHWDamageBonusPercentForHW; + + // SNIPER + UINT8 ubSNBonusCtHRifles; + UINT8 ubSNBonusCtHSniperRifles; + UINT8 ubSNEffRangeToTargetReduction; + UINT8 ubSNAimingBonusPerClick; + UINT8 ubSNDamageBonusPerClick; + UINT8 ubSNDamageBonusFromNumClicks; + UINT8 ubSNChamberRoundAPsReduction; + UINT8 ubSNAimClicksAdded; + + // RANGER + UINT8 ubRABonusCtHRifles; + UINT8 ubRABonusCtHShotguns; + UINT8 ubRAPumpShotgunsAPsReduction; + UINT8 ubRAGroupTimeSpentForTravellingFoot; + UINT8 ubRAGroupTimeSpentForTravellingVehicle; + UINT8 ubRAMaxBonusesToTravelSpeed; + UINT8 ubRABreathForTravellingReduction; + UINT8 ubRAWeatherPenaltiesReduction; + //UINT8 ubRACamoEffectivenessBonus; + UINT8 ubRACamoWornountSpeedReduction; + + // GUNSLINGER + UINT8 ubGSFiringSpeedBonusPistols; + UINT8 ubGSEffectiveRangeBonusPistols; + UINT8 ubGSBonusCtHPistols; + UINT8 ubGSBonusCtHMachinePistols; + UINT8 ubGSCtHMPExcludeAuto; + UINT8 ubGSAimingBonusPerClick; + UINT8 ubGSPercentReadyPistolsReduction; + UINT8 ubGSRealoadSpeedHandgunsBonus; + UINT8 ubGSAimClicksAdded; + + // MARTIAL ARTS + UINT8 ubMABonusCtHBareHands; + UINT8 ubMABonusCtHBrassKnuckles; + UINT8 ubMAPunchAPsReduction; + UINT8 ubMABonusDamageHandToHand; + UINT8 ubMABonusBreathDamageHandToHand; + UINT16 usMALostBreathRegainPenalty; + UINT16 usMAAimedPunchDamageBonus; + INT8 bMAAimedPunchCtHModifier; + UINT8 ubMAChanceToDodgeHtH; + UINT8 ubMAOnTopCTDHtHBareHanded; + UINT8 ubMAOnTopCTDHtHBrassKnuckles; + UINT8 ubMAChanceToDodgeMelee; + UINT8 ubMAReducedAPsToSteal; + UINT8 ubMAAPsChangeStanceReduction; + UINT8 ubMAApsTurnAroundReduction; + UINT8 ubMAAPsClimbOrJumpReduction; + UINT8 ubMAChanceToCkickDoors; + BOOLEAN fPermitExtraAnimationsOnlyToMA; + + // SQUADLEADER + UINT16 usSLRadiusNormal; + UINT16 usSLRadiusExtendedEar; + UINT8 ubSLMaxBonuses; + UINT8 ubSLBonusAPsPercent; + UINT8 ubSLEffectiveLevelInRadius; + UINT8 ubSLEffectiveLevelAsStandby; + UINT8 ubSLOverallSuppresionBonusPercent; + UINT8 ubSLMoraleGainBonus; + UINT8 ubSLMoraleLossReduction; + UINT8 ubSLFearResistance; + UINT8 ubSLDeathMoralelossMultiplier; + + // TECHNICIAN + UINT16 usTERepairSpeedBonus; + UINT16 usTELockpickingBonus; + UINT16 usTEDisarmElTrapBonus; + UINT16 usTEAttachingItemsBonus; + UINT8 ubTEUnjamGunBonus; + UINT8 ubTERepairElectronicsPenaltyReduction; + UINT8 ubTEChanceToDetectTrapsBonus; + UINT8 ubTECtHControlledRobotBonus; + UINT8 ubTERepairRobotPenaltyReduction; + UINT8 ubTETraitsNumToRepairRobot; + + // DOCTOR + UINT8 ubDONumberTraitsNeededForSurgery; + UINT8 ubDOSurgeryHealPercentBase; + UINT8 ubDOSurgeryHealPercentOnTop; + UINT16 usDOSurgeryMedBagConsumption; + UINT16 usDOSurgeryMaxBreathLoss; + UINT16 usDORepairStatsRateBasic; + UINT16 usDORepairStatsRateOnTop; + UINT8 ubDORepStPenaltyIfAlsoHealing; + UINT8 ubDOHealingPenaltyIfAlsoStatRepair; + BOOLEAN fDORepStShouldThrowMessage; + UINT8 ubDOBandagingSpeedPercent; + UINT16 usDODoctorAssignmentBonus; + UINT8 ubDONaturalRegenBonus; + UINT8 ubDOMaxRegenBonuses; + + // AMBIDEXTROUS + UINT8 ubAMPenaltyDoubleReduction; + UINT8 ubAMReloadSpeedMagazines; + UINT8 ubAMReloadSpeedLoose; + UINT8 ubAMPickItemsAPsReduction; + UINT8 ubAMWorkBackpackAPsReduction; + UINT8 ubAMHandleDoorsAPsReduction; + UINT8 ubAMHandleBombsAPsReduction; + UINT8 ubAMAttachingItemsAPsReduction; + + // MELEE + UINT8 ubMEBladesAPsReduction; + UINT8 ubMECtHBladesBonus; + UINT8 ubMECtHBluntBonus; + UINT8 ubMEDamageBonusBlades; + UINT8 ubMEDamageBonusBlunt; + UINT16 usMEAimedMeleeAttackDamageBonus; + UINT8 ubMEDodgeBladesBonus; + UINT8 ubMECtDBladesOnTopWithBladeInHands; + UINT8 ubMEDodgeBluntBonus; + UINT8 ubMECtDBluntOnTopWithBladeInHands; + + // THROWING + UINT8 ubTHBladesAPsReduction; + UINT8 ubTHBladesMaxRange; + UINT8 ubTHBladesCtHBonus; + UINT8 ubTHBladesCtHBonusPerClick; + UINT8 ubTHBladesDamageBonus; + UINT8 ubTHBladesDamageBonusPerClick; + UINT8 ubTHBladesSilentCriticalHitChance; + UINT8 ubTHBladesCriticalHitMultiplierBonus; + UINT8 ubTHBladesAimClicksAdded; + + // NIGHT OPS + UINT8 ubNOeSightRangeBonusInDark; + UINT8 ubNOHearingRangeBonus; + UINT8 ubNOHearingRangeBonusInDark; + UINT8 ubNOIterruptsBonusInDark; + UINT8 ubNONeedForSleepReduction; + + // STEALTHY + UINT8 ubSTStealthModeSpeedBonus; + UINT8 ubSTBonusToMoveQuietly; + UINT8 ubSTStealthBonus; + UINT8 ubSTStealthPenaltyForMovingReduction; + + // ATHLETICS + UINT8 ubATAPsMovementReduction; + UINT8 ubATBPsMovementReduction; + + // BODYBUILDING + UINT8 ubBBDamageResistance; + UINT8 ubBBCarryWeightBonus; + UINT8 ubBBBreathLossForHtHImpactReduction; + UINT16 usBBIncreasedNeededDamageToFallDown; + + // DEMOLITIONS + UINT8 ubDEAPsNeededToThrowGrenadesReduction; + UINT8 ubDEMaxRangeToThrowGrenades; + UINT8 ubDECtHWhenThrowingGrenades; + UINT8 ubDEDamageOfBombsAndMines; + UINT8 ubDEAttachDetonatorCheckBonus; + UINT8 ubDEPlantAndRemoveBombCheckBonus; + UINT8 ubDEPlacedBombLevelBonus; + UINT8 ubDEShapedChargeDamageMultiplier; + + // TEACHING + UINT8 ubTGBonusToTrainMilitia; + UINT8 ubTGEffectiveLDRToTrainMilitia; + UINT8 ubTGBonusToTeachOtherMercs; + UINT8 ubTGEffectiveSkillValueForTeaching; + UINT8 ubTGBonusOnPractising; + + // SCOUTING + UINT8 ubSCSightRangebonusWithScopes; + UINT16 usSCSightRangebonusWithBinoculars; + UINT8 ubSCTunnelVisionReducedWithBinoculars; + BOOLEAN fSCCanDetectEnemyPresenseAround; + BOOLEAN fSCCanDetermineEnemyNumbersAround; + BOOLEAN fSCDetectionInDiagonalSectors; + BOOLEAN fSCPreventsTheEnemyToAmbushMercs; + BOOLEAN fSCPreventsBloodcatsAmbushes; + BOOLEAN fSCThrowMessageIfAmbushPrevented; + +} SKILL_TRAIT_VALUES; + +// HEADROCK HAM 4: Constants used as coefficients by the various parts of the new CTH system. +typedef struct +{ + UINT32 NORMAL_SHOOTING_DISTANCE; // Distance at which 1x magnification is 100% effective. This is a major component of the entire shooting mechanism. + FLOAT DEGREES_MAXIMUM_APERTURE; // Maximum possible aperture for a 100% muzzle sway shot. Decrease to make all shots more accurate. + FLOAT GRAVITY_COEFFICIENT; // Changes the way gravity works in the game. Higher values mean bullets don't drop as quickly after reaching max range. + FLOAT VERTICAL_BIAS; // This float can be used to reduce the chance of missing too far upwards or downwards (compared to left/right). + FLOAT SCOPE_RANGE_MULTIPLIER; // Adjusts the minimum effective range of scopes + + FLOAT BASE_EXP; // Importance of Experience for BASE CTH + FLOAT BASE_MARKS; // Importance of Marksmanship for BASE CTH + FLOAT BASE_WIS; // Importance of Wisdom for BASE CTH + FLOAT BASE_DEX; // Importance of Dexterity for BASE CTH + + FLOAT BASE_LOW_MORALE; // Applied gradually when morale is below 50. + FLOAT BASE_HIGH_MORALE; // Applied gradually when morale is above 50. + FLOAT BASE_PSYCHO; // Applied for each level of PSYCHO trait + FLOAT BASE_SHOOTING_UPWARDS; // Applied gradually for shooting at a higher target. Decreases with distance. + FLOAT BASE_INJURY; // Applied gradually for injuries + FLOAT BASE_DRUNK[4]; // Applied for drunkness levels + FLOAT BASE_FATIGUE; // Applied gradually for fatigue + FLOAT BASE_SAME_TARGET; // Applied for shooting at the same target again + FLOAT BASE_GASSED; // Applied for shooting while breathing gas + FLOAT BASE_BEING_BANDAGED; // Applied for shooting while being bandaged + FLOAT BASE_SHOCK; // Applied gradually for shock points + FLOAT BASE_AGILE_TARGET; // Applied gradually for agile or experienced target + FLOAT BASE_TARGET_INVISIBLE; // Applied for shooting at a target you can't see + FLOAT BASE_DRAW_COST; // Applied per 1 AP of the weapon's Ready Cost, under 100AP. + FLOAT BASE_TWO_GUNS; // Gun Difficulty Multiplier for shooting two guns + FLOAT BASE_ONE_HANDED; // Gun Difficulty Multiplier for shooting a pistol with one hand. + FLOAT BASE_CROUCHING_STANCE; // Gun Difficulty Multiplier for shooting from a crouched stance + FLOAT BASE_PRONE_STANCE; // Gun Difficulty Multiplier for shooting from a prone stance + FLOAT BASE_HEAVY_WEAPON; // Gun Difficulty Multiplier for shooting a launcher + FLOAT BASE_DIFFICULTY[6]; // Applied for game difficulty + + FLOAT AIM_EXP; // Importance of Experience for AIMING CTH + FLOAT AIM_MARKS; // Importance of Marksmanship for AIMING CTH + FLOAT AIM_WIS; // Importance of Wisdom for AIMING CTH + FLOAT AIM_DEX; // Importance of Dexterity for AIMING CTH + + FLOAT AIM_TOO_CLOSE_SCOPE; // Applied per tile closer than the scope's minimum range. + FLOAT AIM_GUN_CONDITION; // Applied per point of condition below 50. + FLOAT AIM_LOW_MORALE; // Applied gradually when morale is below 50. + FLOAT AIM_HIGH_MORALE; // Applied gradually when morale is above 50. + FLOAT AIM_PSYCHO; // Applied for each level of PSYCHO trait + FLOAT AIM_VISIBILITY; // Applied for bad visibility + FLOAT AIM_SHOOTING_UPWARDS; // Applied gradually for shooting at a higher target. Decreases with distance. + FLOAT AIM_INJURY; // Applied gradually for injuries + FLOAT AIM_DRUNK[4]; // Applied for drunkness levels + FLOAT AIM_FATIGUE; // Applied gradually for fatigue + FLOAT AIM_GASSED; // Applied for shooting while breathing gas + FLOAT AIM_BEING_BANDAGED; // Applied for shooting while being bandaged + FLOAT AIM_SHOCK; // Applied gradually for shock points + FLOAT AIM_TARGET_INVISIBLE; // Applied for shooting at a target you can't see + FLOAT AIM_SNIPER_SKILL; // Applied as percentage bonus to CTH cap, once per each level. + FLOAT AIM_DRAW_COST; // Applied per 1 AP of the weapon's Ready Cost, under 100AP. + FLOAT AIM_STANDING_STANCE; // Gun Difficulty multiplier for shooting a heavy gun when standing + FLOAT AIM_CROUCHING_STANCE; // Gun Difficulty multiplier for shooting a heavy gun from a crouched stance + FLOAT AIM_PRONE_STANCE; // Gun Difficulty multiplier for shooting a heavy gun when prone, before bipod bonuses + FLOAT AIM_TWO_GUNS; // Gun Difficulty multiplier for shooting two guns (halved for each Ambidextrous level) + FLOAT AIM_ONE_HANDED; // Gun Difficulty multiplier for firing a pistol with one hand. + FLOAT AIM_HEAVY_WEAPON; // Gun Difficulty multiplier for shooting a launcher (halved for each Heavy Weapons level) + FLOAT AIM_DIFFICULTY[6]; // Applied for game difficulty + + FLOAT MOVEMENT_MRK; + FLOAT MOVEMENT_WIS; + FLOAT MOVEMENT_DEX; + FLOAT MOVEMENT_EXP_LEVEL; + UINT32 MOVEMENT_TRACKING_DIFFICULTY; + FLOAT MOVEMENT_PENALTY_PER_TILE; + + FLOAT PRE_RECOIL_WIS; + FLOAT PRE_RECOIL_EXP_LEVEL; + FLOAT PRE_RECOIL_AUTO_WEAPONS_SKILL; + + FLOAT RECOIL_MAX_COUNTER_STR; + FLOAT RECOIL_MAX_COUNTER_AGI; + FLOAT RECOIL_MAX_COUNTER_EXP_LEVEL; + FLOAT RECOIL_MAX_COUNTER_FORCE; + FLOAT RECOIL_COUNTER_ACCURACY_MIN_ERROR; + FLOAT RECOIL_COUNTER_ACCURACY_DEX; + FLOAT RECOIL_COUNTER_ACCURACY_WIS; + FLOAT RECOIL_COUNTER_ACCURACY_AGI; + FLOAT RECOIL_COUNTER_ACCURACY_EXP_LEVEL; + FLOAT RECOIL_COUNTER_ACCURACY_AUTO_WEAPONS_DIVISOR; + FLOAT RECOIL_COUNTER_ACCURACY_TRACER_BONUS; + FLOAT RECOIL_COUNTER_FREQUENCY_AGI; + FLOAT RECOIL_COUNTER_FREQUENCY_EXP_LEVEL; + FLOAT RECOIL_COUNTER_FREQUENCY_AUTO_WEAPONS_DIVISOR; + + FLOAT MAX_BULLET_DEV; + +} CTH_CONSTANTS; + //This structure will contain general Ja2 settings NOT individual game settings. extern GAME_SETTINGS gGameSettings; @@ -818,6 +1325,11 @@ extern GAME_OPTIONS gGameOptions; // Snap: Options read from an INI file in the default of custom Data directory extern GAME_EXTERNAL_OPTIONS gGameExternalOptions; +extern SKILL_TRAIT_VALUES gSkillTraitValues; // SANDRO - added this one + +// HEADROCK HAM 4: CTH constants read from a separate INI file +extern CTH_CONSTANTS gGameCTHConstants; + // WDS - Automatically try to save when an assertion failure occurs extern bool alreadySaving; @@ -825,7 +1337,10 @@ BOOLEAN SaveGameSettings(); BOOLEAN LoadGameSettings(); // Snap: Read options from an INI file in the default of custom Data directory void LoadGameExternalOptions(); +void LoadSkillTraitsExternalSettings(); // SANDRO - added this one void LoadGameAPBPConstants(); +// HEADROCK HAM 4: Read CTH/Shooting coefficients from file +void LoadCTHConstants(); void FreeGameExternalOptions(); void InitGameOptions(); diff --git a/GameVersion.cpp b/GameVersion.cpp index c9b4ab7b..d2e14fc4 100644 --- a/GameVersion.cpp +++ b/GameVersion.cpp @@ -13,13 +13,11 @@ #ifdef JA2EDITOR //MAP EDITOR BUILD VERSION -CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.3356" }; - +CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.4063" }; #elif defined JA2BETAVERSION //BETA/TEST BUILD VERSION -CHAR16 zVersionLabel[256] = { L"Debug v1.13.3356" }; - +CHAR16 zVersionLabel[256] = { L"Debug v1.13.4063" }; #elif defined CRIPPLED_VERSION //RELEASE BUILD VERSION s @@ -28,11 +26,10 @@ CHAR16 zVersionLabel[256] = { L"Beta v. 0.98" }; #else //RELEASE BUILD VERSION - CHAR16 zVersionLabel[256] = { L"Release v1.13.3356" }; - + CHAR16 zVersionLabel[256] = { L"Release v1.13.4063" }; #endif -CHAR8 czVersionNumber[16] = { "Build 10.03.13" }; //YY.MM.DD +CHAR8 czVersionNumber[16] = { "Build 11.01.18" }; //YY.MM.DD CHAR16 zTrackingNumber[16] = { L"Z" }; diff --git a/GameVersion.h b/GameVersion.h index 36a74c70..feed7b3c 100644 --- a/GameVersion.h +++ b/GameVersion.h @@ -20,10 +20,21 @@ extern CHAR16 zTrackingNumber[16]; // // Keeps track of the saved game version. Increment the saved game version whenever // you will invalidate the saved game file -#define SAVE_GAME_VERSION 107 //106 //105 //104 //103 //102 //101 //100 // 99 +#define SAVE_GAME_VERSION 117 //114 //113 //112 //111 //110 //109 //108 //107 //106 //105 //104 //103 //102 //101 //100 // 99 -#define CURRENT_SAVEGAME_DATATYPE_VERSION 107 -#define BIG_MAPS_PROJECT_SAVEGAME_DATATYPE_CHANGE 107 // Before this, we did not had big maps project +#define CURRENT_SAVEGAME_DATATYPE_VERSION 116 + +#define NCTH_DATATYPE_CHANGE 117 // Before this, we did not have HAM 4.0 NCTH +#define NEW_GENERAL_SAVE_INFO_DATA 116 // Before this, we did not have HAM 4.0 general info +#define IMP_TRAIT_EXPERT_ITEMS_CHANGE 115 // Before this, we did not have additional expert items defined in IMPItemChoices.xml +#define LUA_SAVEGAME_CHANGE 114 // Before this, we did not have additional lua script files (e.g: Intro.lua, ...) +#define STOMP12_SAVEGAME_DATATYPE_CHANGE2 113 // Before this, STOMP did not allow to have up to 30 traits +#define NAS_SAVEGAME_DATATYPE_CHANGE 112 // Before this, NAS settings (ON/OFF) was not saved to the savegame +#define STOMP12_SAVEGAME_DATATYPE_CHANGE 111 // Before this, STOMP v1.2 was not included in the source +#define BUGFIX_NPC_DATA_FOR_BIG_MAPS 110 // Before this, we had a bug in the NPC Data for Big Maps (this fix was introduced in the Closed Beta) +#define STRATEGIC_MINES_DATATYPE_CHANGE 109 // Before this, we did not have strategic mines initialization via lua script +#define HIDE_NPC_NAMES_FOR_UNKNOWN_PERSONS 108 // Before this, we did not have hiding of npc names for unknown persons included (by jazz) +#define BIG_MAPS_PROJECT_SAVEGAME_DATATYPE_CHANGE 107 // Before this, we did not have big maps project #define AIRPORT_SAVEGAME_DATATYPE_CHANGE 106 // Before this, we did not have airport externalized #define AP100_SAVEGAME_DATATYPE_CHANGE 105 // Before this, we didn't have the 100AP structure changes #define NIV_SAVEGAME_DATATYPE_CHANGE 102 // Before this, we used the old structure system diff --git a/Init.cpp b/Init.cpp index effbde29..7cfa8040 100644 --- a/Init.cpp +++ b/Init.cpp @@ -60,10 +60,22 @@ #include "Vehicles.h" #include "Multilingual Text Code Generator.h" #include "editscreen.h" + #include "Arms Dealer Init.h" #endif #include "MPXmlTeams.hpp" +#include "Strategic Mines LUA.h" +#include "UndergroundInit.h" +#include "lua_state.h" +#include "Interface.h" +#include "Strategic Town Loyalty.h" +#include "Soldier Profile.h" +#include "aim.h" + +#include "Civ Quotes.h" #include "Sector Summary.h" +#include "LuaInitNPCs.h" + extern INT16 APBPConstants[TOTAL_APBP_VALUES] = {0}; extern INT16 gubMaxActionPoints[28];//MAXBODYTYPES = 28... JUST GETTING IT TO WORK NOW. GOTTHARD 7/2/08 extern BOOLEAN GetCDromDriveLetter( STR8 pString ); @@ -123,34 +135,62 @@ static void AddLanguagePrefix(STR fileName, const STR language) memmove( fileComponent, language, strlen( language) ); } -static void AddLanguagePrefix(STR fileName) +static const STR GetLanguagePrefix() { +#ifdef ENGLISH + return ""; +#endif #ifdef GERMAN - AddLanguagePrefix( fileName, GERMAN_PREFIX); + return GERMAN_PREFIX; #endif #ifdef RUSSIAN - AddLanguagePrefix( fileName, RUSSIAN_PREFIX); + return RUSSIAN_PREFIX; #endif #ifdef DUTCH - AddLanguagePrefix( fileName, DUTCH_PREFIX); + return DUTCH_PREFIX; #endif #ifdef POLISH - AddLanguagePrefix( fileName, POLISH_PREFIX); + return POLISH_PREFIX; #endif #ifdef FRENCH - AddLanguagePrefix( fileName, FRENCH_PREFIX); + return FRENCH_PREFIX; #endif #ifdef ITALIAN - AddLanguagePrefix( fileName, ITALIAN_PREFIX); + return ITALIAN_PREFIX; #endif #ifdef TAIWANESE - AddLanguagePrefix( fileName, TAIWANESE_PREFIX); + return TAIWANESE_PREFIX; #endif #ifdef CHINESE - AddLanguagePrefix( fileName, CHINESE_PREFIX); + return CHINESE_PREFIX; #endif } +static void AddLanguagePrefix(STR fileName) +{ + AddLanguagePrefix( fileName, GetLanguagePrefix()); +} + +void ResetEmptyRPCFaceSlots() +{ + //legion by jazz (load small faces from rpcs) + // reset empty slots with "-1" + for (UINT8 i = 0; i < 200; i++) + { + if (i == 0 && + gRPCSmallFaceValues[i].bEyesX == 0 && gRPCSmallFaceValues[i].bEyesY == 0 && + gRPCSmallFaceValues[i].bMouthX == 0 && gRPCSmallFaceValues[i].bMouthY == 0 && + gRPCSmallFaceValues[i].FaceIndex == 0 && gRPCSmallFaceValues[i].uiIndex == 0) + { + gRPCSmallFaceValues[i].uiIndex = -1; // -1 -> 65535 + } + else if (i > 0 && gRPCSmallFaceValues[i].uiIndex == 0) + { + gRPCSmallFaceValues[i].uiIndex = -1; // -1 -> 65535 + } + } +} + BOOLEAN LoadExternalGameplayData(STR directoryName) { char fileName[MAX_PATH]; @@ -167,27 +207,27 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) strcpy(fileName, directoryName); strcat(fileName, ENEMYMISCDROPSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInEnemyMiscDropsStats(gEnemyMiscDrops, fileName), ENEMYMISCDROPSFILENAME); + SGP_THROW_IFFALSE(ReadInEnemyMiscDropsStats(gEnemyMiscDrops, fileName), ENEMYMISCDROPSFILENAME); strcpy(fileName, directoryName); strcat(fileName, ENEMYEXPLOSIVEDROPSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInEnemyExplosiveDropsStats(gEnemyExplosiveDrops, fileName),ENEMYEXPLOSIVEDROPSFILENAME); + SGP_THROW_IFFALSE(ReadInEnemyExplosiveDropsStats(gEnemyExplosiveDrops, fileName),ENEMYEXPLOSIVEDROPSFILENAME); strcpy(fileName, directoryName); strcat(fileName, ENEMYWEAPONDROPSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInEnemyWeaponDropsStats(gEnemyWeaponDrops, fileName),ENEMYWEAPONDROPSFILENAME); + SGP_THROW_IFFALSE(ReadInEnemyWeaponDropsStats(gEnemyWeaponDrops, fileName),ENEMYWEAPONDROPSFILENAME); strcpy(fileName, directoryName); strcat(fileName, ENEMYAMMODROPSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInEnemyAmmoDropsStats(gEnemyAmmoDrops, fileName),ENEMYAMMODROPSFILENAME); + SGP_THROW_IFFALSE(ReadInEnemyAmmoDropsStats(gEnemyAmmoDrops, fileName),ENEMYAMMODROPSFILENAME); strcpy(fileName, directoryName); strcat(fileName, ENEMYARMOURDROPSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInEnemyArmourDropsStats(gEnemyArmourDrops, fileName),ENEMYARMOURDROPSFILENAME); + SGP_THROW_IFFALSE(ReadInEnemyArmourDropsStats(gEnemyArmourDrops, fileName),ENEMYARMOURDROPSFILENAME); // WANNE: Enemy drops - end // WANNE: Sector Loadscreens [2007-05-18] @@ -197,7 +237,7 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) if ( FileExists(fileName) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInSectorLoadscreensStats(gSectorLoadscreens, fileName),SECTORLOADSCREENSFILENAME); + SGP_THROW_IFFALSE(ReadInSectorLoadscreensStats(gSectorLoadscreens, fileName),SECTORLOADSCREENSFILENAME); } else { @@ -209,7 +249,7 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) strcpy(fileName, directoryName); strcat(fileName, AMMOTYPESFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInAmmoTypeStats(fileName),AMMOTYPESFILENAME); + SGP_THROW_IFFALSE(ReadInAmmoTypeStats(fileName),AMMOTYPESFILENAME); //Madd: Simple Localization //Read in the correct ammostring file for the given language @@ -245,7 +285,7 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) //CHRISL: If we fail to load, try loading just the default english strcpy(fileName, directoryName); strcat(fileName, AMMOFILENAME); - THROWIFFALSE(!ReadInAmmoStats(fileName),AMMOFILENAME); + SGP_THROW_IFFALSE(!ReadInAmmoStats(fileName),AMMOFILENAME); } @@ -253,13 +293,13 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) strcpy(fileName, directoryName); strcat(fileName, BURSTSOUNDSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInBurstSoundArray(fileName),BURSTSOUNDSFILENAME); + SGP_THROW_IFFALSE(ReadInBurstSoundArray(fileName),BURSTSOUNDSFILENAME); // Lesh: end strcpy(fileName, directoryName); strcat(fileName, ITEMSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInItemStats(fileName,FALSE),ITEMSFILENAME); + SGP_THROW_IFFALSE(ReadInItemStats(fileName,FALSE),ITEMSFILENAME); //Madd: Simple localization // The idea here is that we can have a separate xml file that's named differently @@ -286,57 +326,57 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) strcpy(fileName, directoryName); strcat(fileName, SOUNDSFILENAME); - THROWIFFALSE(ReadInSoundArray(fileName),SOUNDSFILENAME); + SGP_THROW_IFFALSE(ReadInSoundArray(fileName),SOUNDSFILENAME); strcpy(fileName, directoryName); strcat(fileName, MAGAZINESFILENAME); - THROWIFFALSE(ReadInMagazineStats(fileName),MAGAZINESFILENAME); + SGP_THROW_IFFALSE(ReadInMagazineStats(fileName),MAGAZINESFILENAME); strcpy(fileName, directoryName); strcat(fileName, ATTACHMENTSFILENAME); - THROWIFFALSE(ReadInAttachmentStats(fileName),ATTACHMENTSFILENAME); + SGP_THROW_IFFALSE(ReadInAttachmentStats(fileName),ATTACHMENTSFILENAME); strcpy(fileName, directoryName); strcat(fileName, ATTACHMENTINFOFILENAME); - THROWIFFALSE(ReadInAttachmentInfoStats(fileName),ATTACHMENTINFOFILENAME); + SGP_THROW_IFFALSE(ReadInAttachmentInfoStats(fileName),ATTACHMENTINFOFILENAME); strcpy(fileName, directoryName); strcat(fileName, LAUNCHABLESFILENAME); - THROWIFFALSE(ReadInLaunchableStats(fileName),LAUNCHABLESFILENAME); + SGP_THROW_IFFALSE(ReadInLaunchableStats(fileName),LAUNCHABLESFILENAME); strcpy(fileName, directoryName); strcat(fileName, COMPATIBLEFACEITEMSFILENAME); - THROWIFFALSE(ReadInCompatibleFaceItemStats(fileName),COMPATIBLEFACEITEMSFILENAME); + SGP_THROW_IFFALSE(ReadInCompatibleFaceItemStats(fileName),COMPATIBLEFACEITEMSFILENAME); strcpy(fileName, directoryName); strcat(fileName, MERGESFILENAME); - THROWIFFALSE(ReadInMergeStats(fileName),MERGESFILENAME); + SGP_THROW_IFFALSE(ReadInMergeStats(fileName),MERGESFILENAME); //if(!WriteMergeStats()) // return FALSE; strcpy(fileName, directoryName); strcat(fileName, ATTACHMENTCOMBOMERGESFILENAME); - THROWIFFALSE(ReadInAttachmentComboMergeStats(fileName),ATTACHMENTCOMBOMERGESFILENAME); + SGP_THROW_IFFALSE(ReadInAttachmentComboMergeStats(fileName),ATTACHMENTCOMBOMERGESFILENAME); strcpy(fileName, directoryName); strcat(fileName, EXPLOSIVESFILENAME); - THROWIFFALSE(ReadInExplosiveStats(fileName),EXPLOSIVESFILENAME); + SGP_THROW_IFFALSE(ReadInExplosiveStats(fileName),EXPLOSIVESFILENAME); strcpy(fileName, directoryName); strcat(fileName, ARMOURSFILENAME); - THROWIFFALSE(ReadInArmourStats(fileName),ARMOURSFILENAME); + SGP_THROW_IFFALSE(ReadInArmourStats(fileName),ARMOURSFILENAME); // CHRISL: strcpy(fileName, directoryName); strcat(fileName, LOADBEARINGEQUIPMENTFILENAME); - THROWIFFALSE(ReadInlbeStats(fileName),LOADBEARINGEQUIPMENTFILENAME); + SGP_THROW_IFFALSE(ReadInlbeStats(fileName),LOADBEARINGEQUIPMENTFILENAME); // CHRISL: LBEPocketType.clear(); strcpy(fileName, directoryName); strcat(fileName, LBEPOCKETFILENAME); - THROWIFFALSE(ReadInLBEPocketStats(fileName,FALSE),LBEPOCKETFILENAME); + SGP_THROW_IFFALSE(ReadInLBEPocketStats(fileName,FALSE),LBEPOCKETFILENAME); //CHRISL: Simple localization // Same setup as what Madd used for items.xml @@ -354,108 +394,117 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) // CHRISL: strcpy(fileName, directoryName); strcat(fileName, MERCSTARTINGGEARFILENAME); - THROWIFFALSE(ReadInMercStartingGearStats(fileName),MERCSTARTINGGEARFILENAME); + SGP_THROW_IFFALSE(ReadInMercStartingGearStats(fileName),MERCSTARTINGGEARFILENAME); strcpy(fileName, directoryName); strcat(fileName, WEAPONSFILENAME); - THROWIFFALSE(ReadInWeaponStats(fileName),WEAPONSFILENAME); + SGP_THROW_IFFALSE(ReadInWeaponStats(fileName),WEAPONSFILENAME); strcpy(fileName, directoryName); strcat(fileName, INCOMPATIBLEATTACHMENTSFILENAME); - THROWIFFALSE(ReadInIncompatibleAttachmentStats(fileName),INCOMPATIBLEATTACHMENTSFILENAME); + SGP_THROW_IFFALSE(ReadInIncompatibleAttachmentStats(fileName),INCOMPATIBLEATTACHMENTSFILENAME); + + //WarmSteel - Attachment slots related xml's + strcpy(fileName, directoryName); + strcat(fileName, ATTACHMENTSLOTSFILENAME); + SGP_THROW_IFFALSE(ReadInAttachmentSlotsStats(fileName),ATTACHMENTSLOTSFILENAME); strcpy(fileName, directoryName); strcat(fileName, ENEMYGUNCHOICESFILENAME); - THROWIFFALSE(ReadInExtendedArmyGunChoicesStats (fileName),ENEMYGUNCHOICESFILENAME); + SGP_THROW_IFFALSE(ReadInExtendedArmyGunChoicesStats (fileName),ENEMYGUNCHOICESFILENAME); strcpy(fileName, directoryName); strcat(fileName, ENEMYITEMCHOICESFILENAME); - THROWIFFALSE(ReadInArmyItemChoicesStats(fileName),ENEMYITEMCHOICESFILENAME); + SGP_THROW_IFFALSE(ReadInArmyItemChoicesStats(fileName),ENEMYITEMCHOICESFILENAME); strcpy(fileName, directoryName); strcat(fileName, IMPITEMCHOICESFILENAME); - THROWIFFALSE(ReadInIMPItemChoicesStats(fileName),IMPITEMCHOICESFILENAME); + SGP_THROW_IFFALSE(ReadInIMPItemChoicesStats(fileName),IMPITEMCHOICESFILENAME); + + std::copy(DefaultarmsDealerInfo, + DefaultarmsDealerInfo + sizeof(DefaultarmsDealerInfo)/sizeof(*DefaultarmsDealerInfo), + armsDealerInfo.begin()); strcpy(fileName, directoryName); strcat(fileName, TONYINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gTonyInventory,fileName),TONYINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gTonyInventory,fileName),TONYINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, DEVININVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gDevinInventory,fileName),DEVININVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gDevinInventory,fileName),DEVININVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, FRANZINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gFranzInventory,fileName),FRANZINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gFranzInventory,fileName),FRANZINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, KEITHINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gKeithInventory,fileName),KEITHINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gKeithInventory,fileName),KEITHINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, SAMINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gSamInventory,fileName),SAMINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gSamInventory,fileName),SAMINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, JAKEINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gJakeInventory,fileName),JAKEINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gJakeInventory,fileName),JAKEINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, HOWARDINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gHowardInventory,fileName),HOWARDINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gHowardInventory,fileName),HOWARDINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, GABBYINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gGabbyInventory,fileName),GABBYINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gGabbyInventory,fileName),GABBYINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, FRANKINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gFrankInventory,fileName),FRANKINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gFrankInventory,fileName),FRANKINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, ELGININVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gElginInventory,fileName),ELGININVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gElginInventory,fileName),ELGININVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, MANNYINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gMannyInventory,fileName),MANNYINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gMannyInventory,fileName),MANNYINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, HERVEINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gHerveInventory,fileName),HERVEINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gHerveInventory,fileName),HERVEINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, PETERINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gPeterInventory,fileName),PETERINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gPeterInventory,fileName),PETERINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, ALBERTOINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gAlbertoInventory,fileName),ALBERTOINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gAlbertoInventory,fileName),ALBERTOINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, CARLOINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gCarloInventory,fileName),CARLOINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gCarloInventory,fileName),CARLOINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, MICKEYINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gMickyInventory,fileName),MICKEYINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gMickyInventory,fileName),MICKEYINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, ARNIEINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gArnieInventory,fileName),ARNIEINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gArnieInventory,fileName),ARNIEINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, PERKOINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gPerkoInventory,fileName),PERKOINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gPerkoInventory,fileName),PERKOINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, FREDOINVENTORYFILENAME); - THROWIFFALSE(ReadInInventoryStats(gFredoInventory,fileName),FREDOINVENTORYFILENAME); + SGP_THROW_IFFALSE(ReadInInventoryStats(gFredoInventory,fileName),FREDOINVENTORYFILENAME); strcpy(fileName, directoryName); strcat(fileName, CITYTABLEFILENAME); - THROWIFFALSE(ReadInMapStructure(fileName, FALSE),CITYTABLEFILENAME); + SGP_THROW_IFFALSE(ReadInMapStructure(fileName, FALSE),CITYTABLEFILENAME); #ifndef ENGLISH AddLanguagePrefix(fileName); @@ -474,113 +523,365 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) // Lesh: load altsectors list strcpy(fileName, directoryName); strcat(fileName, ALTSECTORSFILENAME); - THROWIFFALSE(ReadInAltSectors(fileName),ALTSECTORSFILENAME); + SGP_THROW_IFFALSE(ReadInAltSectors(fileName),ALTSECTORSFILENAME); // Lesh: load samsites - must be after cities.xml strcpy(fileName, directoryName); strcat(fileName, SAMSITESFILENAME); - THROWIFFALSE(ReadInSAMInfo(fileName),SAMSITESFILENAME); + SGP_THROW_IFFALSE(ReadInSAMInfo(fileName),SAMSITESFILENAME); // Lesh: army externalization strcpy(fileName, directoryName); strcat(fileName, GARRISONFILENAME); - THROWIFFALSE(ReadInGarrisonInfo(fileName),GARRISONFILENAME); + SGP_THROW_IFFALSE(ReadInGarrisonInfo(fileName),GARRISONFILENAME); strcpy(fileName, directoryName); strcat(fileName, PATROLFILENAME); - THROWIFFALSE(ReadInPatrolInfo(fileName),PATROLFILENAME); + SGP_THROW_IFFALSE(ReadInPatrolInfo(fileName),PATROLFILENAME); strcpy(fileName, directoryName); strcat(fileName, COMPOSITIONFILENAME); - THROWIFFALSE(ReadInArmyCompositionInfo(fileName),COMPOSITIONFILENAME); + SGP_THROW_IFFALSE(ReadInArmyCompositionInfo(fileName),COMPOSITIONFILENAME); strcpy(fileName, directoryName); strcat(fileName, EXPLOSIONDATAFILENAME); - THROWIFFALSE(ReadInExplosionDataStats(fileName),EXPLOSIONDATAFILENAME); + SGP_THROW_IFFALSE(ReadInExplosionDataStats(fileName),EXPLOSIONDATAFILENAME); // Kaiden: Read in Restricted Sectors for Mobile Militia strcpy(fileName, directoryName); strcat(fileName, ROAMINGMILITIAFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInRoamingInfo(fileName),ROAMINGMILITIAFILENAME); + SGP_THROW_IFFALSE(ReadInRoamingInfo(fileName),ROAMINGMILITIAFILENAME); // Dealtar: Read in shipping destinations and delivery methods gPostalService.Clear(); strcpy(fileName, directoryName); strcat(fileName, SHIPPINGDESTINATIONSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInShippingDestinations(fileName, FALSE),SHIPPINGDESTINATIONSFILENAME); + SGP_THROW_IFFALSE(ReadInShippingDestinations(fileName, FALSE),SHIPPINGDESTINATIONSFILENAME); #ifndef ENGLISH AddLanguagePrefix(fileName); if ( FileExists(fileName) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInShippingDestinations(fileName, TRUE),SHIPPINGDESTINATIONSFILENAME); + SGP_THROW_IFFALSE(ReadInShippingDestinations(fileName, TRUE),SHIPPINGDESTINATIONSFILENAME); } #endif strcpy(fileName, directoryName); strcat(fileName, DELIVERYMETHODSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInDeliveryMethods(fileName),DELIVERYMETHODSFILENAME); + SGP_THROW_IFFALSE(ReadInDeliveryMethods(fileName),DELIVERYMETHODSFILENAME); // HEADROCK HAM 3.5: Read in facility types strcpy(fileName, directoryName); strcat(fileName, FACILITYTYPESFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInFacilityTypes(fileName), FACILITYTYPESFILENAME); + SGP_THROW_IFFALSE(ReadInFacilityTypes(fileName,FALSE), FACILITYTYPESFILENAME); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInFacilityTypes(fileName,TRUE)) + return FALSE; + } +#endif // HEADROCK HAM 3.4: Read in facility locations strcpy(fileName, directoryName); strcat(fileName, SECTORFACILITIESFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInSectorFacilities(fileName), SECTORFACILITIESFILENAME); + SGP_THROW_IFFALSE(ReadInSectorFacilities(fileName), SECTORFACILITIESFILENAME); // HEADROCK HAM 3.4: Read in dynamic roaming restrictions strcpy(fileName, directoryName); strcat(fileName, DYNAMICROAMINGFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInDynamicRoamingRestrictions(fileName), DYNAMICROAMINGFILENAME); + SGP_THROW_IFFALSE(ReadInDynamicRoamingRestrictions(fileName), DYNAMICROAMINGFILENAME); // HEADROCK HAM 3.6: Read in customized sector names strcpy(fileName, directoryName); strcat(fileName, SECTORNAMESFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInSectorNames(fileName), SECTORNAMESFILENAME); + SGP_THROW_IFFALSE(ReadInSectorNames(fileName,FALSE,0), SECTORNAMESFILENAME); +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInSectorNames(fileName,TRUE,0)) + return FALSE; + } +#endif + + // moved to lua + //strcpy(fileName, directoryName); + //strcat(fileName, SECTORLEVEL1NAMESFILENAME); + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + //SGP_THROW_IFFALSE(ReadInSectorNames(fileName,FALSE,1), SECTORLEVEL1NAMESFILENAME); + // + //#ifndef ENGLISH + //AddLanguagePrefix(fileName); + //if ( FileExists(fileName) ) + //{ + // DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + // if(!ReadInSectorNames(fileName,TRUE,1)) + // return FALSE; + //} + //#endif + + //strcpy(fileName, directoryName); + //strcat(fileName, SECTORLEVEL2NAMESFILENAME); + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + //SGP_THROW_IFFALSE(ReadInSectorNames(fileName,FALSE,2), SECTORLEVEL2NAMESFILENAME); + // + //#ifndef ENGLISH + //AddLanguagePrefix(fileName); + //if ( FileExists(fileName) ) + //{ + // DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + // if(!ReadInSectorNames(fileName,TRUE,2)) + // return FALSE; + //} + //#endif + + //strcpy(fileName, directoryName); + //strcat(fileName, SECTORLEVEL3NAMESFILENAME); + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + //SGP_THROW_IFFALSE(ReadInSectorNames(fileName,FALSE,3), SECTORLEVEL3NAMESFILENAME); + // + //#ifndef ENGLISH + //AddLanguagePrefix(fileName); + //if ( FileExists(fileName) ) + //{ + // DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + // if(!ReadInSectorNames(fileName,TRUE,3)) + // return FALSE; + //} + //#endif + + // code duplication? +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInSectorNames(fileName,TRUE,0)) + return FALSE; + } +#endif + + // WANNE: Why do we need it. It should also run without that file!! + // SANDRO - always initialize those files, we need it on game start if (gGameExternalOptions.fReadProfileDataFromXML) { // HEADROCK PROFEX: Read in Merc Profile data to replace PROF.DAT data strcpy(fileName, directoryName); strcat(fileName, MERCPROFILESFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInMercProfiles(fileName), MERCPROFILESFILENAME); + SGP_THROW_IFFALSE(ReadInMercProfiles(fileName, FALSE), MERCPROFILESFILENAME); + + #ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInMercProfiles(fileName,TRUE)) + return FALSE; + } + #endif // HEADROCK PROFEX: Read in Merc Opinion data to replace PROF.DAT data strcpy(fileName, directoryName); strcat(fileName, MERCOPINIONSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInMercOpinions(fileName), MERCOPINIONSFILENAME); + SGP_THROW_IFFALSE(ReadInMercOpinions(fileName), MERCOPINIONSFILENAME); } // HEADROCK HAM 3.6: Read in customized Bloodcat Placements strcpy(fileName, directoryName); strcat(fileName, BLOODCATPLACEMENTSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInBloodcatPlacements(fileName), BLOODCATPLACEMENTSFILENAME); + SGP_THROW_IFFALSE(ReadInBloodcatPlacements(fileName), BLOODCATPLACEMENTSFILENAME); // HEADROCK HAM 3.6: Read in customized Uniform Colors strcpy(fileName, directoryName); strcat(fileName, UNIFORMCOLORSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); - THROWIFFALSE(ReadInUniforms(fileName), UNIFORMCOLORSFILENAME); + SGP_THROW_IFFALSE(ReadInUniforms(fileName), UNIFORMCOLORSFILENAME); strcpy(fileName, directoryName); strcat(fileName, MULTIPLAYERTEAMSFILENAME); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); mpTeams.ReadInMPTeams(fileName); + //legion by jazz (load small faces from rpcs) + strcpy(fileName, directoryName); + strcat(fileName, RPCFACESSMALLFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInSmallFacesStats(gRPCSmallFaceValues,fileName), RPCFACESSMALLFILENAME); + ResetEmptyRPCFaceSlots(); + + //Hidden Names by Jazz + strcpy(fileName, directoryName); + strcat(fileName, HIDDENNAMESFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInHiddenNamesStats(zHiddenNames,fileName), HIDDENNAMESFILENAME); + + + + if (gGameExternalOptions.fEnemyNames == TRUE && gGameExternalOptions.fEnemyRank == FALSE) + { + // Enemy Names Group by Jazz + strcpy(fileName, directoryName); + strcat(fileName, ENEMYNAMESFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInEnemyNames(fileName,FALSE), ENEMYNAMESFILENAME); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInEnemyNames(fileName,TRUE)) + return FALSE; + } +#endif + } + + + if (gGameExternalOptions.fCivGroupName == TRUE) + { + // Civ Names Group by Jazz + strcpy(fileName, directoryName); + strcat(fileName, CIVGROUPNAMESFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInCivGroupNamesStats(fileName,FALSE), CIVGROUPNAMESFILENAME); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInCivGroupNamesStats(fileName,TRUE)) + return FALSE; + } +#endif + } + + + // Sender Name List by Jazz + strcpy(fileName, directoryName); + strcat(fileName, SENDERNAMELISTFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInSenderNameList(fileName,FALSE), SENDERNAMELISTFILENAME); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInSenderNameList(fileName,TRUE)) + return FALSE; + } +#endif + + if (gGameExternalOptions.fEnemyNames == FALSE && gGameExternalOptions.fEnemyRank == TRUE) + { + // Enemy Rank by Jazz + strcpy(fileName, directoryName); + strcat(fileName, ENEMYRANKFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInEnemyRank(fileName,FALSE), ENEMYRANKFILENAME); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInEnemyRank(fileName,TRUE)) + return FALSE; + } +#endif + } + + // IMP Portraits List by Jazz + strcpy(fileName, directoryName); + strcat(fileName, IMPPORTRAITS); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInIMPPortraits(fileName,FALSE), IMPPORTRAITS); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInIMPPortraits(fileName,TRUE)) + return FALSE; + } +#endif + + LoadIMPPortraitsTEMP(); + + //Sound profile by jazz + strcpy(fileName, directoryName); + strcat(fileName, SOUNDPROFILE); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInSoundProfile(fileName), SOUNDPROFILE); + + //Random stats by jazz + strcpy(fileName, directoryName); + strcat(fileName, RANDOMSTATS); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInRandomStats(fileName), RANDOMSTATS); + //new profiles by Jazz + strcpy(fileName, directoryName); + strcat(fileName, MERCAVAILABILITY); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInMercAvailability(fileName,FALSE), MERCAVAILABILITY); + +#ifndef ENGLISH + AddLanguagePrefix(fileName); + if ( FileExists(fileName) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + if(!ReadInMercAvailability(fileName,TRUE)) + return FALSE; + } +#endif + UINT32 i; + for(i=0; i + +#include "Luaglobal.h" +#include "LuaInitNPCs.h" +#include "XML.h" + +BOOLEAN Style_JA = TRUE; +extern INT8 Test = 0; + +UINT32 iStringToUseLua = -1; +// BF +class VideoPlayer +{ +public: + enum VideoType + { + VT_NONE = 0, + VT_SMK = 1, + VT_BINK = 2, + }; + VideoPlayer(UINT32 type) : _type(type), _smk(NULL), _bink(NULL), _current(VT_NONE) + { + } + void Initialize() + { + if(_type & VT_SMK) + { + SmkInitialize( ghWindow, SCREEN_WIDTH, SCREEN_HEIGHT); + } + if(_type & VT_BINK) + { + BinkInitialize(ghWindow, SCREEN_WIDTH, SCREEN_HEIGHT); + } + } + void Shutdown() + { + if(_type & VT_SMK) + { + SmkShutdown(); + } + if(_type & VT_BINK) + { + BinkShutdownVideo(); + } + } + + bool isValid() + { + if( (_current == VT_SMK && _smk && !_bink) || (_current == VT_BINK && !_smk && _bink) ) + { + return true; + } + return false; + } + + bool isPlaying() + { + if( _current == VT_SMK && _smk && !_bink ) + { + return SmkPollFlics() != 0; + } + else if(_current == VT_BINK && !_smk && _bink) + { + return BinkPollFlics() != 0; + } + else if(_current == VT_NONE && !_smk && !_bink) + { + return false; + } + SGP_THROW(L"Invalid Video Player state!"); + } + + void stopVideo() + { + if(_current == VT_SMK && _smk && !_bink) + { + SmkCloseFlic(_smk); + _smk = NULL; + } + else if(_current == VT_BINK && !_smk && _bink) + { + BinkCloseFlic(_bink); + _bink = NULL; + } + _current = VT_NONE; + } + + bool startVideo(std::string const& filename) + { + if(isPlaying()) + { + return false; + } + + /// check file extension + std::string ext; + std::string::size_type pos = filename.find_last_of("."); + if(pos != std::string::npos) + { + ext = filename.substr(pos, filename.size() - pos); + } + if(vfs::StrCmp::Equal(ext, ".smk")) + { + return startSmkVideo(filename); + } + else if(vfs::StrCmp::Equal(ext, ".bik")) + { + return startBinkVideo(filename); + } + else if(ext.empty()) + { + // try .bik first + if(!startBinkVideo(filename + ".bik")) + { + return startSmkVideo(filename + ".smk"); + } + return true; + } + else + { + SGP_INFO(L"Unknown video file format"); + } + return false; + } +private: + bool startSmkVideo(std::string const& filename) + { + _smk = SmkPlayFlic( filename.c_str(), (SCREEN_WIDTH-640)/2, (SCREEN_HEIGHT-480)/2, TRUE ); + if(_smk) + { + _current = VT_SMK; + return true; + } + return false; + } + bool startBinkVideo(std::string const& filename) + { + _bink = BinkPlayFlic( filename.c_str(), (SCREEN_WIDTH-640)/2, (SCREEN_HEIGHT-480)/2, BINK_FLIC_AUTOCLOSE | BINK_FLIC_CENTER_VERTICAL); + if(_bink) + { + _current = VT_BINK; + return true; + } + return false; + } +private: + UINT32 _type; + SMKFLIC* _smk; + BINKFLIC* _bink; + VideoType _current; +}; + +static VideoPlayer s_VP(VideoPlayer::VT_SMK | VideoPlayer::VT_BINK); extern STR16 gzIntroScreen[]; extern HVSURFACE ghFrameBuffer; @@ -54,37 +209,37 @@ UINT32 guiIntroExitScreen = INTRO_SCREEN; extern BOOLEAN gfDoneWithSplashScreen; -SMKFLIC *gpSmackFlic = NULL; - -#define SMKINTRO_FIRST_VIDEO 255 -#define SMKINTRO_NO_VIDEO -1 +//BF SMKFLIC *gpSmackFlic = NULL; //enums for the various smacker files -enum +enum EGameVideos { - SMKINTRO_REBEL_CRDT, - SMKINTRO_OMERTA, - SMKINTRO_PRAGUE_CRDT, - SMKINTRO_PRAGUE, + INTRO_NO_VIDEO = -1, + INTRO_REBEL_CRDT = 0, + INTRO_OMERTA, + INTRO_PRAGUE_CRDT, + INTRO_PRAGUE, //there are no more videos shown for the begining - SMKINTRO_END_END_SPEECH_MIGUEL, - SMKINTRO_END_END_SPEECH_NO_MIGUEL, - SMKINTRO_END_HELI_FLYBY, - SMKINTRO_END_SKYRIDER_HELICOPTER, - SMKINTRO_END_NOSKYRIDER_HELICOPTER, + INTRO_END_END_SPEECH_MIGUEL, + INTRO_END_END_SPEECH_NO_MIGUEL, + INTRO_END_HELI_FLYBY, + INTRO_END_SKYRIDER_HELICOPTER, + INTRO_END_NOSKYRIDER_HELICOPTER, - SMKINTRO_SPLASH_SCREEN, - SMKINTRO_SPLASH_TALONSOFT, + INTRO_SPLASH_SCREEN, + INTRO_SPLASH_TALONSOFT, //there are no more videos shown for the endgame - SMKINTRO_LAST_END_GAME, + INTRO_LAST_END_GAME, + + INTRO_FIRST_VIDEO = 255 }; -INT32 giCurrentIntroBeingPlayed = SMKINTRO_NO_VIDEO; - +EGameVideos giCurrentIntroBeingPlayed = INTRO_NO_VIDEO; +/* CHAR *gpzSmackerFileNames[] = { //begining of the game @@ -104,7 +259,9 @@ CHAR *gpzSmackerFileNames[] = "INTRO\\SplashScreen.smk", "INTRO\\TalonSoftid_endhold.smk", }; - +*/ +typedef std::map VideoFileNames_t; +static VideoFileNames_t s_VFN; //enums used for when the intro screen can come up, either begining game intro, or end game cinematic INT8 gbIntroScreenMode=-1; @@ -112,15 +269,15 @@ INT8 gbIntroScreenMode=-1; extern void CDromEjectionErrorMessageBoxCallBack( UINT8 bExitValue ); -void GetIntroScreenUserInput(); -BOOLEAN EnterIntroScreen(); -void RenderIntroScreen(); -void ExitIntroScreen(); -void HandleIntroScreen(); -void PrepareToExitIntroScreen(); -INT32 GetNextIntroVideo( UINT32 uiCurrentVideo ); -void StartPlayingIntroFlic( INT32 iIndexOfFlicToPlay ); -void DisplaySirtechSplashScreen(); +void GetIntroScreenUserInput(); +BOOLEAN EnterIntroScreen(); +void RenderIntroScreen(); +void ExitIntroScreen(); +void HandleIntroScreen(); +void PrepareToExitIntroScreen(); +EGameVideos GetNextIntroVideo( EGameVideos uiCurrentVideo ); +void StartPlayingIntroFlic( EGameVideos iIndexOfFlicToPlay ); +void DisplaySirtechSplashScreen(); //ppp @@ -131,6 +288,24 @@ UINT32 IntroScreenInit( void ) //Set so next time we come in, we can set up gfIntroScreenEntry = TRUE; + CIniReader inireader("IntroVideos.ini"); + s_VFN[INTRO_REBEL_CRDT] = inireader.ReadString("INTRO_BEGINNING","INTRO_REBEL_CRDT","INTRO\\Rebel_cr"); + s_VFN[INTRO_OMERTA] = inireader.ReadString("INTRO_BEGINNING","INTRO_OMERTA","INTRO\\Omerta"); + s_VFN[INTRO_PRAGUE_CRDT] = inireader.ReadString("INTRO_BEGINNING","INTRO_PRAGUE_CRDT","INTRO\\Prague_cr"); + s_VFN[INTRO_PRAGUE] = inireader.ReadString("INTRO_BEGINNING","INTRO_PRAGUE","INTRO\\Prague"); + + //there are no more videos shown for the begining + s_VFN[INTRO_END_END_SPEECH_MIGUEL] = inireader.ReadString("INTRO_ENDING","INTRO_END_END_SPEECH_MIGUEL","INTRO\\Throne_Mig"); + s_VFN[INTRO_END_END_SPEECH_NO_MIGUEL] = inireader.ReadString("INTRO_ENDING","INTRO_END_END_SPEECH_NO_MIGUEL","INTRO\\Throne_NoMig"); + s_VFN[INTRO_END_HELI_FLYBY] = inireader.ReadString("INTRO_ENDING","INTRO_END_HELI_FLYBY","INTRO\\Heli_FlyBy"); + s_VFN[INTRO_END_SKYRIDER_HELICOPTER] = inireader.ReadString("INTRO_ENDING","INTRO_END_SKYRIDER_HELICOPTER","INTRO\\Heli_Sky"); + s_VFN[INTRO_END_NOSKYRIDER_HELICOPTER] = inireader.ReadString("INTRO_ENDING","INTRO_END_NOSKYRIDER_HELICOPTER","INTRO\\Heli_NoSky"); + + s_VFN[INTRO_SPLASH_SCREEN] = inireader.ReadString("INTRO_SPLASH","INTRO_SPLASH_SCREEN","INTRO\\SplashScreen"); + s_VFN[INTRO_SPLASH_TALONSOFT] = inireader.ReadString("INTRO_SPLASH","INTRO_SPLASH_TALONSOFT","INTRO\\TalonSoftid_endhold"); + + //there are no more videos shown for the endgame + return( 1 ); } @@ -176,11 +351,11 @@ UINT32 IntroScreenHandle( void ) BOOLEAN EnterIntroScreen() { - INT32 iFirstVideoID = -1; + +Test = 0; ClearMainMenu(); - SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); // Don't play music.... @@ -193,28 +368,11 @@ BOOLEAN EnterIntroScreen() return( TRUE ); } -//#ifdef JA2BETAVERSION -// if( FileExists( "..\\NoIntro.txt" ) ) -// { -// PrepareToExitIntroScreen(); -// return( TRUE ); -// } -//#endif -#ifndef USE_VFS - //if the library doesnt exist, exit - if( !IsLibraryOpened( LIBRARY_INTRO ) ) - { - PrepareToExitIntroScreen(); - return( TRUE ); - } -#endif - - //initialize smacker - SmkInitialize( ghWindow, SCREEN_WIDTH, SCREEN_HEIGHT); - + //initialize video player + s_VP.Initialize(); //get the index opf the first video to watch - iFirstVideoID = GetNextIntroVideo( SMKINTRO_FIRST_VIDEO ); + EGameVideos iFirstVideoID = GetNextIntroVideo( INTRO_FIRST_VIDEO ); if( iFirstVideoID != -1 ) { @@ -239,29 +397,23 @@ void RenderIntroScreen() void ExitIntroScreen() { - - //shutdown smaker - SmkShutdown(); + //shutdown video player + s_VP.Shutdown(); } void HandleIntroScreen() { - BOOLEAN fFlicStillPlaying = FALSE; - //if we are exiting this screen, this frame, dont update the screen if( gfIntroScreenExit ) return; - - //handle smaker each frame - fFlicStillPlaying = SmkPollFlics(); + //handle video in each frame + BOOLEAN fFlicStillPlaying = s_VP.isPlaying(); //if the flic is not playing if( !fFlicStillPlaying ) { - INT32 iNextVideoToPlay = -1; - - iNextVideoToPlay = GetNextIntroVideo( giCurrentIntroBeingPlayed ); + EGameVideos iNextVideoToPlay = GetNextIntroVideo( giCurrentIntroBeingPlayed ); if( iNextVideoToPlay != -1 ) { @@ -270,7 +422,7 @@ void HandleIntroScreen() else { PrepareToExitIntroScreen(); - giCurrentIntroBeingPlayed = -1; + giCurrentIntroBeingPlayed = INTRO_NO_VIDEO; } } @@ -279,12 +431,11 @@ void HandleIntroScreen() -void GetIntroScreenUserInput() +void GetIntroScreenUserInput() { InputAtom Event; POINT MousePos; - GetCursorPos(&MousePos); ScreenToClient(ghWindow, &MousePos); // In window coords! @@ -292,7 +443,7 @@ void GetIntroScreenUserInput() { // HOOK INTO MOUSE HOOKS switch( Event.usEvent) - { + { case LEFT_BUTTON_DOWN: MouseSystemHook(LEFT_BUTTON_DOWN, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown); break; @@ -313,16 +464,16 @@ void GetIntroScreenUserInput() break; } - if( Event.usEvent == KEY_UP ) { switch( Event.usParam ) { case ESC: + s_VP.stopVideo(); PrepareToExitIntroScreen(); break; case SPACE: - SmkCloseFlic( gpSmackFlic ); + s_VP.stopVideo(); break; #ifdef JA2TESTVERSION @@ -343,15 +494,18 @@ void GetIntroScreenUserInput() if( gfLeftButtonState || gfRightButtonState ) { //advance to the next flic - SmkCloseFlic( gpSmackFlic ); + s_VP.stopVideo(); } } void PrepareToExitIntroScreen() { +#ifdef LUA_INTRO + LuaIntro(0, 0, 0, 0); +#else //if its the intro at the begining of the game - if( gbIntroScreenMode == INTRO_BEGINING ) + if( gbIntroScreenMode == INTRO_BEGINNING ) { //go to the init screen guiIntroExitScreen = INIT_SCREEN; @@ -374,110 +528,121 @@ void PrepareToExitIntroScreen() } gfIntroScreenExit = TRUE; +#endif } -INT32 GetNextIntroVideo( UINT32 uiCurrentVideo ) +EGameVideos GetNextIntroVideo( EGameVideos uiCurrentVideo ) { - INT32 iStringToUse = -1; - + EGameVideos iStringToUse = INTRO_NO_VIDEO; +#ifdef LUA_INTRO + switch( Test ) + { + case 0: + LuaIntro(1, uiCurrentVideo, 0, 0); + iStringToUse = (EGameVideos)iStringToUseLua; + //Test = 1; + break; + } +#else //switch on whether it is the beginging or the end game video switch( gbIntroScreenMode ) { //the video at the begining of the game - case INTRO_BEGINING: + case INTRO_BEGINNING: { switch( uiCurrentVideo ) { - case SMKINTRO_FIRST_VIDEO: - iStringToUse = SMKINTRO_REBEL_CRDT; + case INTRO_FIRST_VIDEO: + iStringToUse = INTRO_REBEL_CRDT; break; - case SMKINTRO_REBEL_CRDT: - iStringToUse = SMKINTRO_OMERTA; + case INTRO_REBEL_CRDT: + iStringToUse = INTRO_OMERTA; break; - case SMKINTRO_OMERTA: - iStringToUse = SMKINTRO_PRAGUE_CRDT; + case INTRO_OMERTA: + iStringToUse = INTRO_PRAGUE_CRDT; break; - case SMKINTRO_PRAGUE_CRDT: - iStringToUse = SMKINTRO_PRAGUE; + case INTRO_PRAGUE_CRDT: + iStringToUse = INTRO_PRAGUE; break; - case SMKINTRO_PRAGUE: - iStringToUse = -1; + case INTRO_PRAGUE: + iStringToUse = INTRO_NO_VIDEO; break; -// case SMKINTRO_LAST_INTRO: +// case INTRO_LAST_INTRO: // iStringToUse = -1; // break; } + break; } - break; //end game case INTRO_ENDING: { switch( uiCurrentVideo ) { - case SMKINTRO_FIRST_VIDEO: + case INTRO_FIRST_VIDEO: + { //if Miguel is dead, play the flic with out him in it if( gMercProfiles[ MIGUEL ].bMercStatus == MERC_IS_DEAD ) - iStringToUse = SMKINTRO_END_END_SPEECH_NO_MIGUEL; + iStringToUse = INTRO_END_END_SPEECH_NO_MIGUEL; else - iStringToUse = SMKINTRO_END_END_SPEECH_MIGUEL; + iStringToUse = INTRO_END_END_SPEECH_MIGUEL; break; - - case SMKINTRO_END_END_SPEECH_MIGUEL: - case SMKINTRO_END_END_SPEECH_NO_MIGUEL: - iStringToUse = SMKINTRO_END_HELI_FLYBY; + } + case INTRO_END_END_SPEECH_MIGUEL: + case INTRO_END_END_SPEECH_NO_MIGUEL: + { + iStringToUse = INTRO_END_HELI_FLYBY; break; - + } //if SkyRider is dead, play the flic without him - case SMKINTRO_END_HELI_FLYBY: + case INTRO_END_HELI_FLYBY: + { if( gMercProfiles[ SKYRIDER ].bMercStatus == MERC_IS_DEAD ) - iStringToUse = SMKINTRO_END_NOSKYRIDER_HELICOPTER; + iStringToUse = INTRO_END_NOSKYRIDER_HELICOPTER; else - iStringToUse = SMKINTRO_END_SKYRIDER_HELICOPTER; + iStringToUse = INTRO_END_SKYRIDER_HELICOPTER; break; + } } + break; } - break; case INTRO_SPLASH: switch( uiCurrentVideo ) { - case SMKINTRO_FIRST_VIDEO: - iStringToUse = SMKINTRO_SPLASH_SCREEN; + case INTRO_FIRST_VIDEO: + iStringToUse = INTRO_SPLASH_SCREEN; break; - case SMKINTRO_SPLASH_SCREEN: + case INTRO_SPLASH_SCREEN: //iStringToUse = SMKINTRO_SPLASH_TALONSOFT; break; } break; } +#endif return( iStringToUse ); } -void StartPlayingIntroFlic( INT32 iIndexOfFlicToPlay ) +void StartPlayingIntroFlic( EGameVideos iIndexOfFlicToPlay ) { - if( iIndexOfFlicToPlay != -1 ) { + giCurrentIntroBeingPlayed = iIndexOfFlicToPlay; //start playing a flic - gpSmackFlic = SmkPlayFlic( gpzSmackerFileNames[ iIndexOfFlicToPlay ], (SCREEN_WIDTH-640)/2, (SCREEN_HEIGHT-480)/2, TRUE ); - - if( gpSmackFlic != NULL ) + if(s_VP.startVideo( s_VFN[iIndexOfFlicToPlay] )) { - giCurrentIntroBeingPlayed = iIndexOfFlicToPlay; - } - else - { - //do a check + if(!s_VP.isValid()) + { + //do a check #ifdef JA2BETAVERSION - PrepareToExitIntroScreen(); + PrepareToExitIntroScreen(); #else - - DoScreenIndependantMessageBox( gzIntroScreen[INTRO_TXT__CANT_FIND_INTRO], MSG_BOX_FLAG_OK, CDromEjectionErrorMessageBoxCallBack ); + DoScreenIndependantMessageBox( gzIntroScreen[INTRO_TXT__CANT_FIND_INTRO], MSG_BOX_FLAG_OK, CDromEjectionErrorMessageBoxCallBack ); #endif + } } } } @@ -485,9 +650,12 @@ void StartPlayingIntroFlic( INT32 iIndexOfFlicToPlay ) void SetIntroType( INT8 bIntroType ) { - if( bIntroType == INTRO_BEGINING ) +#ifdef LUA_INTRO + LuaIntro(2, 0, bIntroType, 0); +#else + if( bIntroType == INTRO_BEGINNING ) { - gbIntroScreenMode = INTRO_BEGINING; + gbIntroScreenMode = INTRO_BEGINNING; } else if( bIntroType == INTRO_ENDING ) { @@ -497,58 +665,53 @@ void SetIntroType( INT8 bIntroType ) { gbIntroScreenMode = INTRO_SPLASH; } +#endif } void DisplaySirtechSplashScreen() { - HVOBJECT hPixHandle; - VOBJECT_DESC VObjectDesc; - UINT32 uiLogoID; - - UINT32 uiDestPitchBYTES; - UINT8 *pDestBuf; - - // CLEAR THE FRAME BUFFER - pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES ); + UINT32 uiDestPitchBYTES; + UINT8* pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES ); memset(pDestBuf, 0, SCREEN_HEIGHT * uiDestPitchBYTES ); UnLockVideoSurface( FRAME_BUFFER ); - + VOBJECT_DESC VObjectDesc; memset( &VObjectDesc, 0, sizeof( VOBJECT_DESC ) ); VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\SirtechSplash.sti", VObjectDesc.ImageFile); - // FilenameForBPP("INTERFACE\\TShold.sti", VObjectDesc.ImageFile); + + UINT32 uiLogoID; if( !AddVideoObject(&VObjectDesc, &uiLogoID) ) { FilenameForBPP("GERMAN\\SPLASH_GERMAN.sti", VObjectDesc.ImageFile); - if( !AddVideoObject(&VObjectDesc, &uiLogoID) ) - { - /* - * This is the place, where most non english coders stranding. - * Don't hesitate, don't give up! - * I'll now tell You what You made wrong - * (2006-10-10, Sergeant_Kolja) - */ - #ifdef _DEBUG - # if defined(ENGLISH) - AssertMsg( 0, String( "Wheter English nor German works. May be You built English - but have only German or other foreign Disk?" ) ); - # elif defined(GERMAN) - AssertMsg( 0, String( "Weder Englisch noch Deutsch geht. Deutsche Version kompiliert und mit englischer CDs gestartet? Das geht nicht!" ) ); - # endif - #endif - AssertMsg( 0, String( "Failed to load %s", VObjectDesc.ImageFile ) ); - return; - } + if( !AddVideoObject(&VObjectDesc, &uiLogoID) ) + { + /* + * This is the place, where most non english coders stranding. + * Don't hesitate, don't give up! + * I'll now tell You what You made wrong + * (2006-10-10, Sergeant_Kolja) + */ + #ifdef _DEBUG + # if defined(ENGLISH) + AssertMsg( 0, String( "Wheter English nor German works. May be You built English - but have only German or other foreign Disk?" ) ); + # elif defined(GERMAN) + AssertMsg( 0, String( "Weder Englisch noch Deutsch geht. Deutsche Version kompiliert und mit englischer CDs gestartet? Das geht nicht!" ) ); + # endif + #endif + AssertMsg( 0, String( "Failed to load %s", VObjectDesc.ImageFile ) ); + return; + } } + HVOBJECT hPixHandle; GetVideoObject(&hPixHandle, uiLogoID); BltVideoObject(FRAME_BUFFER, hPixHandle, 0,(SCREEN_WIDTH-640)/2, (SCREEN_HEIGHT-480)/2, VO_BLT_SRCTRANSPARENCY,NULL); DeleteVideoObjectFromIndex(uiLogoID); - InvalidateScreen(); RefreshScreen( NULL ); } diff --git a/Intro.h b/Intro.h index 15a5fd09..f2bfc56e 100644 --- a/Intro.h +++ b/Intro.h @@ -9,9 +9,9 @@ UINT32 IntroScreenInit( void ); //enums used for when the intro screen can come up, used with 'gbIntroScreenMode' -enum +enum EIntroType { - INTRO_BEGINING, //set when viewing the intro at the begining of the game + INTRO_BEGINNING, //set when viewing the intro at the begining of the game INTRO_ENDING, //set when viewing the end game video. INTRO_SPLASH, @@ -22,5 +22,9 @@ extern UINT32 guiSmackerSurface; void SetIntroType( INT8 bIntroType ); +extern void DisplaySirtechSplashScreen(); +extern UINT32 guiIntroExitScreen; +extern BOOLEAN gfIntroScreenExit; +extern INT8 gbIntroScreenMode; #endif \ No newline at end of file diff --git a/JA2 Splash.cpp b/JA2 Splash.cpp index a933de6f..8debb31a 100644 --- a/JA2 Splash.cpp +++ b/JA2 Splash.cpp @@ -24,39 +24,39 @@ void InitJA2SplashScreen() UINT32 uiLogoID = 0; HVSURFACE hVSurface; // unused jonathanl // lalien reenabled for international versions VSURFACE_DESC VSurfaceDesc; //unused jonathanl // lalien reenabled for international versions - #ifdef JA2TESTVERSION - INT32 i = 0; +# ifdef JA2TESTVERSION + INT32 i = 0; + + memset( &VSurfaceDesc, 0, sizeof( VSURFACE_DESC ) ); + VSurfaceDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE; + sprintf( VSurfaceDesc.ImageFile, "LOADSCREENS\\Notification.sti" ); + if( !AddVideoSurface( &VSurfaceDesc, &uiLogoID ) ) + { + //AssertMsg( 0, String( "Failed to load %s", VSurfaceDesc.ImageFile ) ); + return; + } + GetVideoSurface(&hVSurface, uiLogoID ); + //BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, 0, 0, 0, NULL ); + BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, iScreenWidthOffset, iScreenHeightOffset, 0, NULL ); + DeleteVideoSurfaceFromIndex( uiLogoID ); + + + InvalidateScreen(); + RefreshScreen( NULL ); + + guiSplashStartTime = GetJA2Clock(); + while( i < 60 * 15 )//guiSplashStartTime + 15000 > GetJA2Clock() ) + { + //Allow the user to pick his bum. + InvalidateScreen(); + RefreshScreen( NULL ); + i++; + } +# endif // JA2TESTVERSION memset( &VSurfaceDesc, 0, sizeof( VSURFACE_DESC ) ); VSurfaceDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE; - sprintf( VSurfaceDesc.ImageFile, "LOADSCREENS\\Notification.sti" ); - if( !AddVideoSurface( &VSurfaceDesc, &uiLogoID ) ) - { - //AssertMsg( 0, String( "Failed to load %s", VSurfaceDesc.ImageFile ) ); - return; - } - GetVideoSurface(&hVSurface, uiLogoID ); - //BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, 0, 0, 0, NULL ); - BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, iScreenWidthOffset, iScreenHeightOffset, 0, NULL ); - DeleteVideoSurfaceFromIndex( uiLogoID ); - - - InvalidateScreen(); - RefreshScreen( NULL ); - - guiSplashStartTime = GetJA2Clock(); - while( i < 60 * 15 )//guiSplashStartTime + 15000 > GetJA2Clock() ) - { - //Allow the user to pick his bum. - InvalidateScreen(); - RefreshScreen( NULL ); - i++; - } -#endif - - memset( &VSurfaceDesc, 0, sizeof( VSURFACE_DESC ) ); - VSurfaceDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE; - GetMLGFilename( VSurfaceDesc.ImageFile, MLG_SPLASH ); + GetMLGFilename( VSurfaceDesc.ImageFile, MLG_SPLASH ); try { if( !AddVideoSurface( &VSurfaceDesc, &uiLogoID ) ) @@ -65,15 +65,15 @@ void InitJA2SplashScreen() return; } } - catch(CBasicException &ex) + catch(std::exception &ex) { - RETHROWEXCEPTION(L"Failed loading splash screen", &ex); + SGP_RETHROW(L"Failed loading splash screen", ex); } - GetVideoSurface( &hVSurface, uiLogoID ); - BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, iScreenWidthOffset, iScreenHeightOffset, 0, NULL ); - DeleteVideoSurfaceFromIndex( uiLogoID ); - #endif + GetVideoSurface( &hVSurface, uiLogoID ); + BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, iScreenWidthOffset, iScreenHeightOffset, 0, NULL ); + DeleteVideoSurfaceFromIndex( uiLogoID ); +#endif // ENGLISH InvalidateScreen(); RefreshScreen( NULL ); diff --git a/Language Defines.h b/Language Defines.h index 179fce0d..e69af8d2 100644 --- a/Language Defines.h +++ b/Language Defines.h @@ -37,7 +37,11 @@ #endif - +//**ddd direct link libraries +#pragma comment (lib, "user32.lib") +#pragma comment (lib, "gdi32.lib") +#pragma comment (lib, "advapi32.lib") +#pragma comment (lib, "shell32.lib") /* ==================================================================== * Regardless of if we did it Workspace wide or by uncommenting above, diff --git a/Laptop/AimFacialIndex.cpp b/Laptop/AimFacialIndex.cpp index 1874c481..8085cd03 100644 --- a/Laptop/AimFacialIndex.cpp +++ b/Laptop/AimFacialIndex.cpp @@ -23,12 +23,15 @@ extern UINT8 gbCurrentIndex; UINT32 guiMugShotBorder; -UINT32 guiAimFiFace[ MAX_NUMBER_MERCS ]; +UINT32 guiAimFiFace[ NUM_PROFILES ]; //MAX_NUMBER_MERCS +BOOLEAN gAimProfiles[ NUM_PROFILES ]; +#define AIM_FI_NUM_MUGSHOTS_X 8 +#define AIM_FI_NUM_MUGSHOTS_Y 5 -#define AIM_FI_NUM_MUHSHOTS_X 8 -#define AIM_FI_NUM_MUHSHOTS_Y 5 +UINT8 START_MERC =0; +UINT8 END_MERC =0; #define AIM_FI_PORTRAIT_WIDTH 52 #define AIM_FI_PORTRAIT_HEIGHT 48 @@ -46,6 +49,9 @@ UINT32 guiAimFiFace[ MAX_NUMBER_MERCS ]; #define AIM_FI_MEMBER_TEXT_X IMAGE_OFFSET_X + 155 #define AIM_FI_MEMBER_TEXT_Y AIM_SYMBOL_Y + AIM_SYMBOL_SIZE_Y + 1 #define AIM_FI_MEMBER_TEXT_WIDTH 190 +//tais: nsgi, move member text up +#define AIM_FI_MEMBER_TEXT_Y_NSGI AIM_SYMBOL_SMALL_Y + 35 + #define AIM_FI_AWAY_TEXT_OFFSET_X 3 #define AIM_FI_AWAY_TEXT_OFFSET_Y 23//3//36 @@ -55,7 +61,7 @@ UINT32 guiAimFiFace[ MAX_NUMBER_MERCS ]; //Mouse Regions //Face regions -MOUSE_REGION gMercFaceMouseRegions[ MAX_NUMBER_MERCS ]; +MOUSE_REGION gMercFaceMouseRegions[ NUM_PROFILES ]; //MAX_NUMBER_MERCS void SelectMercFaceRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ); void SelectMercFaceMoveRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ); @@ -66,12 +72,74 @@ void SelectScreenRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ); BOOLEAN DrawMercsFaceToScreen(UINT8 ubMercID, UINT16 usPosX, UINT16 usPosY, UINT8 ubImage); +//New profiles +INT32 guiPreviousNewProfilesNextButtonImage; +void BtnNewProfilesButtonCallback(GUI_BUTTON *btn,INT32 reason); + +INT32 PAGE_BUTTON; void GameInitAimFacialIndex() { } +/// Calculates the needed string for the page button based on number of mercs +/// and currently displayed page. +static STR16 GetPageButtonText() +{ + const int MERCS_PER_PAGE = AIM_FI_NUM_MUGSHOTS_X * AIM_FI_NUM_MUGSHOTS_Y; + + int baseTextIndex; + // Display three pages of mercs (strings from gszAimPages[2] to gszAimPages[4]) + if (MAX_NUMBER_MERCS > MERCS_PER_PAGE * 2) + baseTextIndex = 2; + // Display two pages of mercs (strings from gszAimPages[0] to gszAimPages[1]) + else if (MAX_NUMBER_MERCS > MERCS_PER_PAGE) + { + Assert(START_MERC < MERCS_PER_PAGE * 2); + baseTextIndex = 0; + } + // Display one page of mercs (string gszAimPages[5]) + else + { + Assert(START_MERC < MERCS_PER_PAGE); + baseTextIndex = 5; + } + + int currentPage = START_MERC / MERCS_PER_PAGE; + int stringIndex = baseTextIndex + currentPage; + return gszAimPages[ stringIndex ]; +} + +void BtnNewProfilesButtonCallback(GUI_BUTTON *btn,INT32 reason) +{ +UINT32 i; + + for(i=0; i 80 ) + START_MERC = 80; + else + START_MERC = 0; + } + else + { + START_MERC = 0; + } + + ExitAimFacialIndex(); + EnterAimFacialIndex(); +} + BOOLEAN EnterAimFacialIndex() { VOBJECT_DESC VObjectDesc; @@ -79,41 +147,66 @@ BOOLEAN EnterAimFacialIndex() UINT16 usPosX, usPosY, x,y; STR sFaceLoc = "FACES\\"; char sTemp[100]; + + UINT8 p = 0; + + for(i=0; i 40 ) + { + ShowButton( PAGE_BUTTON ); + } + else + { + HideButton( PAGE_BUTTON ); + } DrawAimDefaults(); @@ -175,21 +286,25 @@ BOOLEAN RenderAimFacialIndex() else swprintf(sString, AimFiText[ AIM_FI_AIM_MEMBERS_SORTED_DESCENDING ], AimFiText[gubCurrentSortMode] ); - DrawTextToScreen(sString, AIM_FI_MEMBER_TEXT_X, AIM_FI_MEMBER_TEXT_Y, AIM_FI_MEMBER_TEXT_WIDTH, AIM_MAINTITLE_FONT, AIM_MAINTITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - + if(gGameExternalOptions.gfUseNewStartingGearInterface) DrawTextToScreen(sString, AIM_FI_MEMBER_TEXT_X, AIM_FI_MEMBER_TEXT_Y_NSGI, AIM_FI_MEMBER_TEXT_WIDTH, AIM_MAINTITLE_FONT, AIM_MAINTITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + else DrawTextToScreen(sString, AIM_FI_MEMBER_TEXT_X, AIM_FI_MEMBER_TEXT_Y, AIM_FI_MEMBER_TEXT_WIDTH, AIM_MAINTITLE_FONT, AIM_MAINTITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + //Draw the mug shot border and face usPosX = AIM_FI_FIRST_MUGSHOT_X; usPosY = AIM_FI_FIRST_MUGSHOT_Y; i=0; - for(y=0; yuiFlags &= (~BUTTON_CLICKED_ON ); @@ -277,6 +401,8 @@ void SelectMercFaceMoveRegionCallBack(MOUSE_REGION * pRegion, INT32 reason ) DrawMercsFaceToScreen(ubMercNum, usPosX, usPosY, 0); InvalidateRegion(pRegion->RegionTopLeftX, pRegion->RegionTopLeftY, pRegion->RegionBottomRightX, pRegion->RegionBottomRightY); } + + } } BOOLEAN DrawMercsFaceToScreen(UINT8 ubMercID, UINT16 usPosX, UINT16 usPosY, UINT8 ubImage) @@ -285,7 +411,10 @@ BOOLEAN DrawMercsFaceToScreen(UINT8 ubMercID, UINT16 usPosX, UINT16 usPosY, UINT HVOBJECT hFaceHandle; SOLDIERTYPE *pSoldier=NULL; - pSoldier = FindSoldierByProfileID( AimMercArray[ubMercID], TRUE ); + //pSoldier = FindSoldierByProfileID( AimMercArray[ubMercID], TRUE ); + pSoldier = FindSoldierByProfileID( gAimAvailability[AimMercArray[ubMercID + START_MERC]].ProfilId, TRUE ); + + //Blt the portrait background @@ -296,7 +425,8 @@ BOOLEAN DrawMercsFaceToScreen(UINT8 ubMercID, UINT16 usPosX, UINT16 usPosY, UINT GetVideoObject(&hFaceHandle, guiAimFiFace[ubMercID]); BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,usPosX+AIM_FI_FACE_OFFSET, usPosY+AIM_FI_FACE_OFFSET, VO_BLT_SRCTRANSPARENCY,NULL); - if( IsMercDead( AimMercArray[ubMercID] ) ) + //if( IsMercDead( AimMercArray[ubMercID] ) ) + if( IsMercDead( gAimAvailability[AimMercArray[ubMercID + START_MERC]].ProfilId ) ) { //get the face object GetVideoObject(&hFaceHandle, guiAimFiFace[ubMercID]); @@ -315,7 +445,8 @@ BOOLEAN DrawMercsFaceToScreen(UINT8 ubMercID, UINT16 usPosX, UINT16 usPosY, UINT } //else if the merc is currently a POW or, the merc was fired as a pow - else if( gMercProfiles[ AimMercArray[ubMercID] ].bMercStatus == MERC_FIRED_AS_A_POW || ( pSoldier && pSoldier->bAssignment == ASSIGNMENT_POW ) ) + //else if( gMercProfiles[ AimMercArray[ubMercID] ].bMercStatus == MERC_FIRED_AS_A_POW || ( pSoldier && pSoldier->bAssignment == ASSIGNMENT_POW ) ) + else if( gMercProfiles[ gAimAvailability[AimMercArray[ubMercID + START_MERC]].ProfilId ].bMercStatus == MERC_FIRED_AS_A_POW || ( pSoldier && pSoldier->bAssignment == ASSIGNMENT_POW ) ) { ShadowVideoSurfaceRect( FRAME_BUFFER, usPosX+AIM_FI_FACE_OFFSET, usPosY+AIM_FI_FACE_OFFSET, usPosX + 48+AIM_FI_FACE_OFFSET, usPosY + 43+AIM_FI_FACE_OFFSET); DrawTextToScreen( pPOWStrings[0], (UINT16)(usPosX+AIM_FI_AWAY_TEXT_OFFSET_X), (UINT16)(usPosY+AIM_FI_AWAY_TEXT_OFFSET_Y), AIM_FI_AWAY_TEXT_OFFSET_WIDTH, FONT10ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); @@ -329,7 +460,8 @@ BOOLEAN DrawMercsFaceToScreen(UINT8 ubMercID, UINT16 usPosX, UINT16 usPosY, UINT } //if the merc is away, shadow his/her face and blit 'away' over top - else if( !IsMercHireable( AimMercArray[ubMercID] ) ) + //else if( !IsMercHireable( AimMercArray[ubMercID] ) ) + else if( !IsMercHireable( gAimAvailability[AimMercArray[ubMercID + START_MERC ]].ProfilId ) ) { ShadowVideoSurfaceRect( FRAME_BUFFER, usPosX+AIM_FI_FACE_OFFSET, usPosY+AIM_FI_FACE_OFFSET, usPosX + 48+AIM_FI_FACE_OFFSET, usPosY + 43+AIM_FI_FACE_OFFSET); DrawTextToScreen( AimFiText[AIM_FI_DEAD+1], (UINT16)(usPosX+AIM_FI_AWAY_TEXT_OFFSET_X), (UINT16)(usPosY+AIM_FI_AWAY_TEXT_OFFSET_Y), AIM_FI_AWAY_TEXT_OFFSET_WIDTH, FONT10ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); diff --git a/Laptop/AimFacialIndex.h b/Laptop/AimFacialIndex.h index 9bd4ae3b..02097374 100644 --- a/Laptop/AimFacialIndex.h +++ b/Laptop/AimFacialIndex.h @@ -4,6 +4,11 @@ #define AIM_FI_LEFT_CLICK_TEXT_X (SCREEN_WIDTH - 640) / 2 + 116 #define AIM_FI_LEFT_CLICK_TEXT_Y (SCREEN_HEIGHT - 480) / 2 + 35 + LAPTOP_SCREEN_WEB_DELTA_Y +//tais: nsgi, left click text moved a bit to create space for small logo +#define AIM_FI_LEFT_CLICK_TEXT_X_NSGI (SCREEN_WIDTH - 640) / 2 + 200 +#define AIM_FI_LEFT_CLICK_TEXT_Y_NSGI (SCREEN_HEIGHT - 480) / 2 + 35 + LAPTOP_SCREEN_WEB_DELTA_Y + + #define AIM_FI_CLICK_DESC_TEXT_Y_OFFSET 16 #define AIM_FI_RIGHT_CLICK_TEXT_X (SCREEN_WIDTH - 640) / 2 + 500 @@ -22,6 +27,8 @@ BOOLEAN RenderAimFacialIndex(); BOOLEAN DisplayAimFIMugShot(); +extern UINT8 START_MERC; + #endif diff --git a/Laptop/AimHistory.cpp b/Laptop/AimHistory.cpp index 267bf82d..8f737d5b 100644 --- a/Laptop/AimHistory.cpp +++ b/Laptop/AimHistory.cpp @@ -11,7 +11,7 @@ #include "Text.h" #endif - +#include "LocalizedStrings.h" // Defines @@ -171,7 +171,6 @@ void HandleAimHistory() void RenderAimHistory() { CHAR16 sText[400]; - UINT32 uiStartLoc=0; UINT16 usPosY; DrawAimDefaults(); @@ -210,8 +209,15 @@ void RenderAimHistory() // display coloniel Mohanned... usPosY = AIM_HISTORY_PARAGRAPH_Y + (GetFontHeight(AIM_HISTORY_TEXT_FONT) + 2)* 5 + LAPTOP_SCREEN_WEB_DELTA_Y; - uiStartLoc = AIM_HISTORY_LINE_SIZE * COLONEL_MOHANNED; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * COLONEL_MOHANNED; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", COLONEL_MOHANNED, sText, 400); + } DisplayWrappedString(AIM_HISTORY_PARAGRAPH_X, iScreenHeightOffset + 210+LAPTOP_SCREEN_WEB_DELTA_Y, AIM_HISTORY_PARAGRAPH_WIDTH, 2, AIM_HISTORY_TEXT_FONT, AIM_HISTORY_TEXT_COLOR, sText, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED); break; @@ -220,13 +226,27 @@ void RenderAimHistory() DisplayAimHistoryParagraph(INCORPORATION, 2); // display dunn and bradbord... - uiStartLoc = AIM_HISTORY_LINE_SIZE * DUNN_AND_BRADROAD; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * DUNN_AND_BRADROAD; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", DUNN_AND_BRADROAD, sText, 400); + } DisplayWrappedString(AIM_HISTORY_PARAGRAPH_X, iScreenHeightOffset + 270+LAPTOP_SCREEN_WEB_DELTA_Y, AIM_HISTORY_PARAGRAPH_WIDTH, 2, AIM_HISTORY_TEXT_FONT, AIM_HISTORY_TEXT_COLOR, sText, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED); //AIM_HISTORY_PARAGRAPH_Y - uiStartLoc = AIM_HISTORY_LINE_SIZE * INCORPORATION_3; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * INCORPORATION_3; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", INCORPORATION_3, sText, 400); + } DisplayWrappedString(AIM_HISTORY_PARAGRAPH_X, iScreenHeightOffset + 290+LAPTOP_SCREEN_WEB_DELTA_Y, AIM_HISTORY_PARAGRAPH_WIDTH, 2, AIM_HISTORY_TEXT_FONT, AIM_HISTORY_TEXT_COLOR, sText, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); break; } @@ -360,21 +380,34 @@ void SelectHistoryMenuButtonsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReaso BOOLEAN DisplayAimHistoryParagraph(UINT8 ubPageNum, UINT8 ubNumParagraphs) { CHAR16 sText[400]; - UINT32 uiStartLoc=0; UINT16 usPosY=0; UINT16 usNumPixels=0; //title - uiStartLoc = AIM_HISTORY_LINE_SIZE * ubPageNum; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * ubPageNum; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", ubPageNum, sText, 400); + } DrawTextToScreen(sText, AIM_HISTORY_PARAGRAPH_X, AIM_HISTORY_SUBTITLE_Y, 0, AIM_HISTORY_PARAGRAPH_TITLE_FONT, AIM_HISTORY_PARAGRAPH_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); if(ubNumParagraphs >= 1) { usPosY = AIM_HISTORY_PARAGRAPH_Y; //1st paragraph - uiStartLoc = AIM_HISTORY_LINE_SIZE * (ubPageNum + 1 ); - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * (ubPageNum + 1 ); + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", ubPageNum+1, sText, 400); + } usNumPixels = DisplayWrappedString(AIM_HISTORY_PARAGRAPH_X, usPosY, AIM_HISTORY_PARAGRAPH_WIDTH, 2, AIM_HISTORY_TEXT_FONT, AIM_HISTORY_TEXT_COLOR, sText, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); } @@ -382,8 +415,15 @@ BOOLEAN DisplayAimHistoryParagraph(UINT8 ubPageNum, UINT8 ubNumParagraphs) { //2nd paragraph usPosY += usNumPixels + AIM_HISTORY_SPACE_BETWEEN_PARAGRAPHS; - uiStartLoc = AIM_HISTORY_LINE_SIZE * (ubPageNum + 2 ); - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * (ubPageNum + 2 ); + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", ubPageNum+2, sText, 400); + } DisplayWrappedString(AIM_HISTORY_PARAGRAPH_X, usPosY, AIM_HISTORY_PARAGRAPH_WIDTH, 2, AIM_HISTORY_TEXT_FONT, AIM_HISTORY_TEXT_COLOR, sText, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); } @@ -391,9 +431,15 @@ BOOLEAN DisplayAimHistoryParagraph(UINT8 ubPageNum, UINT8 ubNumParagraphs) { //3rd paragraph usPosY += usNumPixels + AIM_HISTORY_SPACE_BETWEEN_PARAGRAPHS; - - uiStartLoc = AIM_HISTORY_LINE_SIZE * (ubPageNum + 3 ); - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * (ubPageNum + 3 ); + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", ubPageNum+3, sText, 400); + } DisplayWrappedString(AIM_HISTORY_PARAGRAPH_X, usPosY, AIM_HISTORY_PARAGRAPH_WIDTH, 2, AIM_HISTORY_TEXT_FONT, AIM_HISTORY_TEXT_COLOR, sText, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); } @@ -404,19 +450,18 @@ BOOLEAN DisplayAimHistoryParagraph(UINT8 ubPageNum, UINT8 ubNumParagraphs) BOOLEAN InitTocMenu() { - UINT16 i, usPosY; - UINT16 usHeight; - UINT16 usWidth=0; - UINT32 uiStartLoc=0; - CHAR16 sText[400]; - UINT8 ubLocInFile[]= - {IN_THE_BEGINNING, - THE_ISLAND_METAVIRA, - GUS_TARBALLS, - WORD_FROM_FOUNDER, - INCORPORATION}; + UINT16 i, usPosY; + UINT16 usHeight; + UINT16 usWidth=0; + CHAR16 sText[400]; + UINT8 ubLocInFile[] = { + IN_THE_BEGINNING, + THE_ISLAND_METAVIRA, + GUS_TARBALLS, + WORD_FROM_FOUNDER, + INCORPORATION}; - HVOBJECT hContentButtonHandle; + HVOBJECT hContentButtonHandle; GetVideoObject(&hContentButtonHandle, guiContentButton); @@ -424,9 +469,15 @@ BOOLEAN InitTocMenu() usPosY = AIM_HISTORY_CONTENTBUTTON_Y; for(i=0; i 2 ) + //if medical deposit is required + if( gMercProfiles[gbCurrentSoldier].bMedicalDeposit ) { - DisplayWrappedString( AIM_MEDICAL_DEPOSIT_X, (UINT16)(AIM_MEDICAL_DEPOSIT_Y - GetFontHeight( AIM_FONT12ARIAL ) ), AIM_MEDICAL_DEPOSIT_WIDTH, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + CHAR16 zTemp[40]; + CHAR16 sMedicalString[40]; + + // Display the medical cost + swprintf( zTemp, L"%d", gMercProfiles[ gbCurrentSoldier ].sMedicalDepositAmount ); + InsertCommasForDollarFigure( zTemp ); + InsertDollarSignInToString( zTemp ); + + swprintf( sMedicalString, L"%s %s", zTemp, CharacterInfo[AIM_MEMBER_MEDICAL_DEPOSIT_REQ] ); + + // If the string will be displayed in more then 2 lines, recenter the string + if( ( DisplayWrappedString( 0, 0, AIM_MEDICAL_DEPOSIT_WIDTH_NSGI, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ) / GetFontHeight( AIM_FONT12ARIAL ) ) > 2 ) + { + DisplayWrappedString( AIM_MEDICAL_DEPOSIT_X_NSGI, (UINT16)(AIM_MEDICAL_DEPOSIT_Y_NSGI - GetFontHeight( AIM_FONT12ARIAL ) ), AIM_MEDICAL_DEPOSIT_WIDTH_NSGI, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + } + else + DisplayWrappedString(AIM_MEDICAL_DEPOSIT_X_NSGI, AIM_MEDICAL_DEPOSIT_Y_NSGI, AIM_MEDICAL_DEPOSIT_WIDTH_NSGI, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + } + if(!g_bUseXML_Strings) + { + // LoadMercBioInfo( gbCurrentSoldier, MercInfoString, AdditionalInfoString); + if (gbCurrentSoldierBio != 255) + LoadMercBioInfo( gbCurrentSoldierBio, MercInfoString, AdditionalInfoString); + else + { + MercInfoString[0] = 0; + AdditionalInfoString[0] = 0; + } } else - DisplayWrappedString(AIM_MEDICAL_DEPOSIT_X, AIM_MEDICAL_DEPOSIT_Y, AIM_MEDICAL_DEPOSIT_WIDTH, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + { + Loc::GetString(Loc::AIM_BIOGRAPHY, L"Bio", gbCurrentSoldier, MercInfoString, SIZE_MERC_BIO_INFO); + Loc::GetString(Loc::AIM_BIOGRAPHY, L"Add", gbCurrentSoldier, AdditionalInfoString, SIZE_MERC_BIO_INFO); + } + if( MercInfoString[0] != 0) + { + DisplayWrappedString(AIM_MERC_INFO_X_NSGI, AIM_MERC_INFO_Y_NSGI, AIM_MERC_INFO_WIDTH_NSGI, 2, AIM_M_FONT_DYNAMIC_TEXT, AIM_FONT_MCOLOR_WHITE, MercInfoString, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + } + if( AdditionalInfoString[0] != 0) + { + DrawTextToScreen(CharacterInfo[AIM_MEMBER_ADDTNL_INFO], AIM_MERC_ADD_X_NSGI, AIM_MERC_ADD_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayWrappedString(AIM_MERC_ADD_INFO_X_NSGI, AIM_MERC_ADD_INFO_Y_NSGI, AIM_MERC_INFO_WIDTH_NSGI, 2, AIM_M_FONT_DYNAMIC_TEXT, AIM_FONT_MCOLOR_WHITE, AdditionalInfoString, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + } } - - LoadMercBioInfo( gbCurrentSoldier, MercInfoString, AdditionalInfoString); - if( MercInfoString[0] != 0) + else { - DisplayWrappedString(AIM_MERC_INFO_X, AIM_MERC_INFO_Y, AIM_MERC_INFO_WIDTH, 2, AIM_M_FONT_DYNAMIC_TEXT, AIM_FONT_MCOLOR_WHITE, MercInfoString, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - } - if( AdditionalInfoString[0] != 0) - { - DrawTextToScreen(CharacterInfo[AIM_MEMBER_ADDTNL_INFO], AIM_MERC_ADD_X, AIM_MERC_ADD_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayWrappedString(AIM_MERC_ADD_INFO_X, AIM_MERC_ADD_INFO_Y, AIM_MERC_INFO_WIDTH, 2, AIM_M_FONT_DYNAMIC_TEXT, AIM_FONT_MCOLOR_WHITE, AdditionalInfoString, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - } + //Display the salaries + DrawMoneyToScreen(gMercProfiles[gbCurrentSoldier].sSalary, FEE_WIDTH, FEE_X, HEALTH_Y, AIM_M_NUMBER_FONT, AIM_M_COLOR_DYNAMIC_TEXT ); + DrawMoneyToScreen(gMercProfiles[gbCurrentSoldier].uiWeeklySalary, FEE_WIDTH, FEE_X, AGILITY_Y, AIM_M_NUMBER_FONT, AIM_M_COLOR_DYNAMIC_TEXT ); + DrawMoneyToScreen(gMercProfiles[gbCurrentSoldier].uiBiWeeklySalary, FEE_WIDTH, FEE_X, DEXTERITY_Y, AIM_M_NUMBER_FONT, AIM_M_COLOR_DYNAMIC_TEXT ); + //if medical deposit is required + if( gMercProfiles[gbCurrentSoldier].bMedicalDeposit ) + { + CHAR16 zTemp[40]; + CHAR16 sMedicalString[40]; + + // Display the medical cost + swprintf( zTemp, L"%d", gMercProfiles[ gbCurrentSoldier ].sMedicalDepositAmount ); + InsertCommasForDollarFigure( zTemp ); + InsertDollarSignInToString( zTemp ); + + swprintf( sMedicalString, L"%s %s", zTemp, CharacterInfo[AIM_MEMBER_MEDICAL_DEPOSIT_REQ] ); + + // If the string will be displayed in more then 2 lines, recenter the string + if( ( DisplayWrappedString( 0, 0, AIM_MEDICAL_DEPOSIT_WIDTH, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ) / GetFontHeight( AIM_FONT12ARIAL ) ) > 2 ) + { + DisplayWrappedString( AIM_MEDICAL_DEPOSIT_X, (UINT16)(AIM_MEDICAL_DEPOSIT_Y - GetFontHeight( AIM_FONT12ARIAL ) ), AIM_MEDICAL_DEPOSIT_WIDTH, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + } + else + DisplayWrappedString(AIM_MEDICAL_DEPOSIT_X, AIM_MEDICAL_DEPOSIT_Y, AIM_MEDICAL_DEPOSIT_WIDTH, 2, AIM_FONT12ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, sMedicalString, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + } + if(!g_bUseXML_Strings) + { +// LoadMercBioInfo( gbCurrentSoldier, MercInfoString, AdditionalInfoString); + + if (gbCurrentSoldierBio != 255) + LoadMercBioInfo( gbCurrentSoldierBio, MercInfoString, AdditionalInfoString); + else + { + MercInfoString[0] = 0; + AdditionalInfoString[0] = 0; + } + + } + else + { + Loc::GetString(Loc::AIM_BIOGRAPHY, L"Bio", gbCurrentSoldier, MercInfoString, SIZE_MERC_BIO_INFO); + Loc::GetString(Loc::AIM_BIOGRAPHY, L"Add", gbCurrentSoldier, AdditionalInfoString, SIZE_MERC_BIO_INFO); + } + if( MercInfoString[0] != 0) + { + DisplayWrappedString(AIM_MERC_INFO_X, AIM_MERC_INFO_Y, AIM_MERC_INFO_WIDTH, 2, AIM_M_FONT_DYNAMIC_TEXT, AIM_FONT_MCOLOR_WHITE, MercInfoString, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + } + if( AdditionalInfoString[0] != 0) + { + DrawTextToScreen(CharacterInfo[AIM_MEMBER_ADDTNL_INFO], AIM_MERC_ADD_X, AIM_MERC_ADD_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayWrappedString(AIM_MERC_ADD_INFO_X, AIM_MERC_ADD_INFO_Y, AIM_MERC_INFO_WIDTH, 2, AIM_M_FONT_DYNAMIC_TEXT, AIM_FONT_MCOLOR_WHITE, AdditionalInfoString, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + } + } return(TRUE); } @@ -1214,94 +1558,186 @@ BOOLEAN LoadMercBioInfo(UINT8 ubIndex, STR16 pInfoString, STR16 pAddInfo) BOOLEAN DisplayMercsInventory(UINT8 ubMercID) { - UINT8 i; - INT16 PosX, PosY, sCenX, sCenY; + UINT8 i; + INT16 PosX, PosY, sCenX, sCenY; UINT16 usItem; INVTYPE *pItem; HVOBJECT hVObject; UINT32 usHeight, usWidth; - ETRLEObject *pTrav; + ETRLEObject *pTrav; CHAR16 gzItemName[ SIZE_ITEM_NAME ]; - UINT8 ubItemCount=0; -// UINT16 gzTempItemName[ SIZE_ITEM_INFO ]; - + UINT8 ubItemCount=0; + UINT8 ubColumnCount=0; //if the mercs inventory has already been purchased, dont display the inventory if( gMercProfiles[ ubMercID ].ubMiscFlags & PROFILE_MISC_FLAG_ALREADY_USED_ITEMS ) return( TRUE ); - UINT16 wnameY = AIM_MEMBER_WEAPON_NAME_Y; - PosX = WEAPONBOX_X+3; // + 3 ( 1 to take care of the shadow, +2 to get past the weapon box border ) - - PosY = WEAPONBOX_Y; - if(is_networked && guiCurrentLaptopMode == LAPTOP_MODE_MERC_FILES) - { - PosY-=30; - wnameY-=30; - - } - - - for(i=0; iubGraphicNum; - if(usGraphicNum < hVObject->usNumberOfObjects) + //tais: disable Weaponbox Mouseregions to stop crashing when changing kit selection and hovering over item + //tooltips for weaponbox + for(i=0;ipETRLEObject[ usGraphicNum ] ); + //increase the item count + ubItemCount++; + ubColumnCount++; + + pItem = &Item[ usItem ]; + GetVideoObject( &hVObject, GetInterfaceGraphicForItem( pItem ) ); + UINT16 usGraphicNum = g_bUsePngItemImages ? 0 : pItem->ubGraphicNum; + + if(usGraphicNum < hVObject->usNumberOfObjects) + { + pTrav = &(hVObject->pETRLEObject[ usGraphicNum ] ); + } + else + { + SGP_THROW(_BS(L"Number of images in VObject [") << hVObject->usNumberOfObjects + << L"] is smaller than the requested index [" << (int)pItem->ubGraphicNum << L"]" << _BS::wget); + } + + usHeight = (UINT32)pTrav->usHeight; + usWidth = (UINT32)pTrav->usWidth; + + sCenX = PosX + ( abs( WEAPONBOX_SIZE_X_NSGI - 3 - (int)usWidth ) / 2 ) - pTrav->sOffsetX; + sCenY = PosY + ( abs( WEAPONBOX_SIZE_Y_NSGI - (int)usHeight ) / 2 ) - pTrav->sOffsetY; + + //blt the shadow of the item + if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) + BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX-2, sCenY+2); + + //blt the item + BltVideoObjectOutlineFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX, sCenY, 0, FALSE ); + + //if there are more then 1 piece of equipment in the current slot, display how many there are + if( gMercProfiles[ubMercID].bInvNumber[ i ] > 1 ) + { + CHAR16 zTempStr[ 32 ]; + + swprintf( zTempStr, L"x%d", gMercProfiles[ ubMercID ].bInvNumber[ i ] ); + + DrawTextToScreen( zTempStr, (UINT16)(PosX-1), (UINT16)(PosY+20), AIM_MEMBER_WEAPON_NAME_WIDTH, AIM_M_FONT_DYNAMIC_TEXT, AIM_M_WEAPON_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED ); + } + + wcscpy( gzItemName, ShortItemNames[ usItem ] ); + SetRegionFastHelpText( &(gWeaponboxFasthelpRegion[ubItemCount-1]), gzItemName ); + SetRegionHelpEndCallback( &(gWeaponboxFasthelpRegion[ubItemCount-1]), HelpTextDoneCallback ); + MSYS_EnableRegion( &gWeaponboxFasthelpRegion[ubItemCount-1] ); + + // WANNE: In a multiplayer game also display the items name on the MERC website + if (is_networked && guiCurrentLaptopMode == LAPTOP_MODE_MERC_FILES) + { + //if this will only be a single line, center it in the box + if( ( DisplayWrappedString( (UINT16)(PosX-1), wnameY, AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ) / GetFontHeight( AIM_M_WEAPON_TEXT_FONT ) ) == 1 ) + DisplayWrappedString( (UINT16)(PosX-1), (UINT16)(wnameY+GetFontHeight( AIM_M_WEAPON_TEXT_FONT )/2), AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + else + DisplayWrappedString( (UINT16)(PosX-1), wnameY, AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + if(ubColumnCount == WEAPONBOX_COLUMNS) + { + PosX = WEAPONBOX_X_NSGI+3; + PosY += WEAPONBOX_SIZE_Y_NSGI; + ubColumnCount = 0; + } + else + { + PosX += WEAPONBOX_SIZE_X_NSGI; + } } - else + } + } + else + { + UINT16 wnameY = AIM_MEMBER_WEAPON_NAME_Y; + PosX = WEAPONBOX_X+3; // + 3 ( 1 to take care of the shadow, +2 to get past the weapon box border ) + PosY = WEAPONBOX_Y; + if(is_networked && guiCurrentLaptopMode == LAPTOP_MODE_MERC_FILES) + { + PosX+=20; + PosY-=28; + wnameY-=28; + } + + for(i=0; iusNumberOfObjects - << L"] is smaller than the requested index [" << (int)pItem->ubGraphicNum << L"]"; - THROWEXCEPTION(wss.str().c_str()); + //increase the item count + ubItemCount++; + + pItem = &Item[ usItem ]; + GetVideoObject( &hVObject, GetInterfaceGraphicForItem( pItem ) ); + UINT16 usGraphicNum = g_bUsePngItemImages ? 0 : pItem->ubGraphicNum; + if(usGraphicNum < hVObject->usNumberOfObjects) + { + pTrav = &(hVObject->pETRLEObject[ usGraphicNum ] ); + } + else + { + std::wstringstream wss; + wss << L"Number of images in VObject [" << hVObject->usNumberOfObjects + << L"] is smaller than the requested index [" << (int)pItem->ubGraphicNum << L"]"; + SGP_THROW(wss.str().c_str()); + } + + usHeight = (UINT32)pTrav->usHeight; + usWidth = (UINT32)pTrav->usWidth; + + sCenX = PosX + ( abs( WEAPONBOX_SIZE_X - 3 - (int)usWidth ) / 2 ) - pTrav->sOffsetX; + sCenY = PosY + ( abs( WEAPONBOX_SIZE_Y - (int)usHeight ) / 2 ) - pTrav->sOffsetY; + + //blt the shadow of the item + if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) + BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX-2, sCenY+2); + + //blt the item + BltVideoObjectOutlineFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX, sCenY, 0, FALSE ); + + //if there are more then 1 piece of equipment in the current slot, display how many there are + if( gMercProfiles[ubMercID].bInvNumber[ i ] > 1 ) + { + CHAR16 zTempStr[ 32 ]; + + swprintf( zTempStr, L"x%d", gMercProfiles[ ubMercID ].bInvNumber[ i ] ); + + DrawTextToScreen( zTempStr, (UINT16)(PosX-1), (UINT16)(PosY+20), AIM_MEMBER_WEAPON_NAME_WIDTH, AIM_M_FONT_DYNAMIC_TEXT, AIM_M_WEAPON_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED ); + } + + wcscpy( gzItemName, ShortItemNames[ usItem ] ); + + //if this will only be a single line, center it in the box + if( ( DisplayWrappedString( (UINT16)(PosX-1), wnameY, AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ) / GetFontHeight( AIM_M_WEAPON_TEXT_FONT ) ) == 1 ) + DisplayWrappedString( (UINT16)(PosX-1), (UINT16)(wnameY+GetFontHeight( AIM_M_WEAPON_TEXT_FONT )/2), AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + else + DisplayWrappedString( (UINT16)(PosX-1), wnameY, AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + PosX += WEAPONBOX_SIZE_X; } - - usHeight = (UINT32)pTrav->usHeight; - usWidth = (UINT32)pTrav->usWidth; - - sCenX = PosX + ( abs( WEAPONBOX_SIZE_X - 3 - usWidth ) / 2 ) - pTrav->sOffsetX; - sCenY = PosY + ( abs( WEAPONBOX_SIZE_Y - usHeight ) / 2 ) - pTrav->sOffsetY; - - //blt the shadow of the item - if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX-2, sCenY+2); - //blt the item - BltVideoObjectOutlineFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX, sCenY, 0, FALSE ); - - - //if there are more then 1 piece of equipment in the current slot, display how many there are - if( gMercProfiles[ubMercID].bInvNumber[ i ] > 1 ) - { - CHAR16 zTempStr[ 32 ]; -// UINT16 usWidthOfNumber; - - swprintf( zTempStr, L"x%d", gMercProfiles[ ubMercID ].bInvNumber[ i ] ); - - DrawTextToScreen( zTempStr, (UINT16)(PosX-1), (UINT16)(PosY+20), AIM_MEMBER_WEAPON_NAME_WIDTH, AIM_M_FONT_DYNAMIC_TEXT, AIM_M_WEAPON_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED ); - } - else - { - } - - wcscpy( gzItemName, ShortItemNames[ usItem ] ); - - //if this will only be a single line, center it in the box - if( ( DisplayWrappedString( (UINT16)(PosX-1), wnameY, AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ) / GetFontHeight( AIM_M_WEAPON_TEXT_FONT ) ) == 1 ) - DisplayWrappedString( (UINT16)(PosX-1), (UINT16)(wnameY+GetFontHeight( AIM_M_WEAPON_TEXT_FONT )/2), AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - else - DisplayWrappedString( (UINT16)(PosX-1), wnameY, AIM_MEMBER_WEAPON_NAME_WIDTH, 2, AIM_M_WEAPON_TEXT_FONT, AIM_M_WEAPON_TEXT_COLOR, gzItemName, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - - PosX += WEAPONBOX_SIZE_X; } } @@ -1309,10 +1745,168 @@ BOOLEAN DisplayMercsInventory(UINT8 ubMercID) } +//tais: nsgi, kit selection button callbacks one to five +void BtnWeaponboxSelectOneButtonCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + //tais: handle selected kit + WeaponKitSelectionUpdate(0); + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + gfRedrawScreen = TRUE; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + gubVideoConferencingMode = AIM_VIDEO_NOT_DISPLAYED_MODE; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + } + if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} + +void BtnWeaponboxSelectTwoButtonCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + //tais: handle selected kit + WeaponKitSelectionUpdate(1); + + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + gfRedrawScreen = TRUE; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + + gubVideoConferencingMode = AIM_VIDEO_NOT_DISPLAYED_MODE; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + } + if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} +void BtnWeaponboxSelectThreeButtonCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + //tais: handle selected kit + WeaponKitSelectionUpdate(2); + + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + gfRedrawScreen = TRUE; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + + gubVideoConferencingMode = AIM_VIDEO_NOT_DISPLAYED_MODE; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + } + if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} +void BtnWeaponboxSelectFourButtonCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + + //tais: handle selected kit + WeaponKitSelectionUpdate(3); + + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + gfRedrawScreen = TRUE; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + + gubVideoConferencingMode = AIM_VIDEO_NOT_DISPLAYED_MODE; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + } + if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} +void BtnWeaponboxSelectFiveButtonCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + + //tais: handle selected kit + WeaponKitSelectionUpdate(4); + + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + gfRedrawScreen = TRUE; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + + gubVideoConferencingMode = AIM_VIDEO_NOT_DISPLAYED_MODE; + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } + } + if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + } +} void BtnPreviousButtonCallback(GUI_BUTTON *btn,INT32 reason) { + +BOOLEAN Stop = FALSE; + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) { btn->uiFlags |= BUTTON_CLICKED_ON; @@ -1333,7 +1927,9 @@ void BtnPreviousButtonCallback(GUI_BUTTON *btn,INT32 reason) gfRedrawScreen = TRUE; - gbCurrentSoldier = AimMercArray[gbCurrentIndex]; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + gbCurrentSoldierBio = gAimAvailability[AimMercArray[gbCurrentIndex]].AimBio; gubVideoConferencingMode = AIM_VIDEO_NOT_DISPLAYED_MODE; InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); @@ -1382,6 +1978,9 @@ void BtnContactButtonCallback(GUI_BUTTON *btn,INT32 reason) void BtnNextButtonCallback(GUI_BUTTON *btn,INT32 reason) { + +BOOLEAN Stop = FALSE; + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) { btn->uiFlags |= BUTTON_CLICKED_ON; @@ -1394,12 +1993,15 @@ void BtnNextButtonCallback(GUI_BUTTON *btn,INT32 reason) btn->uiFlags &= (~BUTTON_CLICKED_ON ); InitCreateDeleteAimPopUpBox(AIM_POPUP_DELETE, NULL, NULL, 0, 0, 0); - if( gbCurrentIndex < MAX_NUMBER_MERCS-1 ) + if( gbCurrentIndex < MAX_NUMBER_MERCS -1 ) gbCurrentIndex++; else gbCurrentIndex = 0; - gbCurrentSoldier = AimMercArray[gbCurrentIndex]; +// gbCurrentSoldier = AimMercArray[gbCurrentIndex]; + gbCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; + + gbCurrentSoldierBio = gAimAvailability[AimMercArray[gbCurrentIndex]].AimBio; gfRedrawScreen = TRUE; @@ -1430,7 +2032,8 @@ BOOLEAN DisplayMercsFace() // Portrait Frame GetVideoObject(&hPortraitHandle, guiPortrait); - BltVideoObject(FRAME_BUFFER, hPortraitHandle, 0,PORTRAIT_X, PORTRAIT_Y, VO_BLT_SRCTRANSPARENCY,NULL); + if(gGameExternalOptions.gfUseNewStartingGearInterface) BltVideoObject(FRAME_BUFFER, hPortraitHandle, 0,PORTRAIT_X_NSGI, PORTRAIT_Y_NSGI, VO_BLT_SRCTRANSPARENCY,NULL); + else BltVideoObject(FRAME_BUFFER, hPortraitHandle, 0,PORTRAIT_X, PORTRAIT_Y, VO_BLT_SRCTRANSPARENCY,NULL); // load the Face graphic and add it if (gGameExternalOptions.fReadProfileDataFromXML) @@ -1446,51 +2049,100 @@ BOOLEAN DisplayMercsFace() FilenameForBPP(sTemp, VObjectDesc.ImageFile); CHECKF(AddVideoObject(&VObjectDesc, &guiFace)); - //Blt face to screen - GetVideoObject(&hFaceHandle, guiFace); - BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,FACE_X, FACE_Y, VO_BLT_SRCTRANSPARENCY,NULL); - - //if the merc is dead - if( IsMercDead( gbCurrentSoldier ) ) + if(gGameExternalOptions.gfUseNewStartingGearInterface) { - //shade the face red, (to signif that he is dead) - hFaceHandle->pShades[ 0 ] = Create16BPPPaletteShaded( hFaceHandle->pPaletteEntry, DEAD_MERC_COLOR_RED, DEAD_MERC_COLOR_GREEN, DEAD_MERC_COLOR_BLUE, TRUE ); - - //get the face object - GetVideoObject(&hFaceHandle, guiFace); - - //set the red pallete to the face - SetObjectHandleShade( guiFace, 0 ); - //Blt face to screen + GetVideoObject(&hFaceHandle, guiFace); + BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,FACE_X_NSGI, FACE_Y_NSGI, VO_BLT_SRCTRANSPARENCY,NULL); + + //if the merc is dead + if( IsMercDead( gbCurrentSoldier ) ) + { + //shade the face red, (to signif that he is dead) + hFaceHandle->pShades[ 0 ] = Create16BPPPaletteShaded( hFaceHandle->pPaletteEntry, DEAD_MERC_COLOR_RED, DEAD_MERC_COLOR_GREEN, DEAD_MERC_COLOR_BLUE, TRUE ); + + //get the face object + GetVideoObject(&hFaceHandle, guiFace); + + //set the red pallete to the face + SetObjectHandleShade( guiFace, 0 ); + + //Blt face to screen + BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,FACE_X_NSGI, FACE_Y_NSGI, VO_BLT_SRCTRANSPARENCY,NULL); + + //if the merc is dead, display it + DrawTextToScreen(AimPopUpText[AIM_MEMBER_DEAD], FACE_X_NSGI+1, FACE_Y_NSGI+107, FACE_WIDTH_NSGI, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + //else if the merc is currently a POW or, the merc was fired as a pow + else if( gMercProfiles[ gbCurrentSoldier ].bMercStatus == MERC_FIRED_AS_A_POW || ( pSoldier && pSoldier->bAssignment == ASSIGNMENT_POW ) ) + { + ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X_NSGI, FACE_Y_NSGI, FACE_X_NSGI + FACE_WIDTH_NSGI, FACE_Y_NSGI + FACE_HEIGHT_NSGI); + DrawTextToScreen( pPOWStrings[0], FACE_X_NSGI+1, FACE_Y_NSGI+107, FACE_WIDTH_NSGI, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + + //else if the merc has already been hired + else if( FindSoldierByProfileID( gbCurrentSoldier, TRUE ) ) + { + ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X_NSGI, FACE_Y_NSGI, FACE_X_NSGI + FACE_WIDTH_NSGI, FACE_Y_NSGI + FACE_HEIGHT_NSGI); + DrawTextToScreen( MercInfo[MERC_FILES_ALREADY_HIRED], FACE_X_NSGI+1, FACE_Y_NSGI+107, FACE_WIDTH_NSGI, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + else if( !IsMercHireable( gbCurrentSoldier ) ) + { + //else if the merc has a text file and the merc is not away + ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X_NSGI, FACE_Y_NSGI, FACE_X_NSGI + FACE_WIDTH_NSGI, FACE_Y_NSGI + FACE_HEIGHT_NSGI); + DrawTextToScreen(AimPopUpText[AIM_MEMBER_ON_ASSIGNMENT], FACE_X_NSGI+1, FACE_Y_NSGI+107, FACE_WIDTH_NSGI, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + } + else + { + //Blt face to screen + GetVideoObject(&hFaceHandle, guiFace); BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,FACE_X, FACE_Y, VO_BLT_SRCTRANSPARENCY,NULL); - //if the merc is dead, display it - DrawTextToScreen(AimPopUpText[AIM_MEMBER_DEAD], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + //if the merc is dead + if( IsMercDead( gbCurrentSoldier ) ) + { + //shade the face red, (to signif that he is dead) + hFaceHandle->pShades[ 0 ] = Create16BPPPaletteShaded( hFaceHandle->pPaletteEntry, DEAD_MERC_COLOR_RED, DEAD_MERC_COLOR_GREEN, DEAD_MERC_COLOR_BLUE, TRUE ); + + //get the face object + GetVideoObject(&hFaceHandle, guiFace); + + //set the red pallete to the face + SetObjectHandleShade( guiFace, 0 ); + + //Blt face to screen + BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,FACE_X, FACE_Y, VO_BLT_SRCTRANSPARENCY,NULL); + + //if the merc is dead, display it + DrawTextToScreen(AimPopUpText[AIM_MEMBER_DEAD], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + //else if the merc is currently a POW or, the merc was fired as a pow + else if( gMercProfiles[ gbCurrentSoldier ].bMercStatus == MERC_FIRED_AS_A_POW || ( pSoldier && pSoldier->bAssignment == ASSIGNMENT_POW ) ) + { + ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X, FACE_Y, FACE_X + FACE_WIDTH, FACE_Y + FACE_HEIGHT); + DrawTextToScreen( pPOWStrings[0], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + + //else if the merc has already been hired + else if( FindSoldierByProfileID( gbCurrentSoldier, TRUE ) ) + { + ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X, FACE_Y, FACE_X + FACE_WIDTH, FACE_Y + FACE_HEIGHT); + DrawTextToScreen( MercInfo[MERC_FILES_ALREADY_HIRED], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + + else if( !IsMercHireable( gbCurrentSoldier ) ) + { + //else if the merc has a text file and the merc is not away + ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X, FACE_Y, FACE_X + FACE_WIDTH, FACE_Y + FACE_HEIGHT); + DrawTextToScreen(AimPopUpText[AIM_MEMBER_ON_ASSIGNMENT], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } } - - //else if the merc is currently a POW or, the merc was fired as a pow - else if( gMercProfiles[ gbCurrentSoldier ].bMercStatus == MERC_FIRED_AS_A_POW || ( pSoldier && pSoldier->bAssignment == ASSIGNMENT_POW ) ) - { - ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X, FACE_Y, FACE_X + FACE_WIDTH, FACE_Y + FACE_HEIGHT); - DrawTextToScreen( pPOWStrings[0], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - } - - - //else if the merc has already been hired - else if( FindSoldierByProfileID( gbCurrentSoldier, TRUE ) ) - { - ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X, FACE_Y, FACE_X + FACE_WIDTH, FACE_Y + FACE_HEIGHT); - DrawTextToScreen( MercInfo[MERC_FILES_ALREADY_HIRED], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - } - - else if( !IsMercHireable( gbCurrentSoldier ) ) - { - //else if the merc has a text file and the merc is not away - ShadowVideoSurfaceRect( FRAME_BUFFER, FACE_X, FACE_Y, FACE_X + FACE_WIDTH, FACE_Y + FACE_HEIGHT); - DrawTextToScreen(AimPopUpText[AIM_MEMBER_ON_ASSIGNMENT], FACE_X+1, FACE_Y+107, FACE_WIDTH, FONT14ARIAL, 145, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - } - DeleteVideoObjectFromIndex(guiFace); return( TRUE ); @@ -1500,91 +2152,180 @@ BOOLEAN DisplayMercsFace() void DisplayMercStats() { UINT8 ubColor; + if(gGameExternalOptions.gfUseNewStartingGearInterface) + { + // + // Display all the static text + // - // - // Display all the static text - // + //First column in stats box. Health, Agility, dexterity, strength, leadership, wisdom + DrawTextToScreen(CharacterInfo[AIM_MEMBER_HEALTH], STATS_FIRST_COL_NSGI, HEALTH_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL_NSGI, HEALTH_Y_NSGI, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_HEALTH]); - //First column in stats box. Health, Agility, dexterity, strength, leadership, wisdom - DrawTextToScreen(CharacterInfo[AIM_MEMBER_HEALTH], STATS_FIRST_COL, HEALTH_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_FIRST_COL, HEALTH_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_HEALTH]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_AGILITY], STATS_FIRST_COL_NSGI, AGILITY_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL_NSGI, AGILITY_Y_NSGI, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_AGILITY]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_AGILITY], STATS_FIRST_COL, AGILITY_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_FIRST_COL, AGILITY_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_AGILITY]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_DEXTERITY], STATS_FIRST_COL_NSGI, DEXTERITY_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL_NSGI, DEXTERITY_Y_NSGI, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_DEXTERITY]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_DEXTERITY], STATS_FIRST_COL, DEXTERITY_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_FIRST_COL, DEXTERITY_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_DEXTERITY]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_STRENGTH], STATS_FIRST_COL_NSGI, STRENGTH_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL_NSGI, STRENGTH_Y_NSGI, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_STRENGTH]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_STRENGTH], STATS_FIRST_COL, STRENGTH_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_FIRST_COL, STRENGTH_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_STRENGTH]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_LEADERSHIP], STATS_FIRST_COL_NSGI, LEADERSHIP_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL_NSGI, LEADERSHIP_Y_NSGI, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_LEADERSHIP]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_LEADERSHIP], STATS_FIRST_COL, LEADERSHIP_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_FIRST_COL, LEADERSHIP_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_LEADERSHIP]); - - DrawTextToScreen(CharacterInfo[AIM_MEMBER_WISDOM], STATS_FIRST_COL, WISDOM_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_FIRST_COL, WISDOM_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_WISDOM]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_WISDOM], STATS_FIRST_COL_NSGI, WISDOM_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL_NSGI, WISDOM_Y_NSGI, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_WISDOM]); - //Second column in stats box. Exp.Level, Markmanship, mechanical, explosive, medical - DrawTextToScreen(CharacterInfo[AIM_MEMBER_EXP_LEVEL], STATS_SECOND_COL, EXPLEVEL_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - DisplayDots(STATS_SECOND_COL, EXPLEVEL_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_EXP_LEVEL]); + //Second column in stats box. Exp.Level, Markmanship, mechanical, explosive, medical + DrawTextToScreen(CharacterInfo[AIM_MEMBER_EXP_LEVEL], STATS_SECOND_COL_NSGI, EXPLEVEL_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL_NSGI, EXPLEVEL_Y_NSGI, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_EXP_LEVEL]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_MARKSMANSHIP], STATS_SECOND_COL, MARKSMAN_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT , FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - DisplayDots(STATS_SECOND_COL, MARKSMAN_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MARKSMANSHIP]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_MARKSMANSHIP], STATS_SECOND_COL_NSGI, MARKSMAN_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT , FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_SECOND_COL_NSGI, MARKSMAN_Y_NSGI, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MARKSMANSHIP]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_MECHANICAL], STATS_SECOND_COL, MECHANAICAL_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - DisplayDots(STATS_SECOND_COL, MECHANAICAL_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MECHANICAL]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_MECHANICAL], STATS_SECOND_COL_NSGI, MECHANAICAL_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL_NSGI, MECHANAICAL_Y_NSGI, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MECHANICAL]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_EXPLOSIVE], STATS_SECOND_COL, EXPLOSIVE_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - DisplayDots(STATS_SECOND_COL, EXPLOSIVE_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_EXPLOSIVE]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_EXPLOSIVE], STATS_SECOND_COL_NSGI, EXPLOSIVE_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL_NSGI, EXPLOSIVE_Y_NSGI, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_EXPLOSIVE]); - DrawTextToScreen(CharacterInfo[AIM_MEMBER_MEDICAL], STATS_SECOND_COL, MEDICAL_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - DisplayDots(STATS_SECOND_COL, MEDICAL_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MEDICAL]); + DrawTextToScreen(CharacterInfo[AIM_MEMBER_MEDICAL], STATS_SECOND_COL_NSGI, MEDICAL_Y_NSGI, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL_NSGI, MEDICAL_Y_NSGI, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MEDICAL]); - // - // Display all the Merc dynamic stat info - // + // + // Display all the Merc dynamic stat info + // - //Name - DrawTextToScreen(gMercProfiles[gbCurrentSoldier].zName, NAME_X, NAME_Y, 0, FONT14ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + //Name + DrawTextToScreen(gMercProfiles[gbCurrentSoldier].zName, NAME_X_NSGI, NAME_Y_NSGI, 0, FONT14ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - // Numbers for above. Health, Agility, dexterity, strength, leadership, wisdom + // Numbers for above. Health, Agility, dexterity, strength, leadership, wisdom - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bLife ); - DrawNumeralsToScreen( gMercProfiles[gbCurrentSoldier].bLife, 3, STATS_FIRST_NUM, HEALTH_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bLife ); + DrawNumeralsToScreen( gMercProfiles[gbCurrentSoldier].bLife, 3, STATS_FIRST_NUM_NSGI, HEALTH_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bAgility ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bAgility, 3, STATS_FIRST_NUM, AGILITY_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bAgility ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bAgility, 3, STATS_FIRST_NUM_NSGI, AGILITY_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bDexterity ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bDexterity, 3, STATS_FIRST_NUM, DEXTERITY_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bDexterity ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bDexterity, 3, STATS_FIRST_NUM_NSGI, DEXTERITY_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bStrength ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bStrength, 3, STATS_FIRST_NUM, STRENGTH_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bStrength ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bStrength, 3, STATS_FIRST_NUM_NSGI, STRENGTH_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bLeadership ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bLeadership, 3, STATS_FIRST_NUM, LEADERSHIP_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bLeadership ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bLeadership, 3, STATS_FIRST_NUM_NSGI, LEADERSHIP_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bWisdom ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bWisdom, 3, STATS_FIRST_NUM, WISDOM_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bWisdom ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bWisdom, 3, STATS_FIRST_NUM_NSGI, WISDOM_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - //Second column in stats box. Exp.Level, Markmanship, mechanical, explosive, medical + //Second column in stats box. Exp.Level, Markmanship, mechanical, explosive, medical -// ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bExpLevel ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bExpLevel, 3, STATS_SECOND_NUM, EXPLEVEL_Y, AIM_M_NUMBER_FONT, FONT_MCOLOR_WHITE ); + // ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bExpLevel ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bExpLevel, 3, STATS_SECOND_NUM_NSGI, EXPLEVEL_Y_NSGI, AIM_M_NUMBER_FONT, FONT_MCOLOR_WHITE ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMarksmanship ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMarksmanship, 3, STATS_SECOND_NUM, MARKSMAN_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMarksmanship ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMarksmanship, 3, STATS_SECOND_NUM_NSGI, MARKSMAN_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMechanical ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMechanical, 3, STATS_SECOND_NUM, MECHANAICAL_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMechanical ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMechanical, 3, STATS_SECOND_NUM_NSGI, MECHANAICAL_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bExplosive ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bExplosive, 3, STATS_SECOND_NUM, EXPLOSIVE_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bExplosive ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bExplosive, 3, STATS_SECOND_NUM_NSGI, EXPLOSIVE_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); - ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMedical ); - DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMedical, 3, STATS_SECOND_NUM, MEDICAL_Y, AIM_M_NUMBER_FONT, ubColor ); + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMedical ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMedical, 3, STATS_SECOND_NUM_NSGI, MEDICAL_Y_NSGI, AIM_M_NUMBER_FONT, ubColor ); + } + else + { + // + // Display all the static text + // + + //First column in stats box. Health, Agility, dexterity, strength, leadership, wisdom + DrawTextToScreen(CharacterInfo[AIM_MEMBER_HEALTH], STATS_FIRST_COL, HEALTH_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL, HEALTH_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_HEALTH]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_AGILITY], STATS_FIRST_COL, AGILITY_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL, AGILITY_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_AGILITY]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_DEXTERITY], STATS_FIRST_COL, DEXTERITY_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL, DEXTERITY_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_DEXTERITY]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_STRENGTH], STATS_FIRST_COL, STRENGTH_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL, STRENGTH_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_STRENGTH]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_LEADERSHIP], STATS_FIRST_COL, LEADERSHIP_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL, LEADERSHIP_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_LEADERSHIP]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_WISDOM], STATS_FIRST_COL, WISDOM_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_FIRST_COL, WISDOM_Y, FIRST_COLUMN_DOT, CharacterInfo[AIM_MEMBER_WISDOM]); + + + //Second column in stats box. Exp.Level, Markmanship, mechanical, explosive, medical + DrawTextToScreen(CharacterInfo[AIM_MEMBER_EXP_LEVEL], STATS_SECOND_COL, EXPLEVEL_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL, EXPLEVEL_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_EXP_LEVEL]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_MARKSMANSHIP], STATS_SECOND_COL, MARKSMAN_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT , FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + DisplayDots(STATS_SECOND_COL, MARKSMAN_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MARKSMANSHIP]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_MECHANICAL], STATS_SECOND_COL, MECHANAICAL_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL, MECHANAICAL_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MECHANICAL]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_EXPLOSIVE], STATS_SECOND_COL, EXPLOSIVE_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL, EXPLOSIVE_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_EXPLOSIVE]); + + DrawTextToScreen(CharacterInfo[AIM_MEMBER_MEDICAL], STATS_SECOND_COL, MEDICAL_Y, 0, AIM_M_FONT_STATIC_TEXT, AIM_M_COLOR_STATIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayDots(STATS_SECOND_COL, MEDICAL_Y, SECOND_COLUMN_DOT, CharacterInfo[AIM_MEMBER_MEDICAL]); + + + // + // Display all the Merc dynamic stat info + // + + //Name + DrawTextToScreen(gMercProfiles[gbCurrentSoldier].zName, NAME_X, NAME_Y, 0, FONT14ARIAL, AIM_M_COLOR_DYNAMIC_TEXT, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + + // Numbers for above. Health, Agility, dexterity, strength, leadership, wisdom + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bLife ); + DrawNumeralsToScreen( gMercProfiles[gbCurrentSoldier].bLife, 3, STATS_FIRST_NUM, HEALTH_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bAgility ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bAgility, 3, STATS_FIRST_NUM, AGILITY_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bDexterity ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bDexterity, 3, STATS_FIRST_NUM, DEXTERITY_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bStrength ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bStrength, 3, STATS_FIRST_NUM, STRENGTH_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bLeadership ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bLeadership, 3, STATS_FIRST_NUM, LEADERSHIP_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bWisdom ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bWisdom, 3, STATS_FIRST_NUM, WISDOM_Y, AIM_M_NUMBER_FONT, ubColor ); + + //Second column in stats box. Exp.Level, Markmanship, mechanical, explosive, medical + + // ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bExpLevel ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bExpLevel, 3, STATS_SECOND_NUM, EXPLEVEL_Y, AIM_M_NUMBER_FONT, FONT_MCOLOR_WHITE ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMarksmanship ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMarksmanship, 3, STATS_SECOND_NUM, MARKSMAN_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMechanical ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMechanical, 3, STATS_SECOND_NUM, MECHANAICAL_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bExplosive ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bExplosive, 3, STATS_SECOND_NUM, EXPLOSIVE_Y, AIM_M_NUMBER_FONT, ubColor ); + + ubColor = GetStatColor( gMercProfiles[gbCurrentSoldier].bMedical ); + DrawNumeralsToScreen(gMercProfiles[gbCurrentSoldier].bMedical, 3, STATS_SECOND_NUM, MEDICAL_Y, AIM_M_NUMBER_FONT, ubColor ); + } } UINT8 GetStatColor( INT8 bStat ) @@ -1695,7 +2436,8 @@ if (LaptopSaveInfo.iCurrentBalance == 4500001) { unsigned hired = 0; while (hired < gGameExternalOptions.ubGameMaximumNumberOfPlayerMercs) { if (AimMemberHireMerc()) { - giIdOfLastHiredMerc = AimMercArray[gbCurrentIndex]; +// giIdOfLastHiredMerc = AimMercArray[gbCurrentIndex]; + giIdOfLastHiredMerc = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; ++hired; } ++gbCurrentIndex; @@ -1739,7 +2481,8 @@ if (LaptopSaveInfo.iCurrentBalance == 4500001) { SpecifyDisabledButtonStyle( giBuyEquipmentButton[0], DISABLED_STYLE_NONE ); SpecifyDisabledButtonStyle( giBuyEquipmentButton[1], DISABLED_STYLE_NONE ); - giIdOfLastHiredMerc = AimMercArray[gbCurrentIndex]; +// giIdOfLastHiredMerc = AimMercArray[gbCurrentIndex]; + giIdOfLastHiredMerc = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; } } /* @@ -1773,7 +2516,8 @@ if (LaptopSaveInfo.iCurrentBalance == 4500001) { INT8 AimMemberHireMerc() { MERC_HIRE_STRUCT HireMercStruct; - UINT8 ubCurrentSoldier = AimMercArray[gbCurrentIndex]; +// UINT8 ubCurrentSoldier = AimMercArray[gbCurrentIndex]; + UINT8 ubCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; INT8 bReturnCode; INT16 sSoldierID=0; INT8 bTypeOfContract=0; @@ -1809,6 +2553,7 @@ INT8 AimMemberHireMerc() //if the players is buyibng the equipment if( gfBuyEquipment ) { + gMercProfiles[ ubCurrentSoldier ].usOptionalGearCost = 0; gMercProfiles[ ubCurrentSoldier ].ubMiscFlags |= PROFILE_MISC_FLAG_ALREADY_USED_ITEMS; } @@ -3368,7 +4113,7 @@ BOOLEAN InitDeleteVideoConferencePopUp( ) if( gMercProfiles[gbCurrentSoldier].usOptionalGearCost == 0 ) DisableButton( giBuyEquipmentButton[1] ); - if(!ALLOW_EQUIP && is_networked) + if(!cAllowMercEquipment && is_networked) { gfBuyEquipment = FALSE; DisableButton( giBuyEquipmentButton[0] ); @@ -4201,7 +4946,8 @@ BOOLEAN QuickHireMerc() { INT8 bReturnCode; MERC_HIRE_STRUCT HireMercStruct; - UINT8 ubCurrentSoldier = AimMercArray[gbCurrentIndex]; +// UINT8 ubCurrentSoldier = AimMercArray[gbCurrentIndex]; + UINT8 ubCurrentSoldier = gAimAvailability[AimMercArray[gbCurrentIndex]].ProfilId; giContractAmount = 0; @@ -4498,17 +5244,248 @@ void DisplayPopUpBoxExplainingMercArrivalLocationAndTimeCallBack( UINT8 bExitVal void DisplayAimMemberClickOnFaceHelpText() { - //display the 'left and right click' onscreen help msg - DrawTextToScreen( AimMemberText[0], AIM_FI_LEFT_CLICK_TEXT_X, AIM_FI_LEFT_CLICK_TEXT_Y, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_TITLE_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - DrawTextToScreen( AimMemberText[1], AIM_FI_LEFT_CLICK_TEXT_X, AIM_FI_LEFT_CLICK_TEXT_Y+AIM_FI_CLICK_DESC_TEXT_Y_OFFSET, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - + if(gGameExternalOptions.gfUseNewStartingGearInterface) + { + //display the 'left click' onscreen help msg a bit to the right + DrawTextToScreen( AimMemberText[0], AIM_FI_LEFT_CLICK_TEXT_X_NSGI, AIM_FI_LEFT_CLICK_TEXT_Y_NSGI, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_TITLE_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DrawTextToScreen( AimMemberText[1], AIM_FI_LEFT_CLICK_TEXT_X_NSGI, AIM_FI_LEFT_CLICK_TEXT_Y_NSGI+AIM_FI_CLICK_DESC_TEXT_Y_OFFSET, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + else + { + //display the 'left click' onscreen help msg + DrawTextToScreen( AimMemberText[0], AIM_FI_LEFT_CLICK_TEXT_X, AIM_FI_LEFT_CLICK_TEXT_Y, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_TITLE_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DrawTextToScreen( AimMemberText[1], AIM_FI_LEFT_CLICK_TEXT_X, AIM_FI_LEFT_CLICK_TEXT_Y+AIM_FI_CLICK_DESC_TEXT_Y_OFFSET, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + //display the 'right click' onscreen help msg DrawTextToScreen( AimMemberText[2], AIM_FI_RIGHT_CLICK_TEXT_X, AIM_FI_LEFT_CLICK_TEXT_Y, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_TITLE_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); DrawTextToScreen( AimMemberText[3], AIM_FI_RIGHT_CLICK_TEXT_X, AIM_FI_LEFT_CLICK_TEXT_Y+AIM_FI_CLICK_DESC_TEXT_Y_OFFSET, AIM_FI_CLICK_TEXT_WIDTH, AIM_FI_HELP_FONT, AIM_FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); } +void CreateWeaponBoxMouseRegions() +{ + UINT16 i, x, uiPosX, uiPosY; + UINT16 itemcounter = 0; + //tais: Weaponbox Mouseregions + for(i=0; i 1) { + if(buttonEnabled[0] == TRUE) ShowButton(giWeaponboxSelectionButtonOne); + if(buttonEnabled[1] == TRUE) ShowButton(giWeaponboxSelectionButtonTwo); + if(buttonEnabled[2] == TRUE) ShowButton(giWeaponboxSelectionButtonThree); + if(buttonEnabled[3] == TRUE) ShowButton(giWeaponboxSelectionButtonFour); + if(buttonEnabled[4] == TRUE) ShowButton(giWeaponboxSelectionButtonFive); + } + } + } +} + +void WeaponKitSelectionUpdate(UINT8 selectedInventory = 0) +{ + UINT32 uiLoop; + INT16 usItem; + if(UsingNewInventorySystem() == true){ + // Start by resetting all profile inventory values to 0 + gMercProfiles[gbCurrentSoldier].clearInventory(); + gMercProfiles[gbCurrentSoldier].ubInvUndroppable = 0; + // Next, go through and assign everything but lbe gear + for(uiLoop=INV_START_POS; uiLoop 5) + gMercProfiles[gbCurrentSoldier].bInvNumber[uiLoop] = gMercProfileGear[gbCurrentSoldier][selectedInventory].iNumber[uiLoop]; + else + gMercProfiles[gbCurrentSoldier].bInvNumber[uiLoop] = 1; + } + } + // Last, go through and assign LBE items. Only needed for new inventory system + if((UsingNewInventorySystem() == true)) + { + for(uiLoop=0; uiLoop<5; uiLoop++) + { + UINT32 uiLoop2 = uiLoop + VESTPOCKPOS; + if(gMercProfileGear[gbCurrentSoldier][selectedInventory].lbe[uiLoop] != NONE){ + gMercProfiles[gbCurrentSoldier].inv[uiLoop2] = gMercProfileGear[gbCurrentSoldier][selectedInventory].lbe[uiLoop]; + gMercProfiles[gbCurrentSoldier].bInvStatus[uiLoop2] = gMercProfileGear[gbCurrentSoldier][selectedInventory].lStatus[uiLoop]; + gMercProfiles[gbCurrentSoldier].bInvNumber[uiLoop2] = 1; + } + } + } + } + gMercProfiles[gbCurrentSoldier].bMainGunAttractiveness = -1; + gMercProfiles[gbCurrentSoldier].bArmourAttractiveness = -1; + + for ( uiLoop = 0; uiLoop < gMercProfiles[gbCurrentSoldier].inv.size(); uiLoop++ ) + { + usItem = gMercProfiles[gbCurrentSoldier].inv[ uiLoop ]; + + if ( usItem != NOTHING ) + { + // Check if it's a gun + if ( Item[ usItem ].usItemClass & IC_GUN ) + { + gMercProfiles[gbCurrentSoldier].bMainGunAttractiveness = Weapon[ usItem ].ubDeadliness; + } + + // If it's armour + if ( Item[ usItem ].usItemClass & IC_ARMOUR ) + { + gMercProfiles[gbCurrentSoldier].bArmourAttractiveness = min(128,Armour[ Item[ usItem ].ubClassIndex ].ubProtection); + } + } + } + gMercProfiles[ gbCurrentSoldier ].usOptionalGearCost = 0; + UINT16 tempGearCost = 0; + for ( uiLoop = 0; uiLoop< gMercProfiles[ gbCurrentSoldier ].inv.size(); uiLoop++ ) + { + if ( gMercProfiles[ gbCurrentSoldier ].inv[ uiLoop ] != NOTHING ) + { + //get the item + usItem = gMercProfiles[ gbCurrentSoldier ].inv[ uiLoop ]; + + //add the cost + tempGearCost += Item[ usItem ].usPrice; + } + } + //tais: added optional price modifier for gearkits, reads the xml tag mPriceMod from MercStartingGear.xml + if(gMercProfileGear[gbCurrentSoldier][selectedInventory].PriceModifier != 0 && + gMercProfileGear[gbCurrentSoldier][selectedInventory].PriceModifier <= 200 && + gMercProfileGear[gbCurrentSoldier][selectedInventory].PriceModifier >= -100) + { + FLOAT mod; + mod = (FLOAT) (gMercProfileGear[gbCurrentSoldier][selectedInventory].PriceModifier + 100) / 100; + gMercProfiles[ gbCurrentSoldier ].usOptionalGearCost = (UINT16)(tempGearCost * mod); + } + else + { + gMercProfiles[ gbCurrentSoldier ].usOptionalGearCost = tempGearCost; + } +} diff --git a/Laptop/AimPolicies.cpp b/Laptop/AimPolicies.cpp index 5f7c912f..2fa45060 100644 --- a/Laptop/AimPolicies.cpp +++ b/Laptop/AimPolicies.cpp @@ -9,8 +9,11 @@ #include "WordWrap.h" #include "Encrypted File.h" #include "Text.h" + #include "GameSettings.h" #endif +#include "LocalizedStrings.h" + #define NUM_AIM_POLICY_PAGES 11 #define NUM_AIM_POLICY_TOC_BUTTONS 9 #define AIMPOLICYFILE "BINARYDATA\\AimPol.edt" @@ -38,6 +41,9 @@ #define AIM_POLICY_TITLE_Y AIM_SYMBOL_Y + AIM_SYMBOL_SIZE_Y + 11 #define AIM_POLICY_TITLE_WIDTH AIM_SYMBOL_WIDTH +//tais: nsgi, move title up +#define AIM_POLICY_TITLE_Y_NSGI AIM_SYMBOL_Y + 35 + #define AIM_POLICY_TITLE_STATEMENT_WIDTH 300 #define AIM_POLICY_TITLE_STATEMENT_X IMAGE_OFFSET_X + (500 - AIM_POLICY_TITLE_STATEMENT_WIDTH) / 2 +5//80 #define AIM_POLICY_TITLE_STATEMENT_Y AIM_SYMBOL_Y + AIM_SYMBOL_SIZE_Y + 75 @@ -456,21 +462,20 @@ BOOLEAN ExitAimPolicyMenuBar(void) BOOLEAN DrawAimPolicyMenu() { - UINT16 i, usPosY; - UINT16 usHeight; - UINT32 uiStartLoc=0; - CHAR16 sText[400]; - HVOBJECT hContentButtonHandle; - UINT8 ubLocInFile[]= - { DEFINITIONS, - LENGTH_OF_ENGAGEMENT, - LOCATION_0F_ENGAGEMENT, - CONTRACT_EXTENSIONS, - TERMS_OF_PAYMENT, - TERMS_OF_ENGAGEMENT, - ENGAGEMENT_TERMINATION, - EQUIPMENT_AND_INVENTORY, - POLICY_MEDICAL}; + UINT16 i, usPosY; + UINT16 usHeight; + CHAR16 sText[400]; + HVOBJECT hContentButtonHandle; + UINT8 ubLocInFile[]= { + DEFINITIONS, + LENGTH_OF_ENGAGEMENT, + LOCATION_0F_ENGAGEMENT, + CONTRACT_EXTENSIONS, + TERMS_OF_PAYMENT, + TERMS_OF_ENGAGEMENT, + ENGAGEMENT_TERMINATION, + EQUIPMENT_AND_INVENTORY, + POLICY_MEDICAL}; GetVideoObject(&hContentButtonHandle, guiContentButton); @@ -478,10 +483,16 @@ BOOLEAN DrawAimPolicyMenu() usPosY = AIM_POLICY_TOC_Y; for(i=0; iArea.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); + /////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Added ability to scroll forward 5 pages instead of one. + // This is done by holding down SHIFT while clicking. + // + //if previous screen if( bNewValue == BOBBYR_PREVIOUS_PAGE) { if( gubCurPage > 0 ) - gubCurPage--; + { + if (_KeyDown( 16 ) ) // SHIFT + { + gubCurPage = __max(gubCurPage - 5, 0); + } + else + { + gubCurPage--; + } + } } //else next screen else { if( gubCurPage < gubNumPages-1 ) - gubCurPage++; + { + if (_KeyDown( 16 ) ) // SHIFT + { + gubCurPage = __min(gubNumPages, gubCurPage+5); + } + else + { + gubCurPage++; + } + } } @@ -1736,10 +1763,11 @@ BOOLEAN DisplayAmmoInfo(UINT16 usIndex, UINT16 usTextPosY, BOOLEAN fUsed, UINT16 BOOLEAN DisplayBigItemImage(UINT16 usIndex, UINT16 PosY) { - INT16 PosX, sCenX, sCenY; - UINT32 usHeight, usWidth; + INT16 PosX, sCenX, sCenY; + UINT32 usHeight, usWidth; + INT32 sOffsetX, sOffsetY; ETRLEObject *pTrav; - INVTYPE *pItem; + INVTYPE *pItem; UINT32 uiImage; HVOBJECT hPixHandle; @@ -1749,20 +1777,43 @@ BOOLEAN DisplayBigItemImage(UINT16 usIndex, UINT16 PosY) LoadTileGraphicForItem(pItem, &uiImage); GetVideoObject(&hPixHandle, uiImage); - pTrav = &(hPixHandle->pETRLEObject[0]); - //center picture in frame - usHeight = (UINT32)pTrav->usHeight; - usWidth = (UINT32)pTrav->usWidth; + if(hPixHandle->ubBitDepth == 8) + { + pTrav = &(hPixHandle->pETRLEObject[ 0 ] ); + + //center picture in frame + usHeight = (UINT32)pTrav->usHeight; + usWidth = (UINT32)pTrav->usWidth; + sOffsetX = (INT32)pTrav->sOffsetX; + sOffsetY = (INT32)pTrav->sOffsetY; + } + else if(hPixHandle->ubBitDepth == 16 && hPixHandle->p16BPPObject) + { + usHeight = hPixHandle->p16BPPObject->usHeight; + usWidth = hPixHandle->p16BPPObject->usWidth; + sOffsetX = hPixHandle->p16BPPObject->sOffsetX; + sOffsetY = hPixHandle->p16BPPObject->sOffsetY; + } + else if(hPixHandle->ubBitDepth == 32) + { + usHeight = hPixHandle->p16BPPObject->usHeight; + usWidth = hPixHandle->p16BPPObject->usWidth; + sOffsetX = hPixHandle->p16BPPObject->sOffsetX; + sOffsetY = hPixHandle->p16BPPObject->sOffsetY; + } + // sCenX = PosX + ( abs( BOBBYR_GRID_PIC_WIDTH - usWidth ) / 2 ); // sCenY = PosY + 8; - sCenX = PosX + ( abs( BOBBYR_GRID_PIC_WIDTH - usWidth ) / 2 ) - pTrav->sOffsetX; + sCenX = PosX + ( abs( BOBBYR_GRID_PIC_WIDTH - (int)usWidth ) / 2 ) - sOffsetX; sCenY = PosY + 8; //blt the shadow of the item - if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, uiImage, 0, sCenX-2, sCenY+2);//pItem->ubGraphicNum - + if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) + { + BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, uiImage, 0, sCenX-2, sCenY+2);//pItem->ubGraphicNum + } BltVideoObject(FRAME_BUFFER, hPixHandle, 0, sCenX, sCenY, VO_BLT_SRCTRANSPARENCY,NULL); DeleteVideoObjectFromIndex(uiImage); @@ -1923,9 +1974,13 @@ UINT16 DisplayDamage(UINT16 usPosY, UINT16 usIndex, UINT16 usFontHeight) UINT16 DisplayRange(UINT16 usPosY, UINT16 usIndex, UINT16 usFontHeight) { CHAR16 sTemp[20]; + UINT16 gunRange = 0; DrawTextToScreen(BobbyRText[BOBBYR_GUNS_RANGE], BOBBYR_ITEM_WEIGHT_TEXT_X, (UINT16)usPosY, 0, BOBBYR_ITEM_DESC_TEXT_FONT, BOBBYR_STATIC_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - swprintf(sTemp, L"%3d %s", Weapon[ usIndex ].usRange, pMessageStrings[ MSG_METER_ABBREVIATION ] ); + + gunRange = (UINT16)GetModifiedGunRange( usIndex); + + swprintf(sTemp, L"%3d %s", gunRange, pMessageStrings[ MSG_METER_ABBREVIATION ] ); DrawTextToScreen(sTemp, BOBBYR_ITEM_WEIGHT_NUM_X, (UINT16)usPosY, BOBBYR_ITEM_WEIGHT_NUM_WIDTH, BOBBYR_ITEM_DESC_TEXT_FONT, BOBBYR_ITEM_DESC_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED); usPosY += usFontHeight + 2; return(usPosY); @@ -2417,6 +2472,7 @@ void CreateMouseRegionForBigImage( UINT16 usPosY, UINT8 ubCount, INT16 *pItemNum //UINT16 gunDamage = (UINT16)( Weapon[ pItemNumbers[ i ] ].ubImpact + ( (double) Weapon[ pItemNumbers[ i ] ].ubImpact / 100) * gGameExternalOptions.ubGunDamageMultiplier ); UINT16 gunDamage = (UINT16)GetModifiedGunDamage( Weapon[ pItemNumbers[ i ] ].ubImpact ); UINT16 readyAPs = (UINT16)(( Weapon[ pItemNumbers[ i ] ].ubReadyTime * (100 - Item[ pItemNumbers[ i ] ].percentreadytimeapreduction)) / 100); + UINT16 gunRange = (UINT16)GetModifiedGunRange(pItemNumbers[ i ]); //Calculate AP's CHAR16 apStr[20]; @@ -2504,18 +2560,48 @@ void CreateMouseRegionForBigImage( UINT16 usPosY, UINT8 ubCount, INT16 *pItemNum wcscat( attachStr, attachStr3 ); } } + + //Sum up default attachments. + BOOLEAN fFoundDefault = FALSE; + swprintf( attachStr2, L"" ); + swprintf( attachStr3, L"" ); + for(UINT8 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS; cnt++){ + if(Item[pItemNumbers[ i ]].defaultattachments[cnt] != 0){ + if (wcslen( attachStr ) + wcslen(attachStr3) + wcslen(Item[ Item[pItemNumbers[ i ]].defaultattachments[cnt] ].szItemName) > 3800) + { + // End list early to avoid stack overflow + wcscat( attachStr3, L"\n..." ); + break; + } + fFoundDefault = TRUE; + swprintf( attachStr2, L"\n%s", Item[ Item[pItemNumbers[ i ]].defaultattachments[cnt] ].szItemName ); + wcscat( attachStr3, attachStr2 ); + } else { + //If we found an empty entry, we can assume the rest will be empty too. + break; + } + } + if(fFoundDefault){ + //Found at least one default attachment, write it to the attachment string. + CHAR16 defaultStr[50]; + swprintf( defaultStr, L"\n \n%s", gWeaponStatsDesc[ 17 ] ); + wcscat( attachStr, defaultStr ); + wcscat( attachStr, attachStr3 ); + } + // HEADROCK HAM 3: Added last string (attachStr), for display of the possible attachment list. // If the feature is deactivated, the attachStr will simply be empty at this point // (remember? we emptied it earlier!). + INT8 accuracy = (UsingNewCTHSystem()==true?Weapon[ pItemNumbers[ i ] ].nAccuracy:Weapon[ pItemNumbers[ i ] ].bAccuracy); swprintf( pStr, L"%s (%s)\n%s %d\n%s %d\n%s %d\n%s (%d) %s\n%s %1.1f %s%s", ItemNames[ pItemNumbers[ i ] ], AmmoCaliber[ Weapon[ pItemNumbers[ i ] ].ubCalibre ], gWeaponStatsDesc[ 9 ], //Accuracy String - Weapon[ pItemNumbers[ i ] ].bAccuracy, //Accuracy + accuracy, //Accuracy gWeaponStatsDesc[ 11 ], //Damage String gunDamage, //Gun damage gWeaponStatsDesc[ 10 ], //Range String - gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? Weapon[ pItemNumbers[ i ] ].usRange/10 : Weapon[ pItemNumbers[ i ] ].usRange, //Gun Range + gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? gunRange/10 : gunRange, //Gun Range gWeaponStatsDesc[ 6 ], //AP String readyAPs, apStr, //AP's @@ -2571,16 +2657,18 @@ void CreateMouseRegionForBigImage( UINT16 usPosY, UINT8 ubCount, INT16 *pItemNum { // HEADROCK HAM 3.6: Can now take a negative modifier. UINT16 gunDamage = (UINT16)GetModifiedGunDamage( Weapon[ pItemNumbers[ i ] ].ubImpact ); + UINT16 usRange = (UINT16)GetModifiedGunRange(pItemNumbers[ i ]); + INT8 accuracy = (UsingNewCTHSystem()==true?Weapon[ pItemNumbers[ i ] ].nAccuracy:Weapon[ pItemNumbers[ i ] ].bAccuracy); //UINT16 gunDamage = (UINT16)( Weapon[ pItemNumbers[ i ] ].ubImpact + ( (double) Weapon[ pItemNumbers[ i ] ].ubImpact / 100) * gGameExternalOptions.ubGunDamageMultiplier ); swprintf( pStr, L"%s\n%s %d\n%s %d\n%s %d\n%s %s\n%s %1.1f %s", ItemNames[ pItemNumbers[ i ] ], gWeaponStatsDesc[ 9 ], //Accuracy String - Weapon[ pItemNumbers[ i ] ].bAccuracy, //Accuracy + accuracy, //Accuracy gWeaponStatsDesc[ 11 ], //Damage String gunDamage, //Gun damage gWeaponStatsDesc[ 10 ], //Range String - gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? Weapon[ pItemNumbers[ i ] ].usRange/10 : Weapon[ pItemNumbers[ i ] ].usRange, //Gun Range + gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? usRange/10 : usRange, //Gun Range gWeaponStatsDesc[ 6 ], //AP String //apStr, //AP's L"- / - / -", @@ -2764,7 +2852,11 @@ void SelectBigImageRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { UINT16 usItemNum = (UINT16)MSYS_GetRegionUserData( pRegion, 0 ); - PurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum] ); + // HEADROCK HAM 4: Purchase all at once. + if (_KeyDown( 16 ) ) // SHIFT + PurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum], TRUE ); + else + PurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum], FALSE ); fReDrawScreenFlag = TRUE; fPausedReDrawScreenFlag = TRUE; @@ -2773,7 +2865,11 @@ void SelectBigImageRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { UINT16 usItemNum = (UINT16)MSYS_GetRegionUserData( pRegion, 0 ); - UnPurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum] ); + // HEADROCK HAM 4: Unpurchase all at once. + if (_KeyDown( 16 ) ) // SHIFT + UnPurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum], TRUE ); + else + UnPurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum], FALSE ); fReDrawScreenFlag = TRUE; fPausedReDrawScreenFlag = TRUE; } @@ -2781,7 +2877,7 @@ void SelectBigImageRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { UINT16 usItemNum = (UINT16)MSYS_GetRegionUserData( pRegion, 0 ); - PurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum] ); + PurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum], FALSE ); fReDrawScreenFlag = TRUE; fPausedReDrawScreenFlag = TRUE; } @@ -2789,7 +2885,7 @@ void SelectBigImageRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { UINT16 usItemNum = (UINT16)MSYS_GetRegionUserData( pRegion, 0 ); - UnPurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum] ); + UnPurchaseBobbyRayItem( gusItemNumberForItemsOnScreen[ usItemNum], FALSE ); fReDrawScreenFlag = TRUE; fPausedReDrawScreenFlag = TRUE; } @@ -2797,7 +2893,7 @@ void SelectBigImageRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) -void PurchaseBobbyRayItem(UINT16 usItemNumber) +void PurchaseBobbyRayItem(UINT16 usItemNumber, BOOLEAN fAllItems ) { UINT8 ubPurchaseNumber; @@ -2816,8 +2912,10 @@ void PurchaseBobbyRayItem(UINT16 usItemNumber) if( ubPurchaseNumber != BOBBY_RAY_NOT_PURCHASED ) { + UINT8 ubNumItems = fAllItems ? LaptopSaveInfo.BobbyRayUsedInventory[ usItemNumber ].ubQtyOnHand : 1; + BobbyRayPurchases[ ubPurchaseNumber ].usItemIndex = LaptopSaveInfo.BobbyRayUsedInventory[ usItemNumber ].usItemIndex; - BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased = 1; + BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased = ubNumItems; BobbyRayPurchases[ ubPurchaseNumber ].bItemQuality = LaptopSaveInfo.BobbyRayUsedInventory[ usItemNumber ].ubItemQuality; BobbyRayPurchases[ ubPurchaseNumber ].usBobbyItemIndex = usItemNumber; BobbyRayPurchases[ ubPurchaseNumber ].fUsed = TRUE; @@ -2832,8 +2930,10 @@ void PurchaseBobbyRayItem(UINT16 usItemNumber) // Else If the item is already purchased increment purchase amount. Only if ordering less then the max amount! else { - if( BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased <= BOBBY_RAY_MAX_AMOUNT_OF_ITEMS_TO_PURCHASE) - BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased++; + UINT8 ubNumItems = fAllItems ? LaptopSaveInfo.BobbyRayUsedInventory[ usItemNumber ].ubQtyOnHand - BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased : 1; + + if( BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased <= BOBBY_RAY_MAX_AMOUNT_OF_ITEMS_TO_PURCHASE - (ubNumItems-1)) + BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased += ubNumItems; } } else @@ -2858,8 +2958,10 @@ void PurchaseBobbyRayItem(UINT16 usItemNumber) if( ubPurchaseNumber != BOBBY_RAY_NOT_PURCHASED ) { + UINT8 ubNumItems = fAllItems ? LaptopSaveInfo.BobbyRayInventory[ usItemNumber ].ubQtyOnHand : 1; + BobbyRayPurchases[ ubPurchaseNumber ].usItemIndex = LaptopSaveInfo.BobbyRayInventory[ usItemNumber ].usItemIndex; - BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased = 1; + BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased = ubNumItems; BobbyRayPurchases[ ubPurchaseNumber ].bItemQuality = 100; BobbyRayPurchases[ ubPurchaseNumber ].usBobbyItemIndex = usItemNumber; BobbyRayPurchases[ ubPurchaseNumber ].fUsed = FALSE; @@ -2873,8 +2975,10 @@ void PurchaseBobbyRayItem(UINT16 usItemNumber) // Else If the item is already purchased increment purchase amount. Only if ordering less then the max amount! else { - if( BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased <= BOBBY_RAY_MAX_AMOUNT_OF_ITEMS_TO_PURCHASE) - BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased++; + UINT8 ubNumItems = fAllItems ? LaptopSaveInfo.BobbyRayInventory[ usItemNumber ].ubQtyOnHand - BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased : 1; + + if( BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased <= BOBBY_RAY_MAX_AMOUNT_OF_ITEMS_TO_PURCHASE - (ubNumItems-1)) + BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased += ubNumItems; } } else @@ -2916,7 +3020,7 @@ UINT8 GetNextPurchaseNumber() -void UnPurchaseBobbyRayItem(UINT16 usItemNumber) +void UnPurchaseBobbyRayItem(UINT16 usItemNumber, BOOLEAN fAllItems ) { UINT8 ubPurchaseNumber; @@ -2924,7 +3028,7 @@ void UnPurchaseBobbyRayItem(UINT16 usItemNumber) if( ubPurchaseNumber != BOBBY_RAY_NOT_PURCHASED ) { - if( BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased > 1) + if( BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased > 1 && !fAllItems) BobbyRayPurchases[ ubPurchaseNumber ].ubNumberPurchased--; else { diff --git a/Laptop/BobbyRMailOrder.cpp b/Laptop/BobbyRMailOrder.cpp index e3823c40..179b9f4d 100644 --- a/Laptop/BobbyRMailOrder.cpp +++ b/Laptop/BobbyRMailOrder.cpp @@ -31,6 +31,7 @@ #include "Strategic Event Handler.h" #include "connect.h" +/* typedef struct { STR16 *psCityLoc; @@ -38,8 +39,9 @@ typedef struct UINT16 us2DaysService; UINT16 usStandardService; } BobbyROrderLocationStruct; +*/ - +/* BobbyROrderLocationStruct BobbyROrderLocations[]= { { &pDeliveryLocationStrings[0], 20, 15, 10 }, @@ -60,6 +62,7 @@ BobbyROrderLocationStruct BobbyROrderLocations[]= { &pDeliveryLocationStrings[15], 100, 55, 30 }, { &pDeliveryLocationStrings[16], 45, 30, 20 }, }; +*/ //drop down menu enum @@ -829,7 +832,10 @@ void BtnBobbyRAcceptOrderCallback(GUI_BUTTON *btn,INT32 reason) else { //else pop up a confirmation box - swprintf( zTemp, BobbyROrderFormText[BOBBYR_CONFIRM_DEST], *BobbyROrderLocations[gbSelectedCity].psCityLoc ); + //swprintf( zTemp, BobbyROrderFormText[BOBBYR_CONFIRM_DEST], *BobbyROrderLocations[gbSelectedCity].psCityLoc ); + + // WANNE: Replaced hard coded town names with the externalized ones (from ShippingDestination.xml). + swprintf( zTemp, BobbyROrderFormText[BOBBYR_CONFIRM_DEST], gDestinationTable[gbSelectedCity]->wstrName.c_str() ); DoLapTopMessageBox( MSG_BOX_LAPTOP_DEFAULT, zTemp, LAPTOP_SCREEN, MSG_BOX_FLAG_YESNO, ConfirmBobbyRPurchaseMessageBoxCallBack ); } @@ -1433,10 +1439,12 @@ BOOLEAN CreateDestroyBobbyRDropDown( UINT8 ubDropDownAction ) //display the name on the title bar ColorFillVideoSurfaceArea( FRAME_BUFFER, BOBBYR_SHIPPING_LOC_AREA_L_X, BOBBYR_SHIPPING_LOC_AREA_T_Y, BOBBYR_SHIPPING_LOC_AREA_L_X+175, BOBBYR_SHIPPING_LOC_AREA_T_Y+BOBBYR_DROP_DOWN_HEIGHT, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) ); + /* if( gbSelectedCity == -1 ) DrawTextToScreen( BobbyROrderFormText[BOBBYR_SELECT_DEST], BOBBYR_CITY_START_LOCATION_X+BOBBYR_CITY_NAME_OFFSET, BOBBYR_SHIPPING_LOC_AREA_T_Y+3, 0, BOBBYR_DROPDOWN_FONT, BOBBYR_ORDER_DROP_DOWN_SELEC_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - else + else DrawTextToScreen( *(BobbyROrderLocations[gbSelectedCity].psCityLoc), BOBBYR_CITY_START_LOCATION_X+BOBBYR_CITY_NAME_OFFSET, BOBBYR_SHIPPING_LOC_AREA_T_Y+3, 0, BOBBYR_DROPDOWN_FONT, BOBBYR_ORDER_DROP_DOWN_SELEC_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + */ //disable the r\close regiuon MSYS_DisableRegion(&gSelectedCloseDropDownRegion); diff --git a/Laptop/CharProfile.cpp b/Laptop/CharProfile.cpp index 00c799b9..a50c796e 100644 --- a/Laptop/CharProfile.cpp +++ b/Laptop/CharProfile.cpp @@ -25,11 +25,12 @@ #include "IMP Confirm.h" #include "messageboxscreen.h" #include "LaptopSave.h" - // These 4 added - SANDRO + // These 5 added - SANDRO #include "IMP Character and Disability Entrance.h" #include "IMP Character Trait.h" #include "IMP Disability Trait.h" #include "IMP Color Choosing.h" + #include "IMP Minor Trait.h" #endif @@ -67,6 +68,7 @@ CHAR16 pNickName[ 32 ]; // skills INT32 iSkillA = 0; INT32 iSkillB = 0; +INT32 iSkillC = 0; // added third skill - SANDRO // personality INT32 iPersonality = 0; @@ -255,7 +257,7 @@ void HandleCharProfile() case( IMP_CONFIRM ): HandleIMPConfirm( ); break; - // These 4 added - SANDRO + // These 5 added - SANDRO case( IMP_CHARACTER_AND_DISABILITY_ENTRANCE ): HandleIMPCharacterAndDisabilityEntrance( ); break; @@ -268,6 +270,9 @@ void HandleCharProfile() case( IMP_COLOR_CHOICE_PAGE ): HandleIMPColorChoice( ); break; + case( IMP_MINOR_TRAITS_PAGE ): + HandleIMPMinorTrait( ); + break; } return; @@ -328,7 +333,7 @@ void RenderCharProfile() case( IMP_CONFIRM ): RenderIMPConfirm( ); break; - // These 4 added - SANDRO + // These 5 added - SANDRO case( IMP_CHARACTER_AND_DISABILITY_ENTRANCE ): RenderIMPCharacterAndDisabilityEntrance( ); break; @@ -341,6 +346,9 @@ void RenderCharProfile() case( IMP_COLOR_CHOICE_PAGE ): RenderIMPColorChoice( ); break; + case( IMP_MINOR_TRAITS_PAGE ): + RenderIMPMinorTrait( ); + break; } // render title bar @@ -425,7 +433,7 @@ void ExitOldIMPMode( void ) case( IMP_CONFIRM ): ExitIMPConfirm( ); break; - // These 4 added - SANDRO + // These 5 added - SANDRO case( IMP_CHARACTER_AND_DISABILITY_ENTRANCE ): DestroyIMPButtons( ); ExitIMPCharacterAndDisabilityEntrance( ); @@ -442,6 +450,10 @@ void ExitOldIMPMode( void ) DestroyIMPButtons( ); ExitIMPColorChoice( ); break; + case( IMP_MINOR_TRAITS_PAGE ): + DestroyIMPButtons( ); + ExitIMPMinorTrait( ); + break; } return; @@ -508,7 +520,7 @@ void EnterNewIMPMode( void ) case( IMP_CONFIRM ): EnterIMPConfirm( ); break; - // These 4 added - SANDRO + // These 5 added - SANDRO case( IMP_CHARACTER_AND_DISABILITY_ENTRANCE ): CreateIMPButtons( ); EnterIMPCharacterAndDisabilityEntrance( ); @@ -525,6 +537,10 @@ void EnterNewIMPMode( void ) CreateIMPButtons( ); EnterIMPColorChoice( ); break; + case( IMP_MINOR_TRAITS_PAGE ): + CreateIMPButtons( ); + EnterIMPMinorTrait( ); + break; } @@ -552,6 +568,7 @@ void ResetCharacterStats( void ) // skills iSkillA = 0; iSkillB = 0; + iSkillC = 0; // SANDRO - added third skill // personality iPersonality = 0; @@ -614,8 +631,9 @@ void LoadImpGraphics( void ) LoadAvgMercIndentFrame( ); LoadAboutUsIndentFrame( ); - LoadAttribStartingLevelFrame( ); // Added by SANDRO - LoadColorChoiceFrame( ); // Added by SANDRO + // Added by SANDRO + LoadAttribStartingLevelFrame( ); + LoadColorChoiceFrame( ); return; @@ -666,9 +684,10 @@ void RemoveImpGraphics( void ) DeleteAttrib2IndentFrame( ); DeleteAvgMercIndentFrame( ); DeleteAboutUsIndentFrame( ); - - DeleteAttribStartingLevelFrame( ); // Added by SANDRO - DeleteColorChoiceFrame( ); // Added by SANDRO + + // Added by SANDRO + DeleteAttribStartingLevelFrame( ); + DeleteColorChoiceFrame( ); return; } diff --git a/Laptop/CharProfile.h b/Laptop/CharProfile.h index e884dd59..f569b217 100644 --- a/Laptop/CharProfile.h +++ b/Laptop/CharProfile.h @@ -38,6 +38,7 @@ extern CHAR16 pNickName[]; // skills extern INT32 iSkillA; extern INT32 iSkillB; +extern INT32 iSkillC; // Added by SANDRO // persoanlity extern INT32 iPersonality; @@ -78,11 +79,12 @@ enum{ IMP_VOICE, IMP_ABOUT_US, IMP_CONFIRM, - // These 4 added - SANDRO + // These 5 added - SANDRO IMP_CHARACTER_AND_DISABILITY_ENTRANCE, IMP_CHARACTER_PAGE, IMP_DISABILITY_PAGE, IMP_COLOR_CHOICE_PAGE, + IMP_MINOR_TRAITS_PAGE, IMP_NUM_PAGES, }; diff --git a/Laptop/IMP Attribute Selection.cpp b/Laptop/IMP Attribute Selection.cpp index 89500489..0a0d84fa 100644 --- a/Laptop/IMP Attribute Selection.cpp +++ b/Laptop/IMP Attribute Selection.cpp @@ -23,7 +23,10 @@ #include "IMP Compile Character.h" #include "text.h" #include "GameSettings.h" - #include "IMP Disability Trait.h" // Added this one - SANDRO + // Added these 3 - SANDRO + #include "IMP Disability Trait.h" + #include "IMP Color Choosing.h" + #include "IMP Minor Trait.h" #endif @@ -84,6 +87,19 @@ INT32 iCurrentMechanical = 0; INT32 iCurrentMedical = 0; INT32 iCurrentExplosives = 0; +INT32 iStrengthMinimum = gGameExternalOptions.iMinAttribute; +INT32 iAgilityMinimum = gGameExternalOptions.iMinAttribute; +INT32 iDexterityMinimum = gGameExternalOptions.iMinAttribute; +INT32 iHealthMinimum = gGameExternalOptions.iMinAttribute; +INT32 iLeaderShipMinimum = gGameExternalOptions.iMinAttribute; +INT32 iWisdomMinimum = gGameExternalOptions.iMinAttribute; +INT32 iMarkmanshipMinimum = gGameExternalOptions.iMinAttribute; +INT32 iMechanicalMinimum = gGameExternalOptions.iMinAttribute; +INT32 iMedicalMinimum = gGameExternalOptions.iMinAttribute; +INT32 iExplosivesMinimum = gGameExternalOptions.iMinAttribute; + + + // which stat is message about stat at zero about INT32 iCurrentStatAtZero = 0; @@ -460,36 +476,36 @@ void ProcessAttributes( void ) INT32 iMaxAttribute = gGameExternalOptions.iMaxAttribute; // strength - if( iCurrentStrength <= iMinAttribute ) + if( iCurrentStrength <= iStrengthMinimum ) { - iCurrentStrength = iMinAttribute; + iCurrentStrength = iStrengthMinimum; // disable button too } // dex - if( iCurrentDexterity <= iMinAttribute ) + if( iCurrentDexterity <= iDexterityMinimum ) { - iCurrentDexterity = iMinAttribute; + iCurrentDexterity = iDexterityMinimum; // disable button too } // agility - if( iCurrentAgility <= iMinAttribute ) + if( iCurrentAgility <= iAgilityMinimum ) { - iCurrentAgility = iMinAttribute; + iCurrentAgility = iAgilityMinimum; // disable button too } // wisdom - if( iCurrentWisdom <= iMinAttribute ) + if( iCurrentWisdom <= iWisdomMinimum ) { - iCurrentWisdom = iMinAttribute; + iCurrentWisdom = iWisdomMinimum; // disable button too @@ -504,9 +520,9 @@ void ProcessAttributes( void ) //} // health - if( iCurrentHealth <= iMinAttribute ) + if( iCurrentHealth <= iHealthMinimum ) { - iCurrentHealth = iMinAttribute; + iCurrentHealth = iHealthMinimum; // disable button too } @@ -668,7 +684,7 @@ UINT8 IncrementStat( INT32 iStatToIncrement ) { if( DoWeHaveThisManyBonusPoints( iMaxZeroBonus ) == TRUE ) { - iCurrentLeaderShip+=iMinAttribute; + iCurrentLeaderShip+=iLeaderShipMinimum; iCurrentBonusPoints-=iMaxZeroBonus; fSkillAtZeroWarning = FALSE; } @@ -696,7 +712,7 @@ UINT8 IncrementStat( INT32 iStatToIncrement ) { if( DoWeHaveThisManyBonusPoints( iMaxZeroBonus ) == TRUE ) { - iCurrentMarkmanship+=iMinAttribute; + iCurrentMarkmanship+=iMarkmanshipMinimum; iCurrentBonusPoints-=iMaxZeroBonus; fSkillAtZeroWarning = FALSE; } @@ -724,7 +740,7 @@ UINT8 IncrementStat( INT32 iStatToIncrement ) { if( DoWeHaveThisManyBonusPoints( iMaxZeroBonus ) == TRUE ) { - iCurrentMechanical+=iMinAttribute; + iCurrentMechanical+=iMechanicalMinimum; iCurrentBonusPoints-=iMaxZeroBonus; fSkillAtZeroWarning = FALSE; } @@ -752,7 +768,7 @@ UINT8 IncrementStat( INT32 iStatToIncrement ) { if( DoWeHaveThisManyBonusPoints( iMaxZeroBonus ) == TRUE ) { - iCurrentMedical+=iMinAttribute; + iCurrentMedical+=iMedicalMinimum; iCurrentBonusPoints-=iMaxZeroBonus; fSkillAtZeroWarning = FALSE; } @@ -780,7 +796,7 @@ UINT8 IncrementStat( INT32 iStatToIncrement ) { if( DoWeHaveThisManyBonusPoints( iMaxZeroBonus ) == TRUE ) { - iCurrentExplosives+=iMinAttribute; + iCurrentExplosives+=iExplosivesMinimum; iCurrentBonusPoints-=iMaxZeroBonus; fSkillAtZeroWarning = FALSE; } @@ -821,23 +837,23 @@ UINT8 DecrementStat( INT32 iStatToDecrement ) switch( iStatToDecrement ) { case( STRENGTH_ATTRIBUTE ): - if( iCurrentStrength > iMinAttribute ) + if( iCurrentStrength > iStrengthMinimum ) { // ok to decrement iCurrentStrength--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } else { return( SLIDER_OUT_OF_RANGE ); } break; - case( DEXTERITY_ATTRIBUTE ): - if( iCurrentDexterity > iMinAttribute ) + case( DEXTERITY_ATTRIBUTE ): + if( iCurrentDexterity > iDexterityMinimum ) { // ok to decrement iCurrentDexterity--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } else { @@ -845,23 +861,23 @@ UINT8 DecrementStat( INT32 iStatToDecrement ) } break; case( AGILITY_ATTRIBUTE ): - if( iCurrentAgility > iMinAttribute ) + if( iCurrentAgility > iAgilityMinimum ) { // ok to decrement iCurrentAgility--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } else { return( SLIDER_OUT_OF_RANGE ); } break; - case( WISDOM_ATTRIBUTE ): - if( iCurrentWisdom > iMinAttribute ) + case( WISDOM_ATTRIBUTE ): + if( iCurrentWisdom > iWisdomMinimum ) { // ok to decrement iCurrentWisdom--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } else { @@ -869,91 +885,106 @@ UINT8 DecrementStat( INT32 iStatToDecrement ) } break; case( LEADERSHIP_ATTRIBUTE ): - if( iCurrentLeaderShip > iMinAttribute ) + if( iCurrentLeaderShip > iLeaderShipMinimum ) { // ok to decrement iCurrentLeaderShip--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } //Kaiden: Leadership couldn't be set to zero fixed below: - else if( iCurrentLeaderShip == iMinAttribute) + else if( iCurrentLeaderShip == iLeaderShipMinimum) { - // ok to decrement - iCurrentLeaderShip-=iMinAttribute; - iCurrentBonusPoints+=iMaxZeroBonus; - fSkillAtZeroWarning = TRUE; + if (LeadershipRequiredDueToMajorSkills() == 0 && LeaderShipRequiredAdjustmentForMinorTraits( 0 ) == 0 ) + { + // ok to decrement + iCurrentLeaderShip-=iLeaderShipMinimum; + iCurrentBonusPoints+=iMaxZeroBonus; + fSkillAtZeroWarning = TRUE; + } } break; case( HEALTH_ATTRIBUTE ): - if( iCurrentHealth > iMinAttribute ) + if( iCurrentHealth > iHealthMinimum ) { // ok to decrement iCurrentHealth--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } else { return( SLIDER_OUT_OF_RANGE ); } break; - case( MARKSMANSHIP_SKILL ): - if( iCurrentMarkmanship > iMinAttribute ) + case( MARKSMANSHIP_SKILL ): + if( iCurrentMarkmanship > iMarkmanshipMinimum ) { // ok to decrement iCurrentMarkmanship--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } - else if( iCurrentMarkmanship == iMinAttribute) + else if( iCurrentMarkmanship == iMarkmanshipMinimum) { - // ok to decrement - iCurrentMarkmanship-=iMinAttribute; - iCurrentBonusPoints+=iMaxZeroBonus; - fSkillAtZeroWarning = TRUE; + if (MarksmanshipRequiredDueToMajorSkills() == 0 && MarksmanshipRequiredAdjustmentForMinorTraits( 0 ) == 0 ) + { + // ok to decrement + iCurrentMarkmanship-=iMarkmanshipMinimum; + iCurrentBonusPoints+=iMaxZeroBonus; + fSkillAtZeroWarning = TRUE; + } } break; case( MEDICAL_SKILL ): - if( iCurrentMedical > iMinAttribute ) + if( iCurrentMedical > iMedicalMinimum ) { // ok to decrement iCurrentMedical--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } - else if( iCurrentMedical == iMinAttribute) + else if( iCurrentMedical == iMedicalMinimum) { - // ok to decrement - iCurrentMedical-=iMinAttribute; - iCurrentBonusPoints+=iMaxZeroBonus; - fSkillAtZeroWarning = TRUE; + if (MedicalRequiredDueToMajorSkills() == 0 && MedicalRequiredAdjustmentForMinorTraits( 0 ) == 0 ) + { + // ok to decrement + iCurrentMedical-=iMedicalMinimum; + iCurrentBonusPoints+=iMaxZeroBonus; + fSkillAtZeroWarning = TRUE; + } } break; case( MECHANICAL_SKILL ): - if( iCurrentMechanical > iMinAttribute ) + if( iCurrentMechanical > iMechanicalMinimum ) { // ok to decrement iCurrentMechanical--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } - else if( iCurrentMechanical == iMinAttribute) + else if( iCurrentMechanical == iMechanicalMinimum) { - // ok to decrement - iCurrentMechanical-=iMinAttribute; - iCurrentBonusPoints+=iMaxZeroBonus; - fSkillAtZeroWarning = TRUE; + if (MechanicalRequiredDueToMajorSkills() == 0 && MechanicalRequiredAdjustmentForMinorTraits( 0 ) == 0 ) + { + // ok to decrement + iCurrentMechanical-=iMechanicalMinimum; + iCurrentBonusPoints+=iMaxZeroBonus; + fSkillAtZeroWarning = TRUE; + } } break; case( EXPLOSIVE_SKILL ): - if( iCurrentExplosives > iMinAttribute ) + if( iCurrentExplosives > iExplosivesMinimum ) { // ok to decrement iCurrentExplosives--; - iCurrentBonusPoints++; + iCurrentBonusPoints++; } - else if( iCurrentExplosives == iMinAttribute) + else if( iCurrentExplosives == iExplosivesMinimum) { - // ok to decrement - iCurrentExplosives-=iMinAttribute; - iCurrentBonusPoints+=iMaxZeroBonus; - fSkillAtZeroWarning = TRUE; + if (ExplosivesRequiredDueToMajorSkills() == 0 && ExplosivesRequiredAdjustmentForMinorTraits( 0 ) == 0 ) + { + // ok to decrement + iCurrentExplosives-=iExplosivesMinimum; + iCurrentBonusPoints+=iMaxZeroBonus; + fSkillAtZeroWarning = TRUE; + } } break; @@ -1563,7 +1594,9 @@ void CreateSliderBarMouseRegions( void ) INT16 sX = 0; // set the starting X - sX = DetermineNewPosition( gGameExternalOptions.iStartAttribute - iMinAttribute ); + // SANDRO - some changes in attribute points distribution method + //sX = DetermineNewPosition( gGameExternalOptions.iStartAttribute - iMinAttribute ); + sX = DetermineNewPosition( 0 ); for( iCounter = 0; iCounter < 10; iCounter++ ) { @@ -1882,59 +1915,190 @@ INT32 GetCurrentAttributeValue( INT32 iAttribute ) void SetAttributes( void ) { - INT8 bExtraPoints = 0; -/* - // set attributes and skills based on what is in charprofile.c - - // attributes - iCurrentStrength = iStrength + iAddStrength; - iCurrentDexterity = iDexterity + iAddDexterity; - iCurrentHealth = iHealth + iAddHealth; - iCurrentLeaderShip = iLeadership + iAddLeadership; - iCurrentWisdom = iWisdom + iAddWisdom; - iCurrentAgility = iAgility + iAddAgility; - - // skills - iCurrentMarkmanship = iMarksmanship + iAddMarksmanship; - iCurrentMechanical = iMechanical + iAddMechanical; - iCurrentMedical = iMedical + iAddMedical; - iCurrentExplosives = iExplosives + iAddExplosives; - - // reset bonus pts - iCurrentBonusPoints = 40; -*/ + INT32 iExtraPoints = 0; // added externilized multiplier for starting level - SADNRO iLevelCostMultiplier = gGameExternalOptions.iIMPStartingLevelCostMultiplier; - iCurrentStrength = gGameExternalOptions.iStartAttribute; - iCurrentDexterity = gGameExternalOptions.iStartAttribute; - iCurrentHealth = gGameExternalOptions.iStartAttribute; - iCurrentLeaderShip = gGameExternalOptions.iStartAttribute; - iCurrentWisdom = gGameExternalOptions.iStartAttribute; - iCurrentAgility = gGameExternalOptions.iStartAttribute; + ///////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - determine minimum attribute values due to chosen traits - // skills - iCurrentMarkmanship = gGameExternalOptions.iStartAttribute; - iCurrentMechanical = gGameExternalOptions.iStartAttribute; - iCurrentMedical = gGameExternalOptions.iStartAttribute; - iCurrentExplosives = gGameExternalOptions.iStartAttribute; - - - // reset bonus pts - //iCurrentBonusPoints = 40; - iCurrentBonusPoints = gGameExternalOptions.iImpAttributePoints; - - - //Determine if the player has any extra points - bExtraPoints += iPlayersAttributePointsBonusForDisabilitySelected(); // Added attribute bonus for chosen disability - SANDRO - bExtraPoints += DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection(); - - if( bExtraPoints > 0 ) + // For new trait system only though + if ( gGameOptions.fNewTraitSystem ) { - iCurrentBonusPoints += bExtraPoints; - } + // reset bonus pts + iCurrentBonusPoints = gGameExternalOptions.iImpAttributePoints; + //Determine if the player has any extra points + iExtraPoints += iPlayersAttributePointsBonusForDisabilitySelected(); + iExtraPoints += DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection(); + if( iExtraPoints > 0 ) + iCurrentBonusPoints += iExtraPoints; + + // Get Strength minimum + iStrengthMinimum = StrengthRequiredDueToMajorSkills(); + if ( iStrengthMinimum < gGameExternalOptions.iMinAttribute ) + iStrengthMinimum = gGameExternalOptions.iMinAttribute; + + iStrengthMinimum += StrengthRequiredAdjustmentForMinorTraits( iStrengthMinimum ); + + // hehehe, make the alternative weapon holding anim requiring a big strength + if ( bBadAssSelected() && iStrengthMinimum < 80 ) + iStrengthMinimum = 80; + + if ( iStrengthMinimum > gGameExternalOptions.iMaxAttribute ) + iStrengthMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentStrength = iStrengthMinimum; + iCurrentBonusPoints -= iStrengthMinimum; + + // Get Agility minimum + iAgilityMinimum = AgilityRequiredDueToMajorSkills(); + if ( iAgilityMinimum < gGameExternalOptions.iMinAttribute ) + iAgilityMinimum = gGameExternalOptions.iMinAttribute; + + iAgilityMinimum += AgilityRequiredAdjustmentForMinorTraits( iAgilityMinimum ); + + if ( iAgilityMinimum > gGameExternalOptions.iMaxAttribute ) + iAgilityMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentAgility = iAgilityMinimum; + iCurrentBonusPoints -= iAgilityMinimum; + + // Get Dexterity minimum + iDexterityMinimum = DexterityRequiredDueToMajorSkills(); + if ( iDexterityMinimum < gGameExternalOptions.iMinAttribute ) + iDexterityMinimum = gGameExternalOptions.iMinAttribute; + + iDexterityMinimum += DexterityRequiredAdjustmentForMinorTraits( iDexterityMinimum ); + + if ( iDexterityMinimum > gGameExternalOptions.iMaxAttribute ) + iDexterityMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentDexterity = iDexterityMinimum; + iCurrentBonusPoints -= iDexterityMinimum; + + // Get Health minimum + iHealthMinimum = HealthRequiredDueToMajorSkills(); + if ( iHealthMinimum <= 0 ) + iHealthMinimum = gGameExternalOptions.iMinAttribute; + + iHealthMinimum += HealthRequiredAdjustmentForMinorTraits( iHealthMinimum ); + + if ( iHealthMinimum > gGameExternalOptions.iMaxAttribute ) + iHealthMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentHealth = iHealthMinimum; + iCurrentBonusPoints -= iHealthMinimum; + + // Get Leadership minimum + iLeaderShipMinimum = LeadershipRequiredDueToMajorSkills(); + if ( iLeaderShipMinimum < gGameExternalOptions.iMinAttribute ) + iLeaderShipMinimum = gGameExternalOptions.iMinAttribute; + + iLeaderShipMinimum += LeaderShipRequiredAdjustmentForMinorTraits( iLeaderShipMinimum ); + + if ( iLeaderShipMinimum > gGameExternalOptions.iMaxAttribute ) + iLeaderShipMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentLeaderShip = iLeaderShipMinimum; + iCurrentBonusPoints -= (iLeaderShipMinimum - gGameExternalOptions.iMinAttribute + gGameExternalOptions.iMaxZeroBonus); + + // Get Wisdom minimum + iWisdomMinimum = WisdomRequiredDueToMajorSkills(); + if ( iWisdomMinimum < gGameExternalOptions.iMinAttribute ) + iWisdomMinimum = gGameExternalOptions.iMinAttribute; + + iWisdomMinimum += WisdomRequiredAdjustmentForMinorTraits( iWisdomMinimum ); + + if ( iWisdomMinimum > gGameExternalOptions.iMaxAttribute ) + iWisdomMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentWisdom = iWisdomMinimum; + iCurrentBonusPoints -= iWisdomMinimum; + + // Get Marksmanship minimum + iMarkmanshipMinimum = MarksmanshipRequiredDueToMajorSkills(); + if ( iMarkmanshipMinimum < gGameExternalOptions.iMinAttribute ) + iMarkmanshipMinimum = gGameExternalOptions.iMinAttribute; + + iMarkmanshipMinimum += MarksmanshipRequiredAdjustmentForMinorTraits( iMarkmanshipMinimum ); + + if ( iMarkmanshipMinimum > gGameExternalOptions.iMaxAttribute ) + iMarkmanshipMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentMarkmanship = iMarkmanshipMinimum; + iCurrentBonusPoints -= (iMarkmanshipMinimum - gGameExternalOptions.iMinAttribute + gGameExternalOptions.iMaxZeroBonus); + + // Get Mechanical minimum + iMechanicalMinimum = MechanicalRequiredDueToMajorSkills(); + if ( iMechanicalMinimum < gGameExternalOptions.iMinAttribute ) + iMechanicalMinimum = gGameExternalOptions.iMinAttribute; + + iMechanicalMinimum += MechanicalRequiredAdjustmentForMinorTraits( iMechanicalMinimum ); + + if ( iMechanicalMinimum > gGameExternalOptions.iMaxAttribute ) + iMechanicalMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentMechanical = iMechanicalMinimum; + iCurrentBonusPoints -= (iMechanicalMinimum - gGameExternalOptions.iMinAttribute + gGameExternalOptions.iMaxZeroBonus); + + // Get Medical minimum + iMedicalMinimum = MedicalRequiredDueToMajorSkills(); + if ( iMedicalMinimum < gGameExternalOptions.iMinAttribute ) + iMedicalMinimum = gGameExternalOptions.iMinAttribute; + + iMedicalMinimum += MedicalRequiredAdjustmentForMinorTraits( iMedicalMinimum ); + + if ( iMedicalMinimum > gGameExternalOptions.iMaxAttribute ) + iMedicalMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentMedical = iMedicalMinimum; + iCurrentBonusPoints -= (iMedicalMinimum - gGameExternalOptions.iMinAttribute + gGameExternalOptions.iMaxZeroBonus); + + // Get Explosives minimum + iExplosivesMinimum = ExplosivesRequiredDueToMajorSkills(); + if ( iExplosivesMinimum < gGameExternalOptions.iMinAttribute ) + iExplosivesMinimum = gGameExternalOptions.iMinAttribute; + + iExplosivesMinimum += ExplosivesRequiredAdjustmentForMinorTraits( iExplosivesMinimum ); + + if ( iExplosivesMinimum > gGameExternalOptions.iMaxAttribute ) + iExplosivesMinimum = gGameExternalOptions.iMaxAttribute; + + iCurrentExplosives = iExplosivesMinimum; + iCurrentBonusPoints -= (iExplosivesMinimum - gGameExternalOptions.iMinAttribute + gGameExternalOptions.iMaxZeroBonus); + + + // if we exceeded points available, just give us zero points, but keep the attribute minimums untouched + if ( iCurrentBonusPoints < 0 ) + iCurrentBonusPoints = 0; + } + ///////////////////////////////////////////////////////////////////////////////////////////////// + else // ORIGINAL + { + iCurrentBonusPoints = gGameExternalOptions.iImpAttributePoints; + + //Determine if the player has any extra points + iExtraPoints += iPlayersAttributePointsBonusForDisabilitySelected(); + iExtraPoints += DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection(); + if( iExtraPoints > 0 ) + iCurrentBonusPoints += iExtraPoints; + + iCurrentStrength = gGameExternalOptions.iMinAttribute; + iCurrentDexterity = gGameExternalOptions.iMinAttribute; + iCurrentHealth = gGameExternalOptions.iMinAttribute; + iCurrentLeaderShip = gGameExternalOptions.iMinAttribute; + iCurrentWisdom = gGameExternalOptions.iMinAttribute; + iCurrentAgility = gGameExternalOptions.iMinAttribute; + iCurrentMarkmanship = gGameExternalOptions.iMinAttribute; + iCurrentMechanical = gGameExternalOptions.iMinAttribute; + iCurrentMedical = gGameExternalOptions.iMinAttribute; + iCurrentExplosives = gGameExternalOptions.iMinAttribute; + + iCurrentBonusPoints -= ((5 * gGameExternalOptions.iMinAttribute) + (5 * gGameExternalOptions.iMaxZeroBonus)); + } + //////////////////////////////////////////////////// ResetIncrementCharacterAttributes( ); diff --git a/Laptop/IMP Begin Screen.cpp b/Laptop/IMP Begin Screen.cpp index b71aaa55..58094185 100644 --- a/Laptop/IMP Begin Screen.cpp +++ b/Laptop/IMP Begin Screen.cpp @@ -32,7 +32,7 @@ #include "LaptopSave.h" #endif -#include "VFS/Tools/ParserTools.h" +#include #define FULL_NAME_CURSOR_Y LAPTOP_SCREEN_WEB_UL_Y + 138 #define NICK_NAME_CURSOR_Y LAPTOP_SCREEN_WEB_UL_Y + 195 @@ -1299,9 +1299,9 @@ BOOLEAN CheckCharacterInputForEgg( void ) iMechanical = 0; iExplosives = 99; iMedical = 0; - iSkillA = AMBIDEXT; - iSkillB = AUTO_WEAPS; - iPersonality = NO_PERSONALITYTRAIT; + iSkillA = AMBIDEXT_OT; + iSkillB = AUTO_WEAPS_OT; + iPersonality = NO_DISABILITY; iAttitude = ATT_ASSHOLE; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1324,9 +1324,9 @@ BOOLEAN CheckCharacterInputForEgg( void ) iMechanical = 40; iExplosives = 25; iMedical = 60; - iSkillA = MARTIALARTS; - iSkillB = AUTO_WEAPS; - iPersonality = NO_PERSONALITYTRAIT; + iSkillA = MARTIALARTS_OT; + iSkillB = AUTO_WEAPS_OT; + iPersonality = NO_DISABILITY; iAttitude = ATT_FRIENDLY; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1349,9 +1349,9 @@ BOOLEAN CheckCharacterInputForEgg( void ) iMechanical = 100; iExplosives = 100; iMedical = 100; - iSkillA = MARTIALARTS; - iSkillB = AUTO_WEAPS; - iPersonality = NO_PERSONALITYTRAIT; + iSkillA = MARTIALARTS_OT; + iSkillB = AUTO_WEAPS_OT; + iPersonality = NO_DISABILITY; iAttitude = ATT_FRIENDLY; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 2; @@ -1376,10 +1376,10 @@ BOOLEAN CheckCharacterInputForEgg( void ) iExplosives = 99; iMedical = 75; - iSkillA = STEALTHY; - iSkillB = MARTIALARTS; + iSkillA = STEALTHY_OT; + iSkillB = MARTIALARTS_OT; - iPersonality = NO_PERSONALITYTRAIT; + iPersonality = NO_DISABILITY; iAttitude = ATT_AGGRESSIVE; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1404,10 +1404,10 @@ BOOLEAN CheckCharacterInputForEgg( void ) iExplosives = 0; iMedical = 99; - iSkillA = AUTO_WEAPS; - iSkillB = AMBIDEXT; + iSkillA = AUTO_WEAPS_OT; + iSkillB = AMBIDEXT_OT; - iPersonality = NO_PERSONALITYTRAIT; + iPersonality = NO_DISABILITY; iAttitude = ATT_ARROGANT; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1432,10 +1432,10 @@ BOOLEAN CheckCharacterInputForEgg( void ) iExplosives = 99; iMedical = 35; - iSkillA = AUTO_WEAPS; - iSkillB = MARTIALARTS; + iSkillA = AUTO_WEAPS_OT; + iSkillB = MARTIALARTS_OT; - iPersonality = NO_PERSONALITYTRAIT; + iPersonality = NO_DISABILITY; iAttitude = ATT_AGGRESSIVE; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1460,10 +1460,10 @@ BOOLEAN CheckCharacterInputForEgg( void ) iExplosives = 99; iMedical = 0; - iSkillA = AUTO_WEAPS; - iSkillB = MARTIALARTS; + iSkillA = AUTO_WEAPS_OT; + iSkillB = MARTIALARTS_OT; - iPersonality = NO_PERSONALITYTRAIT; + iPersonality = NO_DISABILITY; iAttitude = ATT_LONER; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1486,8 +1486,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iMechanical = 0; iExplosives = 99; iMedical = 0; - iSkillA = AMBIDEXT; - iSkillB = AUTO_WEAPS; + iSkillA = AMBIDEXT_OT; + iSkillB = AUTO_WEAPS_OT; iPersonality = PSYCHO; iAttitude = ATT_ASSHOLE; iCurrentImpPage = IMP_FINISH; @@ -1542,10 +1542,10 @@ BOOLEAN CheckCharacterInputForEgg( void ) iExplosives = 99; iMedical = 60; - iSkillA = ELECTRONICS; - iSkillB = LOCKPICKING; + iSkillA = ELECTRONICS_OT; + iSkillB = LOCKPICKING_OT; - iPersonality = NO_PERSONALITYTRAIT; + iPersonality = NO_DISABILITY; iAttitude = ATT_LONER; iCurrentImpPage = IMP_FINISH; // LaptopSaveInfo.iCurrentVoice = 1; @@ -1575,7 +1575,7 @@ BOOLEAN CheckCharacterInputForEgg( void ) iSkillA = 0; iSkillB = 0; - iPersonality = NO_PERSONALITYTRAIT; + iPersonality = NO_DISABILITY; iAttitude = ATT_LONER; iCurrentImpPage = IMP_FINISH; LaptopSaveInfo.iIMPIndex = 54; diff --git a/Laptop/IMP Character Trait.cpp b/Laptop/IMP Character Trait.cpp index 98f83a42..16b0e98c 100644 --- a/Laptop/IMP Character Trait.cpp +++ b/Laptop/IMP Character Trait.cpp @@ -19,6 +19,7 @@ #include "CharProfile.h" #include "soldier profile type.h" #include "IMP Compile Character.h" + #include "GameSettings.h" #endif @@ -33,13 +34,6 @@ #define IMP_CHARACTER_TRAIT__FONT FONT12ARIAL #define IMP_CHARACTER_TRAIT__COLOR FONT_MCOLOR_WHITE -enum -{ - IMP_CHARACTER_TRAIT__TITLE_TEXT=IMP_CHARACTER_TRAITS_NUMBER, -}; - - - #define IMP_CHARACTER_1ST_COLUMN_START_X ( LAPTOP_SCREEN_UL_X + 15 ) #define IMP_CHARACTER_1ST_COLUMN_START_Y ( LAPTOP_SCREEN_WEB_UL_Y + 40 ) @@ -48,7 +42,7 @@ enum #define IMP_CHARACTER_TRAIT__SPACE_BTN_BUTTONS 38 -#define IMP_CHARACTER_TRAIT_NUMBER_TO_START_2ND_COLUMN 5 +//#define IMP_CHARACTER_TRAIT_NUMBER_TO_START_2ND_COLUMN 5 #define IMP_CHARACTER_TRAIT__TEXT_OFFSET_X 65 #define IMP_CHARACTER_TRAIT__TEXT_OFFSET_Y 12 @@ -69,11 +63,11 @@ enum BOOLEAN gfIST_Redraw2=FALSE; -BOOLEAN gfCharacterTraitQuestions[ IMP_CHARACTER_TRAITS_NUMBER ]; +BOOLEAN gfCharacterTraitQuestions[ 15 ]; // these are the buttons for the questions -INT32 giIMPCharacterTraitAnswerButton[ IMP_CHARACTER_TRAITS_NUMBER ]; -INT32 giIMPCharacterTraitAnswerButtonImage[ IMP_CHARACTER_TRAITS_NUMBER ]; +INT32 giIMPCharacterTraitAnswerButton[ 15 ]; +INT32 giIMPCharacterTraitAnswerButtonImage[ 15 ]; // this is the Done buttons INT32 giIMPCharacterTraitFinsihButton; @@ -82,6 +76,8 @@ INT32 giIMPCharacterTraitFinsihButtonImage; //image handle UINT32 guiIST_GreyGoldBox2; +MOUSE_REGION gMR_CharacterTraitHelpTextRegions[IMP_NUMBER_CHARACTER_TRAITS]; + //******************************************************************* // // Function Prototypes @@ -100,6 +96,7 @@ void IMPCharacterTraitDisplayCharacterTraits(); //void HandleLastSelectedCharacterTraits( INT8 bNewTrait ); BOOLEAN CameBackToCharacterTraitPageButNotFinished(); //ppp +void AssignCharacterTraitHelpText( UINT8 ubNumber ); //******************************************************************* // @@ -111,7 +108,7 @@ BOOLEAN CameBackToCharacterTraitPageButNotFinished(); void EnterIMPCharacterTrait( void ) { -// UINT32 uiCnt; +// UINT32 ubCnt; VOBJECT_DESC VObjectDesc; //add the skill trait buttons @@ -144,11 +141,36 @@ void EnterIMPCharacterTrait( void ) if( iCurrentProfileMode != IMP__FINISH ) { //Have the NONE trait initially selected - gfCharacterTraitQuestions[ IMP_CHARACTER_TRAIT_NORMAL ] = TRUE; + gfCharacterTraitQuestions[ 0 ] = TRUE; } HandleCharacterTraitButtonStates( ); + if ( gGameOptions.fNewTraitSystem ) + { + // add regions for help texts + UINT16 usPosX = IMP_CHARACTER_1ST_COLUMN_START_X + 62; + UINT16 usPosY = IMP_CHARACTER_1ST_COLUMN_START_Y + 8; + for( UINT8 ubCnt=0; ubCnt<(gGameOptions.fNewTraitSystem ? IMP_NUMBER_CHARACTER_TRAITS : IMP_NUMBER_ATTITUDES); ubCnt++ ) + { + MSYS_DefineRegion( &gMR_CharacterTraitHelpTextRegions[ubCnt], ( usPosX ), ( usPosY ), + (usPosX + 156), ( usPosY + 17), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gMR_CharacterTraitHelpTextRegions[ubCnt] ); + + //Determine the next x location + if( ubCnt < (gGameOptions.fNewTraitSystem ? 6 : 5) ) + usPosX = IMP_CHARACTER_1ST_COLUMN_START_X + 62; + else + usPosX = IMP_CHARACTER_2ND_COLUMN_START_X + 62; + + //Determine the next Y location + if( ubCnt == (gGameOptions.fNewTraitSystem ? 6 : 5) ) + usPosY = IMP_CHARACTER_2ND_COLUMN_START_Y + 8; + else + usPosY += IMP_CHARACTER_TRAIT__SPACE_BTN_BUTTONS; + } + } } @@ -158,7 +180,10 @@ void RenderIMPCharacterTrait( void ) RenderProfileBackGround(); //Display the title - DrawTextToScreen( gzIMPCharacterTraitText[IMP_CHARACTER_TRAITS_NUMBER], LAPTOP_SCREEN_UL_X - 111, iScreenHeightOffset + 53, ( LAPTOP_SCREEN_LR_X - LAPTOP_SCREEN_UL_X ), FONT14ARIAL, FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + if ( gGameOptions.fNewTraitSystem ) + DrawTextToScreen( gzIMPCharacterTraitText[IMP_NUMBER_CHARACTER_TRAITS], LAPTOP_SCREEN_UL_X - 111, iScreenHeightOffset + 53, ( LAPTOP_SCREEN_LR_X - LAPTOP_SCREEN_UL_X ), FONT14ARIAL, FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + else + DrawTextToScreen( gzIMPAttitudesText[IMP_NUMBER_ATTITUDES], LAPTOP_SCREEN_UL_X - 111, iScreenHeightOffset + 53, ( LAPTOP_SCREEN_LR_X - LAPTOP_SCREEN_UL_X ), FONT14ARIAL, FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); IMPCharacterTraitDisplayCharacterTraits(); } @@ -171,7 +196,7 @@ void ExitIMPCharacterTrait( void ) DeleteVideoObjectFromIndex( guiIST_GreyGoldBox2 ); //remove the skill buttons - for(iCnt = 0; iCnt < IMP_CHARACTER_TRAITS_NUMBER; iCnt++) + for(iCnt = 0; iCnt < (gGameOptions.fNewTraitSystem ? IMP_NUMBER_CHARACTER_TRAITS : IMP_NUMBER_ATTITUDES); iCnt++) { //if there is a button allocated if( giIMPCharacterTraitAnswerButton[iCnt] != -1 ) @@ -179,6 +204,9 @@ void ExitIMPCharacterTrait( void ) RemoveButton(giIMPCharacterTraitAnswerButton[ iCnt ] ); UnloadButtonImage(giIMPCharacterTraitAnswerButtonImage[ iCnt ] ); } + + if ( gGameOptions.fNewTraitSystem ) + MSYS_RemoveRegion( &gMR_CharacterTraitHelpTextRegions[iCnt] ); } RemoveButton( giIMPCharacterTraitFinsihButton ); @@ -205,7 +233,7 @@ void AddImpCharacterTraitButtons() usPosX = IMP_CHARACTER_1ST_COLUMN_START_X; usPosY = IMP_CHARACTER_1ST_COLUMN_START_Y; - for(iCnt = 0; iCnt < IMP_CHARACTER_TRAITS_NUMBER; iCnt++) + for(iCnt = 0; iCnt < (gGameOptions.fNewTraitSystem ? IMP_NUMBER_CHARACTER_TRAITS : IMP_NUMBER_ATTITUDES) ; iCnt++) { //reset giIMPCharacterTraitAnswerButton[iCnt] = -1; @@ -233,13 +261,13 @@ void AddImpCharacterTraitButtons() //ButtonList[ giIMPCharacterTraitAnswerButton[ iCnt ] ]->ubSoundSchemeID = 0; //Determine the next x location - if( iCnt < IMP_CHARACTER_TRAIT_NUMBER_TO_START_2ND_COLUMN ) + if( iCnt < (gGameOptions.fNewTraitSystem ? 6 : 5) ) usPosX = IMP_CHARACTER_1ST_COLUMN_START_X; else usPosX = IMP_CHARACTER_2ND_COLUMN_START_X; //Determine the next Y location - if( iCnt == IMP_CHARACTER_TRAIT_NUMBER_TO_START_2ND_COLUMN ) + if( iCnt == (gGameOptions.fNewTraitSystem ? 6 : 5) ) usPosY = IMP_CHARACTER_2ND_COLUMN_START_Y; else usPosY += IMP_CHARACTER_TRAIT__SPACE_BTN_BUTTONS; @@ -265,7 +293,7 @@ void BtnIMPCharacterTraitAnswerCallback(GUI_BUTTON *btn,INT32 reason) void HandleIMPCharacterTraitAnswers( UINT32 uiSkillPressed ) { - UINT32 uiCnt; + INT8 bCnt; //if we are DONE and are just reviewing if( iCurrentProfileMode == IMP__FINISH ) @@ -274,13 +302,13 @@ void HandleIMPCharacterTraitAnswers( UINT32 uiSkillPressed ) } //reset all other buttons - for( uiCnt=0; uiCnt IMP_CHARACTER_TRAITS_NUMBER ) + if( uiSkillPressed > (UINT32)(gGameOptions.fNewTraitSystem ? IMP_NUMBER_CHARACTER_TRAITS : IMP_NUMBER_ATTITUDES) ) { Assert( 0 ); return; @@ -315,26 +343,26 @@ void HandleIMPCharacterTraitAnswers( UINT32 uiSkillPressed ) void HandleCharacterTraitButtonStates( ) { - UINT32 uiCnt; + INT8 bCnt; - for( uiCnt=0; uiCntuiFlags |= BUTTON_CLICKED_ON; + ButtonList[ giIMPCharacterTraitAnswerButton[ bCnt ] ]->uiFlags |= BUTTON_CLICKED_ON; } else { - ButtonList[ giIMPCharacterTraitAnswerButton[ uiCnt ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + ButtonList[ giIMPCharacterTraitAnswerButton[ bCnt ] ]->uiFlags &= ~BUTTON_CLICKED_ON; } } } void IMPCharacterTraitDisplayCharacterTraits() { - UINT32 uiCnt; + INT8 bCnt; UINT16 usPosX, usPosY; UINT16 usBoxPosX, usBoxPosY; HVOBJECT hImageHandle; @@ -345,13 +373,13 @@ void IMPCharacterTraitDisplayCharacterTraits() usPosX = IMP_CHARACTER_1ST_COLUMN_START_X + IMP_CHARACTER_TRAIT__TEXT_OFFSET_X; usPosY = IMP_CHARACTER_1ST_COLUMN_START_Y + IMP_CHARACTER_TRAIT__TEXT_OFFSET_Y; - for( uiCnt=0; uiCnt iHighestHits ) - { - iHighestHits = __max( iHighestHits, iAttitudeHits[ iCounter ] ); - iNumAttitudesWithHighestHits = 1; - } - else if ( iAttitudeHits[ iCounter ] == iHighestHits ) - { - iNumAttitudesWithHighestHits++; - } - } - } - - // roll dice - iDiceValue = Random( iNumAttitudesWithHighestHits + 1 ); - - // find attitude - for ( iCounter = 0; iCounter < NUM_ATTITUDES; iCounter++ ) - { - if ( iAttitudeHits[ iCounter ] == iHighestHits ) - { - if ( iCounter2 == iDiceValue ) - { - // this is it! - iAttitude = iCounter2; - break; - } - else - { - // one of the next attitudes... - iCounter2++; - } - } - } - } - else - { - iAttitude = gGameExternalOptions.iCustomAttitude; - }*/ - - // Chosen by ourselves - SANDRO iAttitude = iChosenCharacterTrait(); } @@ -382,7 +310,7 @@ void ClearAllSkillsList( void ) { INT32 iLoop; - for ( iLoop = 0; iLoop < iLastElementInSkillsList; iLoop++ ) + for ( iLoop = 0; iLoop < ATTITUDE_LIST_SIZE; iLoop++ ) // SANDRO - better clear everything to be sure { SkillsList[ iLoop ] = 0; } @@ -445,132 +373,113 @@ void ValidateSkillsList( void ) if ( pProfile->bMechanical == 0 ) { // without mechanical, electronics is useless - iIndex = FindSkillInSkillsList( ELECTRONICS ); - if ( iIndex != -1 ) + // Electronics/Technician check - SANDRO + if ( gGameOptions.fNewTraitSystem ) { - pProfile->bMechanical = 1; + iIndex = FindSkillInSkillsList( TECHNICIAN_NT ); + if ( iIndex != -1 ) + pProfile->bMechanical = 1; } + else + { + iIndex = FindSkillInSkillsList( ELECTRONICS_OT ); + if ( iIndex != -1 ) + pProfile->bMechanical = 1; + + iIndex = FindSkillInSkillsList( LOCKPICKING_OT ); + if ( iIndex != -1 ) + pProfile->bMechanical = 1; + } + } - // Kaiden using UB's code, lockpicking can't be removed from the list "yet". - // special check for lockpicking - //iValue = pProfile->bMechanical; - //iValue = ( iValue * pProfile->bWisdom ) / 100; - //iValue = ( iValue * pProfile->bDexterity ) / 100; - //if ( iValue + gbSkillTraitBonus[ LOCKPICKING ] < 50 ) - //{ - // // not good enough for lockpicking! - // - // // so is lockpicking - // iIndex = FindSkillInSkillsList( LOCKPICKING ); - // while ( iIndex != -1 ) - // { - // RemoveSkillFromSkillsList( iIndex ); - // iIndex = FindSkillInSkillsList( LOCKPICKING ); - // } - //} + // SANDRO - added to give 1 medical skill to doctors + if ( pProfile->bMedical == 0 && gGameOptions.fNewTraitSystem ) + { + // without medical, Doctor trait is useless + iIndex = FindSkillInSkillsList( DOCTOR_NT ); + if ( iIndex != -1 ) + pProfile->bMedical = 1; + } + + // SANDRO - added to give 1 explosive skill to dmolitions + if ( pProfile->bExplosive == 0 && gGameOptions.fNewTraitSystem ) + { + iIndex = FindSkillInSkillsList( DEMOLITIONS_NT ); + if ( iIndex != -1 ) + pProfile->bExplosive = 1; + } + + // SANDRO - added to give 1 Leadership skill to Squadleaders + if ( pProfile->bLeadership == 0 && gGameOptions.fNewTraitSystem ) + { + // without medical, Doctor trait is useless + iIndex = FindSkillInSkillsList( SQUADLEADER_NT ); + if ( iIndex != -1 ) + pProfile->bLeadership = 1; + } if ( pProfile->bMarksmanship == 0 ) { // without marksmanship, the following traits are useless: - // auto weapons, heavy weapons - iIndex = FindSkillInSkillsList( AUTO_WEAPS ); - if( iIndex != -1 ) + // auto weapons, heavy weapons, sniper, ranger, gunslinger + + if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO { - //RemoveSkillFromSkillsList( iIndex ); - //iIndex = FindSkillInSkillsList( AUTO_WEAPS ); - pProfile->bMarksmanship = 1; + iIndex = FindSkillInSkillsList( AUTO_WEAPONS_NT ); + if( iIndex != -1 ) + pProfile->bMarksmanship = 1; + + iIndex = FindSkillInSkillsList( HEAVY_WEAPONS_NT ); + if( iIndex != -1 ) + pProfile->bMarksmanship = 1; + + iIndex = FindSkillInSkillsList( SNIPER_NT ); + if( iIndex != -1 ) + pProfile->bMarksmanship = 1; + + iIndex = FindSkillInSkillsList( RANGER_NT ); + if( iIndex != -1 ) + pProfile->bMarksmanship = 1; + + iIndex = FindSkillInSkillsList( GUNSLINGER_NT ); + if( iIndex != -1 ) + pProfile->bMarksmanship = 1; } - // so is lockpicking - iIndex = FindSkillInSkillsList( HEAVY_WEAPS ); - if( iIndex != -1 ) + else { - //RemoveSkillFromSkillsList( iIndex ); - //iIndex = FindSkillInSkillsList( HEAVY_WEAPS ); - pProfile->bMarksmanship = 1; + iIndex = FindSkillInSkillsList( AUTO_WEAPS_OT ); + if( iIndex != -1 ) + { + //RemoveSkillFromSkillsList( iIndex ); + //iIndex = FindSkillInSkillsList( AUTO_WEAPS_OT ); + pProfile->bMarksmanship = 1; + } + iIndex = FindSkillInSkillsList( HEAVY_WEAPS_OT ); + if( iIndex != -1 ) + { + //RemoveSkillFromSkillsList( iIndex ); + //iIndex = FindSkillInSkillsList( HEAVY_WEAPONS_NT ); + pProfile->bMarksmanship = 1; + } } } } void CreatePlayerSkills( void ) { - - // this function will 'roll a die' and decide if any attitude does exists - INT32 iDiceValue = 0; - ValidateSkillsList(); -/* Kaiden - Commented out in UB to skip the whole random skill thing - // roll dice - iDiceValue = Random( iLastElementInSkillsList ); - // set attitude - iSkillA = SkillsList[ iDiceValue ]; - - // second dice value - iDiceValue = Random( iLastElementInSkillsList ); - - iSkillB = SkillsList[ iDiceValue ]; -*/ - - // Kaiden: This section was added in it's place: + // Kaiden: This section was added in it's place: + // SANDRO - Note: this is actually used only for old trait system if( iLastElementInSkillsList > 0 ) { - // set attitude iSkillA = SkillsList[ 0 ]; } - if( iLastElementInSkillsList > 1 ) { iSkillB = SkillsList[ 1 ]; } - else - { - iSkillB = SkillsList[ 0 ]; - } - - // allow expert level for generated merc so you CAN have two of the same - // but there is no such thing as expert level for electronics - - - while ( iSkillA == iSkillB && ( iSkillB == ELECTRONICS || iSkillB == AMBIDEXT ) ) - { - // remove electronics as an option and roll again - RemoveSkillFromSkillsList( iDiceValue ); - if ( iLastElementInSkillsList == 0 ) - { - // ok, only one trait! - iSkillB = NO_SKILLTRAIT; - break; - } - else - { - iDiceValue = Random( iLastElementInSkillsList ); - iSkillB = SkillsList[ iDiceValue ]; - } - } - - /* - // are the same, - // reroll until different, or until ATTITUDE_LIST_SIZE times - iSkillB = Random( iLastElementInSkillsList + 1 ); - - while( (iSkillA == iSkillB ) && ( iCounter < HOW_MANY_ROLLS_FOR_SAME_SKILL_CHECK ) ) - { - // increment counter - iCounter++; - - // next random - iSkillB = Random( iLastElementInSkillsList + 1 ); - - } - if( iCounter == ATTITUDE_LIST_SIZE ) - { - iSkillB = NO_SKILLTRAIT; - } - return; - - - */ } @@ -604,82 +513,15 @@ void AddAPersonalityToPersonalityList( INT8 bPersonlity ) void CreatePlayerPersonality( void ) { + // DELETED UNUSED PART OF THE CODE - SANDRO - // Kaiden: Added for optional Mercenary personalities and attitudes - // We don't need this - SANDRO - /*if(gGameSettings.fOptions[TOPTION_USE_RANDOM_PERSONALITY] == TRUE) - { - // Kaiden: More chances for Psycho and Normal. - AddAPersonalityToPersonalityList( NO_PERSONALITYTRAIT ); - AddAPersonalityToPersonalityList( PSYCHO ); - AddAPersonalityToPersonalityList( FORGETFUL ); - AddAPersonalityToPersonalityList( NERVOUS ); - AddAPersonalityToPersonalityList( HEAT_INTOLERANT ); - AddAPersonalityToPersonalityList( NO_PERSONALITYTRAIT ); - AddAPersonalityToPersonalityList( PSYCHO ); - AddAPersonalityToPersonalityList( CLAUSTROPHOBIC ); - AddAPersonalityToPersonalityList( NONSWIMMER ); - AddAPersonalityToPersonalityList( FEAR_OF_INSECTS ); - AddAPersonalityToPersonalityList( NO_PERSONALITYTRAIT ); - AddAPersonalityToPersonalityList( PSYCHO ); - AddAPersonalityToPersonalityList( FORGETFUL ); - AddAPersonalityToPersonalityList( NERVOUS ); - AddAPersonalityToPersonalityList( HEAT_INTOLERANT ); - AddAPersonalityToPersonalityList( NO_PERSONALITYTRAIT ); - AddAPersonalityToPersonalityList( PSYCHO ); - AddAPersonalityToPersonalityList( CLAUSTROPHOBIC ); - AddAPersonalityToPersonalityList( NONSWIMMER ); - AddAPersonalityToPersonalityList( FEAR_OF_INSECTS ); - - - INT32 iDiceValue = 0; - INT32 iCounter = 0; - INT32 iCounter2 = 0; - - // Kaiden: Roll dice 20 times just to be on the safe side - // was getting too many repeats. Will end up scrapping - // rand() later anyway so will worry about fixing it then. - for (iCounter2 = 0; iCounter2 < 20; iCounter2++) - { - iDiceValue = Random( iLastElementInPersonalityList + 1 ); - } - - // Kaiden two chances to avoid a normal personality. As IMP - // says, They check it twice just to make sure :p - for( iCounter = 0; iCounter < iLastElementInPersonalityList; iCounter++ ) - { - - DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("iDiceValue = %d",iDiceValue)); - - if( PersonalityList[ iDiceValue ] == NO_PERSONALITYTRAIT ) - { - //Kaiden: Roll one more time for good measure: - iDiceValue = Random( iLastElementInPersonalityList + 1 ); - } - } - DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("And our Personality is... = %d",PersonalityList[ iDiceValue ])); - iPersonality = PersonalityList[ iDiceValue ]; - } - else - { - iPersonality = gGameExternalOptions.iCustomPersonality; - }*/ - - // Chosen by ourselves - SANDRO iPersonality = iChosenDisabilityTrait(); - return; - } - void CreatePlayersPersonalitySkillsAndAttitude( void ) { - - - - // creates personality, skills and attitudes from curretly built list // personality @@ -731,12 +573,52 @@ void ResetIncrementCharacterAttributes( void ) void SelectMercFace( void ) { +/* +UINT32 cnt; + + for ( cnt = 0; cnt < MAX_NEW_IMP_PORTRAITS; cnt++ ) + { + sFacePositions[ cnt ][ 0 ] = 0; + sFacePositions[ cnt ][ 1 ] = 0; + sFacePositions[ cnt ][ 2 ] = 0; + sFacePositions[ cnt ][ 3 ] = 0; + } + */ // this procedure will select the approriate face for the merc and save offsets // grab face filename // strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubUnusedFaceFileName , pPlayerSelectedFaceFileNames[ iPortraitNumber ]); + + if( fCharacterIsMale ) + { + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubFaceIndex = 200 + ( UINT8 )iPortraitNumber; + + // eyes + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usEyesX = sFacePositions[ gIMPMaleValues[iPortraitNumber].uiEyeXPositions ][ 0 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usEyesY = sFacePositions[ gIMPMaleValues[iPortraitNumber].uiEyeYPositions ][ 1 ]; + + // mouth + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthX = sFacePositions[ gIMPMaleValues[iPortraitNumber].uiMouthXPositions ][ 2 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthY = sFacePositions[ gIMPMaleValues[iPortraitNumber].uiMouthYPositions ][ 3 ]; + } + else + { + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubFaceIndex = 200 + ( UINT8 )iPortraitNumber; + + // eyes + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usEyesX = sFacePositions[ gIMPFemaleValues[iPortraitNumber].uiEyeXPositions ][ 0 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usEyesY = sFacePositions[ gIMPFemaleValues[iPortraitNumber].uiEyeYPositions ][ 1 ]; + + // mouth + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthX = sFacePositions[ gIMPFemaleValues[iPortraitNumber].uiMouthXPositions ][ 2 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthY = sFacePositions[ gIMPFemaleValues[iPortraitNumber].uiMouthYPositions ][ 3 ]; + + + } + // now the offsets + /* gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubFaceIndex = 200 + ( UINT8 )iPortraitNumber; // eyes @@ -746,7 +628,7 @@ void SelectMercFace( void ) // mouth gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthX = sFacePositions[ iPortraitNumber ][ 2 ]; gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthY = sFacePositions[ iPortraitNumber ][ 3 ]; - + */ // set merc skins and hair color SetMercSkinAndHairColors( ); return; @@ -754,40 +636,7 @@ void SelectMercFace( void ) void SetMercSkinAndHairColors( void ) { - // We don't need this - SANDRO - /*enum{ PINKSKIN, TANSKIN, DARKSKIN, BLACKSKIN, NUMSKINS }; - enum{ BROWNHEAD, BLACKHEAD, //black skin (only this line ) - WHITEHEAD, //dark skin (this line plus all above) - BLONDHEAD, REDHEAD, //pink/tan skin (this line plus all above ) - NUMHEADS - }; - - enum - { - WHITEVEST, - GYELLOWSHIRT, - YELLOWVEST, - GREYVEST, - BROWNVEST, - PURPLESHIRT, - BLUEVEST, - JEANVEST, - GREENVEST, - REDVEST, - BLACKSHIRT, - NUMSHIRTS - };//shirts - - enum - { - BLUEPANTS, - BLACKPANTS, - JEANPANTS, - TANPANTS, - BEIGEPANTS, - GREENPANTS, - NUMPANTS - };//pants*/ + // DELETED UNUSED PART OF THE CODE - SANDRO // skin strings STR sSkinStrings[]={ @@ -832,117 +681,8 @@ void SetMercSkinAndHairColors( void ) "GREENPANTS", };//pants - // We don't need this - SANDRO - // given the portrait number, set the merc's skin and hair color - /*INT16 sSkinColor = 0, sHairColor = 0, sShirtColor, sPantColor; + // DELETED UNUSED PART OF THE CODE - SANDRO - switch( iPortraitNumber ) - { - case( 0 ): - sSkinColor = BLACKSKIN; - sHairColor = BROWNHEAD; - sShirtColor = JEANVEST; - sPantColor = JEANPANTS; - break; - case( 1 ): - sSkinColor = TANSKIN; - sHairColor = BROWNHEAD; - sShirtColor = BROWNVEST; - sPantColor = TANPANTS; - break; - case( 2 ): - sSkinColor = TANSKIN; - sHairColor = BROWNHEAD; - sShirtColor = WHITEVEST; - sPantColor = BLUEPANTS; - break; - case( 3 ): - sSkinColor = DARKSKIN; - sHairColor = BROWNHEAD; - sShirtColor = WHITEVEST; - sPantColor = BLACKPANTS; - break; - case( 4 ): - sSkinColor = TANSKIN; - sHairColor = BROWNHEAD; - sShirtColor = GREYVEST; - sPantColor = GREENPANTS; - break; - case( 5 ): - sSkinColor = DARKSKIN; - sHairColor = BLACKHEAD; - sShirtColor = GREYVEST; - sPantColor = BLACKPANTS; - break; - case( 6 ): - sSkinColor = TANSKIN; - sHairColor = BROWNHEAD; - sShirtColor = BROWNVEST; - sPantColor = BLUEPANTS; - break; - case( 7 ): - sSkinColor = TANSKIN; - sHairColor = BROWNHEAD; - sShirtColor = BLACKSHIRT; - sPantColor = BLACKPANTS; - break; - case( 8 ): - sSkinColor = TANSKIN; - sHairColor = BROWNHEAD; - sShirtColor = BROWNVEST; - sPantColor = TANPANTS; - break; - case( 9 ): - sSkinColor = PINKSKIN; - sHairColor = BROWNHEAD; - sShirtColor = BROWNVEST; - sPantColor = BEIGEPANTS; - break; - case( 10 ): - sSkinColor = TANSKIN; - sHairColor = BLACKHEAD; - sShirtColor = BROWNVEST; - sPantColor = BLACKPANTS; - break; - case( 11 ): - sSkinColor = TANSKIN; - sHairColor = BLACKHEAD; - sShirtColor = BLACKSHIRT; - sPantColor = BLACKPANTS; - break; - case( 12 ): - sSkinColor = PINKSKIN; - sHairColor = BROWNHEAD; - sShirtColor = WHITEVEST; - sPantColor = GREENPANTS; - break; - case( 13 ): - sSkinColor = BLACKSKIN; - sHairColor = BROWNHEAD; - sShirtColor = GREYVEST; - sPantColor = BLACKPANTS; - break; - case( 14 ): - sSkinColor = TANSKIN; - sHairColor = REDHEAD; - sShirtColor = WHITEVEST; - sPantColor = JEANPANTS; - break; - case( 15 ): - sSkinColor = TANSKIN; - sHairColor = BLONDHEAD; - sShirtColor = BROWNVEST; - sPantColor = GREENPANTS; - break; - } - - // now set them - strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].HAIR, sHairStrings[ sHairColor ] ); - strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].SKIN, sSkinStrings[ sSkinColor ] ); - strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].PANTS, sPantStrings[ sPantColor ] ); - strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].VEST, sShirtStrings[ sShirtColor ] );*/ - - // Cosen colors by ourselves - SANDRO strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].HAIR, sHairStrings[ iChosenHair() ] ); strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].SKIN, sSkinStrings[ iChosenSkin() ] ); strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].PANTS, sPantStrings[ iChosenPants() ] ); @@ -957,9 +697,12 @@ void HandleMercStatsForChangesInFace( ) return; } - //add the skills to the skills list + //add the skills (major) to the skills list AddSelectedSkillsToSkillsList(); + if ( gGameOptions.fNewTraitSystem ) // SANDRO - add also minor traits + AddSelectedMinorTraitsToSkillsList(); + // now figure out skills CreatePlayerSkills(); @@ -969,60 +712,56 @@ void HandleMercStatsForChangesInFace( ) // male // big or regular // Madd - don't override the skills - override the body type instead - if( ShouldThisMercHaveABigBody() && iSkillA != MARTIALARTS && iSkillB != MARTIALARTS ) + // this should not happen any more, we don't even offer the martial arts to big mercs - SANDRO + //if( ShouldThisMercHaveABigBody() && iSkillA != MARTIALARTS_OT && iSkillB != MARTIALARTS_OT ) + if( ShouldThisMercHaveABigBody() ) // still added a safety check - SANDRO { - gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = BIGMALE; + if (!gGameOptions.fNewTraitSystem) // SANDRO - traits + { + if (iSkillA == MARTIALARTS_OT ) + iSkillA = HANDTOHAND_OT; + if (iSkillB == MARTIALARTS_OT ) + iSkillB = HANDTOHAND_OT; + } - //if( iSkillA == MARTIALARTS ) - //{ - // iSkillA = HANDTOHAND; - //} - //if( iSkillB == MARTIALARTS ) - //{ - // iSkillB = HANDTOHAND; - //} + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = BIGMALE; } else { - gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = REGMALE; - } + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = REGMALE; + } } else { - // female - gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = REGFEMALE; + // female + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = REGFEMALE; - if( iSkillA == MARTIALARTS ) + if (!gGameOptions.fNewTraitSystem) // SANDRO - traits { - iSkillA = HANDTOHAND; - } - if( iSkillB == MARTIALARTS ) - { - iSkillB = HANDTOHAND; + if( iSkillA == MARTIALARTS_OT ) + iSkillA = HANDTOHAND_OT; + if( iSkillB == MARTIALARTS_OT ) + iSkillB = HANDTOHAND_OT; } } - - // skill trait - gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTrait = ( INT8 )iSkillA; - gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTrait2 = ( INT8 )iSkillB; - + if (gGameOptions.fNewTraitSystem) + { + for ( UINT8 ubCnt = 0; ubCnt < gSkillTraitValues.ubMaxNumberOfTraits; ubCnt++ ) + { + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTraits[ ubCnt ] = ( INT8 )SkillsList[ ubCnt ]; + } + } + else + { + // skill trait + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTraits[0] = ( INT8 )iSkillA; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTraits[1] = ( INT8 )iSkillB; + } } BOOLEAN ShouldThisMercHaveABigBody( void ) { - // should this merc be a big body type - // Madd - don't limit it by portrait - //if ( ( iPortraitNumber == 0 ) || ( iPortraitNumber == 6 ) || ( iPortraitNumber == 7 ) ) - //{ - // if ( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bStrength >= 75 ) - // { - // return( TRUE ); - // } - //} - - //return( FALSE ); - // We can now choose this ourselves - SANDRO return( bBigBodySelected() ); } diff --git a/Laptop/IMP Compile Character.h b/Laptop/IMP Compile Character.h index c6647b10..d3487817 100644 --- a/Laptop/IMP Compile Character.h +++ b/Laptop/IMP Compile Character.h @@ -2,8 +2,8 @@ #define __IMP_COMPILE_H #define PLAYER_GENERATED_CHARACTER_ID 51 -#define ATTITUDE_LIST_SIZE 20 -#define NUMBER_OF_PLAYER_PORTRAITS 16 +#define ATTITUDE_LIST_SIZE 30 +#define NUMBER_OF_PLAYER_PORTRAITS 50 //16 void AddAnAttitudeToAttitudeList( INT8 bAttitude ); void CreatePlayerAttitude( void ); diff --git a/Laptop/IMP Confirm.cpp b/Laptop/IMP Confirm.cpp index 81e508fa..189c319b 100644 --- a/Laptop/IMP Confirm.cpp +++ b/Laptop/IMP Confirm.cpp @@ -34,9 +34,13 @@ #include "weapons.h" #include "Random.h" #include "GameVersion.h" + #include "faces.h" #include "GameSettings.h" #endif +#include +#include + // Changed by ADB (rev 1513) to resolve IMPs created prior to structural changes //#define IMP_FILENAME_SUFFIX ".dat" #define OLD_IMP_FILENAME_SUFFIX ".dat" @@ -60,6 +64,13 @@ void GiveIMPItems( MERCPROFILESTRUCT *pProfile, INT8 abilityValue, UINT8 typeInd UINT32 giIMPConfirmButton[ 2 ]; UINT32 giIMPConfirmButtonImage[ 2 ]; BOOLEAN fNoAlreadySelected = FALSE; + +IMP_FACE_VALUES gIMPFaceValues[200]; + +IMP_FEMALE_VALUES gIMPFemaleValues[200]; +IMP_MALE_VALUES gIMPMaleValues[200]; + +/* UINT16 uiEyeXPositions[ ]={ 8, 9, @@ -137,7 +148,7 @@ UINT16 uiMouthYPositions[]={ 24, //214 26, }; - +*/ BOOLEAN fLoadingCharacterForPreviousImpProfile = FALSE; void CreateConfirmButtons( void ); @@ -271,8 +282,23 @@ BOOLEAN AddCharacterToPlayersTeam( void ) HireMercStruct.ubInsertionCode = INSERTION_CODE_ARRIVING_GAME; HireMercStruct.uiTimeTillMercArrives = GetMercArrivalTimeOfDay( ); - SetProfileFaceData( HireMercStruct.ubProfileID , ( UINT8 ) ( 200 + iPortraitNumber ), uiEyeXPositions[ iPortraitNumber ], uiEyeYPositions[ iPortraitNumber ], uiMouthXPositions[ iPortraitNumber ], uiMouthYPositions[ iPortraitNumber ] ); - + + if( fCharacterIsMale ) + { + if ( gIMPMaleValues[ iPortraitNumber ].PortraitId !=0 ) + { + SetProfileFaceData( HireMercStruct.ubProfileID , (UINT8)(gIMPMaleValues[ iPortraitNumber ].PortraitId), gIMPMaleValues[ iPortraitNumber ].uiEyeXPositions, gIMPMaleValues[ iPortraitNumber ].uiEyeYPositions, gIMPMaleValues[ iPortraitNumber ].uiMouthXPositions, gIMPMaleValues[ iPortraitNumber ].uiMouthYPositions ); + } + } + else + { + if ( gIMPFemaleValues[ iPortraitNumber ].PortraitId !=0 ) + { + SetProfileFaceData( HireMercStruct.ubProfileID , (UINT8)(gIMPFemaleValues[ iPortraitNumber ].PortraitId), gIMPFemaleValues[ iPortraitNumber ].uiEyeXPositions, gIMPFemaleValues[ iPortraitNumber ].uiEyeYPositions, gIMPFemaleValues[ iPortraitNumber ].uiMouthXPositions, gIMPFemaleValues[ iPortraitNumber ].uiMouthYPositions ); + } + } + + //if we succesfully hired the merc if( !HireMerc( &HireMercStruct ) ) { @@ -310,18 +336,23 @@ void BtnIMPConfirmYes(GUI_BUTTON *btn,INT32 reason) return; } */ - if( LaptopSaveInfo.iCurrentBalance < COST_OF_PROFILE ) + // SANDRO - changed to find the actual profile cost + //if( LaptopSaveInfo.iCurrentBalance < COST_OF_PROFILE ) + if( LaptopSaveInfo.iCurrentBalance < iGetProfileCost() ) { // not enough - return; + return; } // line moved by CJC Nov 28 2002 to AFTER the check for money LaptopSaveInfo.fIMPCompletedFlag = TRUE; // charge the player - AddTransactionToPlayersBook(IMP_PROFILE, (UINT8)(LaptopSaveInfo.iIMPIndex), GetWorldTotalMin( ), - ( COST_OF_PROFILE ) ); - AddHistoryToPlayersLog( HISTORY_CHARACTER_GENERATED, 0,GetWorldTotalMin( ), -1, -1 ); + // SANDRO - changed to find the actual profile cost + //AddTransactionToPlayersBook(IMP_PROFILE, (UINT8)(LaptopSaveInfo.iIMPIndex), GetWorldTotalMin( ), - ( COST_OF_PROFILE ) ); + AddTransactionToPlayersBook(IMP_PROFILE, (UINT8)(LaptopSaveInfo.iIMPIndex), GetWorldTotalMin( ), - ( iGetProfileCost() ) ); + + AddHistoryToPlayersLog( HISTORY_CHARACTER_GENERATED, 0,GetWorldTotalMin( ), -1, -1 ); AddCharacterToPlayersTeam( ); // write the created imp merc @@ -426,9 +457,11 @@ void BtnIMPConfirmNo( GUI_BUTTON *btn,INT32 reason ) } */ - -#define PROFILE_HAS_SKILL_TRAIT( p, t ) ((p->bSkillTrait == t) || (p->bSkillTrait2 == t)) - +// SANDRO - improved this function +//#define PROFILE_HAS_SKILL_TRAIT( p, t ) ( gGameOptions.fNewTraitSystem ? ((p->bSkillTrait == t) || (p->bSkillTrait2 == t) || (p->bSkillTrait3 == t)) : ((p->bSkillTrait == t) || (p->bSkillTrait2 == t))) +#define PROFILE_HAS_SKILL_TRAIT( p, t ) ( ProfileHasSkillTrait( p, t ) > 0 ) +// DBrot: need a check for experts +#define PROFILE_HAS_EXPERT_TRAIT( p, t ) ( ProfileHasSkillTrait( p, t ) > 1 ) //CHRISL: New function to handle proper distribution of starting gear void DistributeInitialGear(MERCPROFILESTRUCT *pProfile) { @@ -560,101 +593,26 @@ void DistributeInitialGear(MERCPROFILESTRUCT *pProfile) } } - void GiveItemsToPC( UINT8 ubProfileId ) { MERCPROFILESTRUCT *pProfile; - // gives starting items to merc // NOTE: Any guns should probably be from those available in regular gun set pProfile = &(gMercProfiles[ubProfileId]); - // STANDARD EQUIPMENT + // SANDRO - obsolete code deleted GiveIMPItems(pProfile, 100, IMP_DEFAULT); GiveIMPRandomItems(pProfile, IMP_RANDOMDEFAULT); - - // kevlar vest, leggings, & helmet -// MakeProfileInvItemThisSlot(pProfile, VESTPOS, FLAK_JACKET, 100, 1); - GiveIMPItems (pProfile,pProfile->bWisdom,IMP_WISDOM); - - - //if ( PreRandom( 100 ) < (UINT32) pProfile->bWisdom ) - //{ - // MakeProfileInvItemThisSlot(pProfile, HELMETPOS, STEEL_HELMET, 100, 1); - //} - - // canteen -// MakeProfileInvItemThisSlot(pProfile, SMALLPOCK4POS, CANTEEN, 100, 1); - GiveIMPItems (pProfile,pProfile->bMarksmanship,IMP_MARKSMANSHIP); - - - //Give ANY imp the calico -// MakeProfileInvItemThisSlot( pProfile, HANDPOS, M950, 100, 1); - - - - //No ammo clip MakeProfileInvItemThisSlot( pProfile, SMALLPOCK1POS, CLIP9_30, 100, 2); - - /* - Ja25 IMP only gets 1 gun now - - - - - if (pProfile->bMarksmanship >= 80) - { - // good shooters get a better & matching ammo - MakeProfileInvItemThisSlot( pProfile, HANDPOS, MP5K, 100, 1); - MakeProfileInvItemThisSlot( pProfile, SMALLPOCK1POS, CLIP9_30, 100, 2); - } - else - { - // Automatic pistol, with matching ammo - MakeProfileInvItemThisSlot( pProfile, HANDPOS, BERETTA_93R, 100, 1 ); - MakeProfileInvItemThisSlot( pProfile, SMALLPOCK1POS, CLIP9_15, 100, 3 ); - } - */ - - // OPTIONAL EQUIPMENT: depends on skills & special skills - GiveIMPItems (pProfile,pProfile->bMedical,IMP_MEDICAL); - - //if (pProfile->bMedical >= 60) - //{ - // // strong medics get full medic kit - // MakeProfileInvItemAnySlot(pProfile, MEDICKIT, 100, 1); - //} - //else - //if (pProfile->bMedical >= 30) - //{ - // // passable medics get first aid kit - // MakeProfileInvItemAnySlot(pProfile, FIRSTAIDKIT, 100, 1); - //} - GiveIMPItems (pProfile,pProfile->bMechanical,IMP_MECHANICAL); - - //if (pProfile->bMechanical >= 50) - //{ - // // mechanics get toolkit - // MakeProfileInvItemAnySlot(pProfile, TOOLKIT, 100, 1); - //} - GiveIMPItems (pProfile,pProfile->bExplosive,IMP_EXPLOSIVE); - - //if (pProfile->bExplosive >= 50) - //{ - // // loonies get TNT & Detonator - //MakeProfileInvItemAnySlot(pProfile, TNT, 100, 1); - //MakeProfileInvItemAnySlot(pProfile, DETONATOR, 100, 1); - //} - GiveIMPItems (pProfile,pProfile->bAgility,IMP_AGILITY); GiveIMPItems (pProfile,pProfile->bDexterity,IMP_DEXTERITY); GiveIMPItems (pProfile,pProfile->bStrength,IMP_STRENGTH); @@ -662,89 +620,309 @@ void GiveItemsToPC( UINT8 ubProfileId ) GiveIMPItems (pProfile,pProfile->bLeadership,IMP_LEADERSHIP); // check for special skills - if (PROFILE_HAS_SKILL_TRAIT(pProfile, LOCKPICKING) && ( iMechanical ) ) + ///////////////////////////////////////////////////////////////////// + // Check for new traits - SANDRO + // DBrot: experts get other stuff + if ( gGameOptions.fNewTraitSystem ) { - //MakeProfileInvItemAnySlot(pProfile, LOCKSMITHKIT, 100, 1); - GiveIMPRandomItems(pProfile,IMP_LOCKPICKING); + // MAJOR TRAITS + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, AUTO_WEAPONS_NT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, AUTO_WEAPONS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_AUTO_WEAPONS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_AUTO_WEAPONS); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, HEAVY_WEAPONS_NT )) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, HEAVY_WEAPONS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_HEAVY_WEAPONS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_HEAVY_WEAPONS); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, SNIPER_NT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, SNIPER_NT)) + { + GiveIMPRandomItems(pProfile,IMP_SNIPER_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_SNIPER); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, RANGER_NT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, RANGER_NT)) + { + GiveIMPRandomItems(pProfile,IMP_RANGER_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_RANGER); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, GUNSLINGER_NT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, GUNSLINGER_NT)) + { + GiveIMPRandomItems(pProfile,IMP_GUNSLINGER_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_GUNSLINGER); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, MARTIAL_ARTS_NT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, MARTIAL_ARTS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_MARTIAL_ARTS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_MARTIAL_ARTS); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, SQUADLEADER_NT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, SQUADLEADER_NT)) + { + GiveIMPRandomItems(pProfile,IMP_SQUADLEADER_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_SQUADLEADER); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, TECHNICIAN_NT) && ( iMechanical ) ) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, TECHNICIAN_NT)) + { + GiveIMPRandomItems(pProfile,IMP_TECHNICIAN_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_TECHNICIAN); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, DOCTOR_NT )) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, DOCTOR_NT)) + { + GiveIMPRandomItems(pProfile,IMP_DOCTOR_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_DOCTOR); + } + } + // MINOR TRAITS + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, AMBIDEXTROUS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_AMBIDEXTROUS); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, MELEE_NT)) + { + GiveIMPRandomItems(pProfile,IMP_MELEE); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, THROWING_NT)) + { + GiveIMPRandomItems(pProfile,IMP_THROWING); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, NIGHT_OPS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_NIGHT_OPS); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, STEALTHY_NT)) + { + GiveIMPRandomItems(pProfile,IMP_STEALTHY); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, ATHLETICS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_ATHLETICS); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, BODYBUILDING_NT)) + { + GiveIMPRandomItems(pProfile,IMP_BODYBUILDING); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, DEMOLITIONS_NT)) + { + GiveIMPRandomItems(pProfile,IMP_DEMOLITIONS); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, TEACHING_NT)) + { + GiveIMPRandomItems(pProfile,IMP_TEACHING); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, SCOUTING_NT)) + { + GiveIMPRandomItems(pProfile,IMP_SCOUTING); + } + } + else + { + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, LOCKPICKING_OT) && ( iMechanical ) ) + { + //MakeProfileInvItemAnySlot(pProfile, LOCKSMITHKIT, 100, 1); + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, LOCKPICKING_OT)) + { + GiveIMPRandomItems(pProfile,IMP_LOCKPICKING_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_LOCKPICKING); + } + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, ELECTRONICS_OT) && ( iMechanical ) ) + { + //MakeProfileInvItemAnySlot(pProfile, METALDETECTOR, 100, 1); + GiveIMPRandomItems(pProfile,IMP_ELECTRONICS); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, CAMOUFLAGED_OT)) // TODO: Madd - other camouflage types, once we figure out a way to enable more traits + { + //MakeProfileInvItemAnySlot(pProfile, CAMOUFLAGEKIT, 100, 1); + GiveIMPRandomItems(pProfile,IMP_CAMOUFLAGED); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, AMBIDEXT_OT)) + { + //MakeProfileInvItemAnySlot(pProfile, M950, 100, 1); + GiveIMPRandomItems(pProfile,IMP_AMBIDEXTROUS); + } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, NIGHTOPS_OT)) + { +// MakeProfileInvItemAnySlot(pProfile, SILENCER, 100, 2); + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, NIGHTOPS_OT)) + { + GiveIMPRandomItems(pProfile,IMP_NIGHT_OPS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_NIGHT_OPS); + } + } + + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, HANDTOHAND_OT)) + { + //MakeProfileInvItemAnySlot(pProfile, BRASS_KNUCKLES, 100, 1); + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, HANDTOHAND_OT)) + { + GiveIMPRandomItems(pProfile,IMP_MARTIAL_ARTS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_MARTIAL_ARTS); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, HANDTOHAND)) - { - //MakeProfileInvItemAnySlot(pProfile, BRASS_KNUCKLES, 100, 1); - GiveIMPRandomItems(pProfile,IMP_HTH); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, THROWING_OT)) + { +// MakeProfileInvItemAnySlot(pProfile, THROWING_KNIFE, 100, 1); + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, THROWING_OT)) + { + GiveIMPRandomItems(pProfile,IMP_THROWING_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_THROWING); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, ELECTRONICS) && ( iMechanical ) ) - { - //MakeProfileInvItemAnySlot(pProfile, METALDETECTOR, 100, 1); - GiveIMPRandomItems(pProfile,IMP_ELECTRONICS); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, STEALTHY_OT)) + { +// MakeProfileInvItemAnySlot(pProfile, SILENCER, 100, 1); + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, STEALTHY_OT)) + { + GiveIMPRandomItems(pProfile,IMP_STEALTHY_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_STEALTHY); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, NIGHTOPS)) - { -// MakeProfileInvItemAnySlot(pProfile, SILENCER, 100, 2); - GiveIMPRandomItems(pProfile,IMP_NIGHTOPS); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, KNIFING_OT)) + { +// MakeProfileInvItemAnySlot(pProfile, COMBAT_KNIFE, 100, 1); + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, KNIFING_OT)) + { + GiveIMPRandomItems(pProfile,IMP_MELEE_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_MELEE); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, THROWING)) - { -// MakeProfileInvItemAnySlot(pProfile, THROWING_KNIFE, 100, 1); - GiveIMPRandomItems(pProfile,IMP_THROWING); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, MARTIALARTS_OT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, MARTIALARTS_OT)) + { + GiveIMPRandomItems(pProfile,IMP_MARTIAL_ARTS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_MARTIAL_ARTS); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, STEALTHY)) - { -// MakeProfileInvItemAnySlot(pProfile, SILENCER, 100, 1); - GiveIMPRandomItems(pProfile,IMP_STEALTHY); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, PROF_SNIPER_OT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, PROF_SNIPER_OT)) + { + GiveIMPRandomItems(pProfile,IMP_SNIPER_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_SNIPER); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, KNIFING)) - { -// MakeProfileInvItemAnySlot(pProfile, COMBAT_KNIFE, 100, 1); - GiveIMPRandomItems(pProfile,IMP_KNIFING); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, TEACHING_OT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, TEACHING_OT)) + { + GiveIMPRandomItems(pProfile,IMP_TEACHING_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_TEACHING); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, CAMOUFLAGED)) // TODO: Madd - other camouflage types, once we figure out a way to enable more traits - { -// MakeProfileInvItemAnySlot(pProfile, CAMOUFLAGEKIT, 100, 1); - GiveIMPRandomItems(pProfile,IMP_CAMOUFLAGED); - } + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, AUTO_WEAPS_OT)) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, AUTO_WEAPS_OT)) + { + GiveIMPRandomItems(pProfile,IMP_AUTO_WEAPONS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_AUTO_WEAPONS); + } + } - if (PROFILE_HAS_SKILL_TRAIT(pProfile, AMBIDEXT)) - { -// MakeProfileInvItemAnySlot(pProfile, M950, 100, 1); - GiveIMPRandomItems(pProfile,IMP_AMBIDEXTROUS); - } - - if (PROFILE_HAS_SKILL_TRAIT(pProfile, MARTIALARTS)) - { - GiveIMPRandomItems(pProfile,IMP_MARTIALARTS); - } - - if (PROFILE_HAS_SKILL_TRAIT(pProfile, PROF_SNIPER)) - { - GiveIMPRandomItems(pProfile,IMP_PROF_SNIPER); - } - - if (PROFILE_HAS_SKILL_TRAIT(pProfile, TEACHING)) - { - GiveIMPRandomItems(pProfile,IMP_TEACHING); - } - - if (PROFILE_HAS_SKILL_TRAIT(pProfile, AUTO_WEAPS)) - { - GiveIMPRandomItems(pProfile,IMP_AUTOWEAPONS); - } - - if (PROFILE_HAS_SKILL_TRAIT(pProfile, HEAVY_WEAPS )) - { - GiveIMPRandomItems(pProfile,IMP_HEAVYWEAPONS); - } - - if (PROFILE_HAS_SKILL_TRAIT(pProfile, THIEF )) - { - GiveIMPRandomItems(pProfile,IMP_THIEF); + if (PROFILE_HAS_SKILL_TRAIT(ubProfileId, HEAVY_WEAPS_OT )) + { + if( gGameExternalOptions.fExpertsGetDifferentChoices && PROFILE_HAS_EXPERT_TRAIT(ubProfileId, HEAVY_WEAPS_OT)) + { + GiveIMPRandomItems(pProfile,IMP_HEAVY_WEAPONS_EXP); + } + else + { + GiveIMPRandomItems(pProfile, IMP_HEAVY_WEAPONS); + } + } } + ///////////////////////////////////////////////////////////////////// // CHRISL: Now that all items have been issued, distribute them into appropriate pockets, starting with the largest items DistributeInitialGear(pProfile); @@ -871,7 +1049,8 @@ INT32 SpecificFreePocket(MERCPROFILESTRUCT *pProfile, UINT16 usItem, UINT8 ubHow { if(LoadBearingEquipment[Item[usItem].ubClassIndex].lbeCombo!=0) { - if((pProfile->inv[BPACKPOCKPOS]!=NONE && LoadBearingEquipment[Item[pProfile->inv[BPACKPOCKPOS]].ubClassIndex].lbeCombo==LoadBearingEquipment[Item[usItem].ubClassIndex].lbeCombo) || pProfile->inv[BPACKPOCKPOS]==NONE) + //DBrot: changed to bitwise comparison + if((pProfile->inv[BPACKPOCKPOS]!=NONE && (LoadBearingEquipment[Item[pProfile->inv[BPACKPOCKPOS]].ubClassIndex].lbeCombo & LoadBearingEquipment[Item[usItem].ubClassIndex].lbeCombo)) || pProfile->inv[BPACKPOCKPOS]==NONE) return CPACKPOCKPOS; } else if(pProfile->inv[BPACKPOCKPOS]==NONE) @@ -884,7 +1063,8 @@ INT32 SpecificFreePocket(MERCPROFILESTRUCT *pProfile, UINT16 usItem, UINT8 ubHow { if(LoadBearingEquipment[Item[usItem].ubClassIndex].lbeCombo!=0) { - if((pProfile->inv[CPACKPOCKPOS]!=NONE && LoadBearingEquipment[Item[pProfile->inv[CPACKPOCKPOS]].ubClassIndex].lbeCombo==LoadBearingEquipment[Item[usItem].ubClassIndex].lbeCombo) || pProfile->inv[CPACKPOCKPOS]==NONE) + //DBrot: changed to bitwise comparison + if((pProfile->inv[CPACKPOCKPOS]!=NONE && (LoadBearingEquipment[Item[pProfile->inv[CPACKPOCKPOS]].ubClassIndex].lbeCombo & LoadBearingEquipment[Item[usItem].ubClassIndex].lbeCombo)) || pProfile->inv[CPACKPOCKPOS]==NONE) return BPACKPOCKPOS; } else if(pProfile->inv[CPACKPOCKPOS]==NONE) @@ -1117,8 +1297,6 @@ INT32 AnyFreeBigEnoughPocket(MERCPROFILESTRUCT *pProfile, INVNODE *tInv) return(-1); } -#include "VFS/vfs.h" -#include "VFS/vfs_settings.h" void WriteOutCurrentImpCharacter( INT32 iProfileId ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("WriteOutCurrentImpCharacter: IMP.dat")); @@ -1145,11 +1323,11 @@ void WriteOutCurrentImpCharacter( INT32 iProfileId ) char zFileName[32]; if(vfs::Settings::getUseUnicode()) { - strncpy(zFileName, utf8string::as_utf8(gMercProfiles[iProfileId].zNickname,10).c_str(), 32); + strncpy(zFileName, vfs::String::as_utf8(gMercProfiles[iProfileId].zNickname,10).c_str(), 32); } else { - utf8string::narrow(gMercProfiles[iProfileId].zNickname, 10, zFileName, 32); + vfs::String::narrow(gMercProfiles[iProfileId].zNickname, 10, zFileName, 32); } #endif @@ -1339,20 +1517,31 @@ BOOLEAN LoadImpCharacter( STR nickName ) //CHRISL: At this point, we need to resort profile inventory so that NewInv items don't accidentally appear in OldInv DistributeInitialGear(&gMercProfiles[iProfileId]); - if( LaptopSaveInfo.iCurrentBalance < COST_OF_PROFILE ) + // Changed to find actual IMP cost - SANDRO + if( LaptopSaveInfo.iCurrentBalance < iGetProfileCost() ) { DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 3 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); // not enough return FALSE; } + + //new camo face + if ( gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + gCamoFace[iProfileId].gCamoface = TRUE; + gCamoFace[iProfileId].gUrbanCamoface = FALSE; + gCamoFace[iProfileId].gDesertCamoface = FALSE; + gCamoFace[iProfileId].gSnowCamoface = FALSE; + } // charge the player // is the character male? fCharacterIsMale = ( gMercProfiles[ iProfileId ].bSex == MALE ); fLoadingCharacterForPreviousImpProfile = TRUE; - AddTransactionToPlayersBook(IMP_PROFILE,0, GetWorldTotalMin( ), - ( COST_OF_PROFILE ) ); + // Changed to find actual IMP cost - SANDRO + AddTransactionToPlayersBook(IMP_PROFILE,0, GetWorldTotalMin( ), - ( iGetProfileCost() ) ); AddHistoryToPlayersLog( HISTORY_CHARACTER_GENERATED, 0,GetWorldTotalMin( ), -1, -1 ); LaptopSaveInfo.iIMPIndex = iProfileId; AddCharacterToPlayersTeam( ); @@ -1383,38 +1572,86 @@ BOOLEAN LoadImpCharacter( STR nickName ) void ResetIMPCharactersEyesAndMouthOffsets( UINT8 ubMercProfileID ) { // ATE: Check boundary conditions! - if( ( ( gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ) > 16 ) || ( ubMercProfileID >= PROF_HUMMER ) ) + if( ( ( gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ) > MAX_NEW_IMP_PORTRAITS ) || ( ubMercProfileID >= PROF_HUMMER ) ) // 16 { return; } + /* + gMercProfiles[ ubMercProfileID ].usEyesX = gIMPFaceValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiEyeXPositions; + gMercProfiles[ ubMercProfileID ].usEyesY = gIMPFaceValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiEyeYPositions; - gMercProfiles[ ubMercProfileID ].usEyesX = uiEyeXPositions[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ]; - gMercProfiles[ ubMercProfileID ].usEyesY = uiEyeYPositions[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ]; + gMercProfiles[ ubMercProfileID ].usMouthX = gIMPFaceValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiMouthXPositions; + gMercProfiles[ ubMercProfileID ].usMouthY = gIMPFaceValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiMouthYPositions; + */ + + if( gMercProfiles[ ubMercProfileID ].bSex == 0 ) + { + gMercProfiles[ ubMercProfileID ].usEyesX = gIMPMaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiEyeXPositions; + gMercProfiles[ ubMercProfileID ].usEyesY = gIMPMaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiEyeYPositions; - gMercProfiles[ ubMercProfileID ].usMouthX = uiMouthXPositions[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ]; - gMercProfiles[ ubMercProfileID ].usMouthY = uiMouthYPositions[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ]; + gMercProfiles[ ubMercProfileID ].usMouthX = gIMPMaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiMouthXPositions; + gMercProfiles[ ubMercProfileID ].usMouthY = gIMPMaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiMouthYPositions; + } + else + { + gMercProfiles[ ubMercProfileID ].usEyesX = gIMPFemaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiEyeXPositions; + gMercProfiles[ ubMercProfileID ].usEyesY = gIMPFemaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiEyeYPositions; + + gMercProfiles[ ubMercProfileID ].usMouthX = gIMPFemaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiMouthXPositions; + gMercProfiles[ ubMercProfileID ].usMouthY = gIMPFemaleValues[ gMercProfiles[ ubMercProfileID ].ubFaceIndex - 200 ].uiMouthYPositions; + } + } void GiveIMPRandomItems( MERCPROFILESTRUCT *pProfile, UINT8 typeIndex ) { + ///////////////////////////////////////////////////////////////////// + // SANDRO - I've changed this formula a bit, <- me too - silversurfer + // now it should not take the same choice twice + ///////////////////////////////////////////////////////////////////// DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("GiveIMPRandomItems: typeIndex = %d",typeIndex )); UINT16 usItem = 0; INT32 iChoice; + UINT8 ubValidChoices = 0; + UINT8 ubNumChoices = gIMPItemChoices[ typeIndex ].ubChoices; + UINT8 ubNumItemsToGive = 0; + BOOLEAN ubItemsGiven[ 50 ]={FALSE}; - if ( gIMPItemChoices[ typeIndex ].ubChoices <= 0 ) - return; - - for ( int i=0; i < gIMPItemChoices[typeIndex].ubNumItems ;i++ ) + // check how many legal items are in the choices list, this is to prevent infinite loop + for ( UINT8 cnt=0; cnt < ubNumChoices; cnt++ ) { + usItem = gIMPItemChoices[ typeIndex ].bItemNo[ cnt ]; + if ( ItemIsLegal(usItem) ) + ubValidChoices++; + } + + // if no valid items found, bail out + if ( ubValidChoices <= 0 ) + return; + + // define how many items we get + if ( ubValidChoices < gIMPItemChoices[typeIndex].ubNumItems ) + // if there are less legal items than the number we should get, we only get the number of legal items + ubNumItemsToGive = ubValidChoices; + else + // give us the maximum possible + ubNumItemsToGive = gIMPItemChoices[typeIndex].ubNumItems; + + for ( int i=0; i < ubNumItemsToGive ;i++ ) + { + usItem = 0; while (usItem == 0 ) { - iChoice = Random(gIMPItemChoices[ typeIndex ].ubChoices); - usItem = gIMPItemChoices[ typeIndex ].bItemNo[ iChoice ]; - if (!ItemIsLegal(usItem)) - usItem=0; + iChoice = Random( ubNumChoices ); + usItem = gIMPItemChoices[ typeIndex ].bItemNo[ iChoice ]; + // is this legal and we don't have it already? + if (ItemIsLegal(usItem) && !ubItemsGiven[iChoice] ) + ubItemsGiven[iChoice] = TRUE; + else + usItem=0; } DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("GiveIMPRandomItems: typeIndex = %d, usItem = %d ",typeIndex, usItem )); if ( usItem > 0 ) @@ -1491,5 +1728,23 @@ void GiveIMPItems( MERCPROFILESTRUCT *pProfile, INT8 abilityValue, UINT8 typeInd } +// SANDRO - Function to determine actual cost of profile +INT32 iGetProfileCost() +{ + if (gGameExternalOptions.fDynamicIMPProfileCost) + { + INT32 iIMPProfileCost; + + iIMPProfileCost = gGameExternalOptions.iIMPProfileCost * CountFilledIMPSlots(-1); + + if (iIMPProfileCost >= gGameExternalOptions.iIMPProfileCost) + return(iIMPProfileCost); + else + return(gGameExternalOptions.iIMPProfileCost); + } + else + return(gGameExternalOptions.iIMPProfileCost); +} + diff --git a/Laptop/IMP Confirm.h b/Laptop/IMP Confirm.h index b1aeaead..2bba2a9d 100644 --- a/Laptop/IMP Confirm.h +++ b/Laptop/IMP Confirm.h @@ -6,6 +6,76 @@ void RenderIMPConfirm( void ); void ExitIMPConfirm( void ); void HandleIMPConfirm( void ); +#define MAX_NEW_IMP_PORTRAITS 50 + +typedef struct +{ + UINT16 uiEyeXPositions; + UINT16 uiEyeYPositions; + UINT16 uiMouthXPositions; + UINT16 uiMouthYPositions; + UINT16 uiIndex; + UINT16 FaceIndex; + UINT16 PortraitId; + BOOLEAN bSex; + INT32 iCurrentSkin; + INT32 iCurrentHair; + INT32 iCurrentShirt; + INT32 iCurrentPants; + BOOLEAN bBigBody; + BOOLEAN bBadAss; + +} IMP_FACE_VALUES; + +extern IMP_FACE_VALUES gIMPFaceValues[200]; + + +typedef struct +{ + UINT16 uiIndexIMP; + BOOLEAN Enabled; + + UINT16 uiEyeXPositions; + UINT16 uiEyeYPositions; + UINT16 uiMouthXPositions; + UINT16 uiMouthYPositions; + UINT16 uiIndex; + UINT16 FaceIndex; + UINT16 PortraitId; + BOOLEAN bSex; + INT32 iCurrentSkin; + INT32 iCurrentHair; + INT32 iCurrentShirt; + INT32 iCurrentPants; + BOOLEAN bBigBody; + BOOLEAN bBadAss; + +} IMP_MALE_VALUES; + +typedef struct +{ + UINT16 uiIndexIMP; + BOOLEAN Enabled; + + UINT16 uiEyeXPositions; + UINT16 uiEyeYPositions; + UINT16 uiMouthXPositions; + UINT16 uiMouthYPositions; + UINT16 uiIndex; + UINT16 FaceIndex; + UINT16 PortraitId; + BOOLEAN bSex; + INT32 iCurrentSkin; + INT32 iCurrentHair; + INT32 iCurrentShirt; + INT32 iCurrentPants; + BOOLEAN bBigBody; + BOOLEAN bBadAss; +} IMP_FEMALE_VALUES; + +extern IMP_FEMALE_VALUES gIMPFemaleValues[200]; +extern IMP_MALE_VALUES gIMPMaleValues[200]; + BOOLEAN AddCharacterToPlayersTeam( void ); BOOLEAN LoadImpCharacter( STR fileName ); void WriteOutCurrentImpCharacter( INT32 iProfileId ); @@ -15,5 +85,7 @@ void ResetIMPCharactersEyesAndMouthOffsets( UINT8 ubMercProfileID ); BOOLEAN ImpExists ( STR fileName ); +INT32 iGetProfileCost( void ); // added by SANDRO + #endif diff --git a/Laptop/IMP Disability Trait.cpp b/Laptop/IMP Disability Trait.cpp index 48ce631d..3b85ddea 100644 --- a/Laptop/IMP Disability Trait.cpp +++ b/Laptop/IMP Disability Trait.cpp @@ -78,6 +78,8 @@ INT32 giIMPDisabilityTraitFinsihButtonImage; //image handle UINT32 guiIST_GreyGoldBox3; +MOUSE_REGION gMR_DisabilityHelpTextRegions[ IMP_DISABILITIES_NUMBER ]; + //******************************************************************* // // Function Prototypes @@ -93,6 +95,7 @@ void IMPDisabilityTraitDisplayDisabilityTraits(); BOOLEAN CameBackToDisabilityTraitPageButNotFinished(); +void AssignDisabilityHelpText( UINT8 ubNumber ); //******************************************************************* // @@ -141,7 +144,18 @@ void EnterIMPDisabilityTrait( void ) } HandleDisabilityTraitButtonStates( ); - + + // add regions for help texts + UINT16 usPosY = IMP_DISABILITY_COLUMN_START_Y + 8; + for( UINT8 ubCnt=0; ubCntubSoundSchemeID = 0; + //ButtonList[ giIMPDisabilityTraitAnswerButton[ ubCnt ] ]->ubSoundSchemeID = 0; //Determine the next x location - //if( iCnt < IMP_DISABILITY_TRAIT_NUMBER_TO_START_2ND_COLUMN ) + //if( ubCnt < IMP_DISABILITY_TRAIT_NUMBER_TO_START_2ND_COLUMN ) usPosX = IMP_DISABILITY_COLUMN_START_X; //else // usPosX = IMP_DISABILITY_2ND_COLUMN_START_X; //Determine the next Y location - //if( iCnt == IMP_DISABILITY_TRAIT_NUMBER_TO_START_2ND_COLUMN ) + //if( ubCnt == IMP_DISABILITY_TRAIT_NUMBER_TO_START_2ND_COLUMN ) // usPosY = IMP_DISABILITY_2ND_COLUMN_START_Y; //else usPosY += IMP_DISABILITY_TRAIT__SPACE_BTN_BUTTONS; @@ -258,7 +274,7 @@ void BtnIMPDisabilityTraitAnswerCallback(GUI_BUTTON *btn,INT32 reason) void HandleIMPDisabilityTraitAnswers( UINT32 uiSkillPressed ) { - UINT32 uiCnt; + UINT8 ubCnt; //if we are DONE and are just reviewing if( iCurrentProfileMode == IMP__FINISH ) @@ -267,9 +283,9 @@ void HandleIMPDisabilityTraitAnswers( UINT32 uiSkillPressed ) } //reset all other buttons - for( uiCnt=0; uiCntuiFlags |= BUTTON_CLICKED_ON; + ButtonList[ giIMPDisabilityTraitAnswerButton[ ubCnt ] ]->uiFlags |= BUTTON_CLICKED_ON; } else { - ButtonList[ giIMPDisabilityTraitAnswerButton[ uiCnt ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + ButtonList[ giIMPDisabilityTraitAnswerButton[ ubCnt ] ]->uiFlags &= ~BUTTON_CLICKED_ON; } } } void IMPDisabilityTraitDisplayDisabilityTraits() { - UINT32 uiCnt; + UINT8 ubCnt; UINT16 usPosX, usPosY; UINT16 usBoxPosX, usBoxPosY; HVOBJECT hImageHandle; @@ -342,13 +357,13 @@ void IMPDisabilityTraitDisplayDisabilityTraits() usPosX = IMP_DISABILITY_COLUMN_START_X + IMP_DISABILITY_TRAIT__TEXT_OFFSET_X; usPosY = IMP_DISABILITY_COLUMN_START_Y + IMP_DISABILITY_TRAIT__TEXT_OFFSET_Y; - for( uiCnt=0; uiCntuiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { +// btn->uiFlags|=(BUTTON_CLICKED_ON); + + INT32 iMinorTrait = MSYS_GetBtnUserData( btn, 0 ); + + HandleIMPMinorTraitAnswers( iMinorTrait ); + } +} + +void HandleIMPMinorTraitAnswers( UINT32 uiSkillPressed ) +{ + UINT32 uiCnt; + + //if we are DONE and are just reviewing + if( iCurrentProfileMode == IMP__FINISH ) + { + return; + } + + //make sure its a valid skill + if( uiSkillPressed > IMP_SKILL_TRAITS_NEW_NUMBER_MINOR_SKILLS ) + { + Assert( 0 ); + return; + } + + //if its allready set + if( gfMinorTraitQuestions[ uiSkillPressed ] && uiSkillPressed != IMP_SKILL_TRAITS_NEW_MINOR_NONE ) + { + gfMinorTraitQuestions[ uiSkillPressed ] = FALSE; + + BOOLEAN fNoSkillSelected = TRUE; + for ( uiCnt=0; uiCnt<(IMP_SKILL_TRAITS_NEW_MINOR_NONE); uiCnt++ ) + { + if ( gfMinorTraitQuestions[ uiCnt ] == TRUE ) + fNoSkillSelected = FALSE; + } + if ( fNoSkillSelected ) + { + // select NONE button + gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_MINOR_NONE ] = TRUE; + } + } + else + { + //if we are to reset all the buttons + if( CountNumMinorTraitsSelected( FALSE ) >= NumAvailableMinorTraits() ) + { + // try to remove the last selected minor trait + if ( gfMinorTraitQuestions[ GetLastSelectedMinorTrait() ] > 0 ) + { + gfMinorTraitQuestions[ GetLastSelectedMinorTrait() ] = FALSE; + + // remove this one from list + HandleLastSelectedMinorTrait( -1 ); + } + // if there is none, remove all for sure + else + { + //loop through all the skill and reset them + for( uiCnt=0; uiCntuiFlags |= BUTTON_CLICKED_ON; + } + else + { + ButtonList[ giIMPMinorTraitAnswerButton[ uiCnt ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + } + } +} + +void IMPMinorTraitDisplaySkills() +{ + UINT32 uiCnt; + UINT16 usPosX, usPosY; + UINT16 usBoxPosX, usBoxPosY; + HVOBJECT hImageHandle; + + //Display the title + DrawTextToScreen( gzIMPSkillTraitsTextNewMinor[ IMP_SKILL_TRAITS_NEW_NUMBER_MINOR_SKILLS ], IMP_MINOR_TRAIT__TITLE_X, IMP_MINOR_TRAIT__TITLE_Y, IMP_MINOR_TRAIT__TITLE_WIDTH, IMP_MINOR_TRAIT__TITLE_FONT, IMP_MINOR_TRAIT__COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + // Stats + GetVideoObject(&hImageHandle, guiIMT_GreyGoldBox ); + + usPosX = IMP_MINOR_TRAIT__LEFT_COLUMN_START_X + IMP_MINOR_TRAIT__TEXT_OFFSET_X; + usPosY = IMP_MINOR_TRAIT__LEFT_COLUMN_START_Y + IMP_MINOR_TRAIT__TEXT_OFFSET_Y; + + for( uiCnt=0; uiCntuiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags|=(BUTTON_CLICKED_ON); + + //if we are just reviewing the page + if( iCurrentProfileMode == IMP__FINISH ) + { + //go back tot he done screen + iCurrentImpPage = IMP_FINISH; + } + else + { + iCurrentImpPage = IMP_MAIN_PAGE; + + if( CameBackToMinorTraitPageButNotFinished() ) + { + } + else + { + //We are finished on this page + iCurrentProfileMode = IMP__ATTRIBUTES; + } + } + } +} + +BOOLEAN CameBackToMinorTraitPageButNotFinished() +{ + //if we are in a page that comes after this one + if( iCurrentProfileMode == IMP__ATTRIBUTES ) + { + return( TRUE ); + } + else + { + return( FALSE ); + } +} + +INT8 CountNumMinorTraitsSelected( BOOLEAN fIncludeNoneSkill ) +{ + UINT32 uiCnt; + INT8 iNumberSkills=0; + + for( uiCnt=0; uiCnt < IMP_SKILL_TRAITS_NEW_NUMBER_MINOR_SKILLS; uiCnt++ ) + { + if( !fIncludeNoneSkill && uiCnt == IMP_SKILL_TRAITS_NEW_MINOR_NONE ) + continue; + //if the skill is selected ( ie depressed ) + else if( gfMinorTraitQuestions[ uiCnt ] ) + { + iNumberSkills++; + } + } + + return( iNumberSkills ); +} + +INT8 NumAvailableMinorTraits() +{ + INT8 bNumMinorTraits=0; + INT8 bNumMajorTraits=0; + + //Count the number of skills selected + bNumMajorTraits = CountNumSkillTraitsSelected( FALSE ); + + bNumMinorTraits = gSkillTraitValues.ubMaxNumberOfTraits - bNumMajorTraits; + + bNumMinorTraits = max( 1, bNumMinorTraits ); + + //if ( bNumMajorTraits == 0 ) + // bNumMinorTraits = 3; + //else if ( bNumMajorTraits == 1 ) + // bNumMinorTraits = 2; + //else if ( bNumMajorTraits == 2 ) + // bNumMinorTraits = 1; + //else + //{ + // Assert( 0 ); + // bNumMinorTraits = 0; + //} + + return(bNumMinorTraits); +} + + +void AddSelectedMinorTraitsToSkillsList() +{ + UINT32 uiCnt; + + // if we have somehow reached beyond available traits, try to fix it by removing the last one selected + if ( NumAvailableMinorTraits() < CountNumMinorTraitsSelected( FALSE ) ) + { + if (gfMinorTraitQuestions[ GetLastSelectedMinorTrait() ] == TRUE ) + gfMinorTraitQuestions[ GetLastSelectedMinorTrait() ] = FALSE; + } + // if still something is wrong, remove them all + if ( NumAvailableMinorTraits() < CountNumMinorTraitsSelected( FALSE ) ) + { + for( uiCnt=0; uiCnt=0; iCnt-- ) + { + if ( gbLastSelectedMinorTrait[ iCnt ] > 0 ) + { + gbLastSelectedMinorTrait[ iCnt ] = 0; + break; + } + } + + } + else + { + for( iCnt=0; iCnt<9; iCnt++ ) + { + gbLastSelectedMinorTrait[ (iCnt + 1) ] = gbLastSelectedMinorTrait[ iCnt ]; + } + gbLastSelectedMinorTrait[ 0 ] = bNewTrait; + } + + // here in "gbLastSelectedMinorTrait[ 0 ]" must always be the oldest minor trait selected + // this is indeed pretty sh*tty code + /*if( bNewTrait == IMP_SKILL_TRAITS_NEW_MINOR_NONE ) + { + gbLastSelectedMinorTrait[ 0 ] = -1; + gbLastSelectedMinorTrait[ 1 ] = -1; + gbLastSelectedMinorTrait[ 2 ] = -1; + return; + } + + if( gfMinorTraitQuestions[ gbLastSelectedMinorTrait[ 0 ] ] == FALSE ) + gbLastSelectedMinorTrait[ 0 ] = -1; + if( gfMinorTraitQuestions[ gbLastSelectedMinorTrait[ 1 ] ] == FALSE ) + gbLastSelectedMinorTrait[ 1 ] = -1; + if( gfMinorTraitQuestions[ gbLastSelectedMinorTrait[ 2 ] ] == FALSE ) + gbLastSelectedMinorTrait[ 2 ] = -1; + + if( gbLastSelectedMinorTrait[ 0 ] == -1 ) + { + if( gbLastSelectedMinorTrait[ 1 ] != -1 ) + gbLastSelectedMinorTrait[ 0 ] = gbLastSelectedMinorTrait[ 1 ]; + else if( gbLastSelectedMinorTrait[ 2 ] != -1 ) + gbLastSelectedMinorTrait[ 0 ] = gbLastSelectedMinorTrait[ 2 ]; + } + else if( gbLastSelectedMinorTrait[ 1 ] == -1 && gbLastSelectedMinorTrait[ 2 ] != -1 ) + { + gbLastSelectedMinorTrait[ 1 ] = gbLastSelectedMinorTrait[ 2 ]; + } + + if( NumAvailableMinorTraits() == 1 ) + { + gbLastSelectedMinorTrait[ 0 ] = bNewTrait; + } + else if( NumAvailableMinorTraits() == 2 ) + { + if( gbLastSelectedMinorTrait[ 0 ] == -1 ) + { + gbLastSelectedMinorTrait[ 0 ] = bNewTrait; + } + else if( gbLastSelectedMinorTrait[ 1 ] == -1 ) + { + gbLastSelectedMinorTrait[ 1 ] = bNewTrait; + } + else + { + gbLastSelectedMinorTrait[ 0 ] = gbLastSelectedMinorTrait[ 1 ]; + gbLastSelectedMinorTrait[ 1 ] = bNewTrait; + } + } + else if( NumAvailableMinorTraits() == 3 ) + { + if( gbLastSelectedMinorTrait[ 0 ] == -1 ) + { + gbLastSelectedMinorTrait[ 0 ] = bNewTrait; + } + else if( gbLastSelectedMinorTrait[ 1 ] == -1 ) + { + gbLastSelectedMinorTrait[ 1 ] = bNewTrait; + } + else if( gbLastSelectedMinorTrait[ 2 ] == -1 ) + { + gbLastSelectedMinorTrait[ 2 ] = bNewTrait; + } + else + { + gbLastSelectedMinorTrait[ 0 ] = gbLastSelectedMinorTrait[ 1 ]; + gbLastSelectedMinorTrait[ 1 ] = gbLastSelectedMinorTrait[ 2 ]; + gbLastSelectedMinorTrait[ 2 ] = bNewTrait; + } + } + else + { + Assert( 0 ); + gbLastSelectedMinorTrait[ 0 ] = bNewTrait; + }*/ +} + +INT8 GetLastSelectedMinorTrait( void ) +{ + INT16 iCnt; + + for( iCnt=9; iCnt>=0; iCnt-- ) + { + if ( gbLastSelectedMinorTrait[ iCnt ] > 0 ) + { + return ( gbLastSelectedMinorTrait[ iCnt ] ); + break; + } + } + return ( 0 ); +} + +UINT8 StrengthRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_MELEE ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + return( 0 ); +} +UINT8 DexterityRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_AMBIDEXTROUS ] && gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_THROWING ] ) + { + // 70 is minimum if having both, +20 is addition to other preset requirements + if( (iInitialValue + 20) < 70 ) + { + // if less than minimum, add how much we need + return ( 70 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 20 ); + } + } + else if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_AMBIDEXTROUS ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + else if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_THROWING ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + + return( 0 ); +} +UINT8 AgilityRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_ATHLETICS ] && gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_STEALTHY ] ) + { + // 70 is minimum if having both, +20 is addition to other preset requirements + if( (iInitialValue + 20) < 70 ) + { + // if less than minimum, add how much we need + return ( 70 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 20 ); + } + } + else if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_ATHLETICS ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + else if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_STEALTHY ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + + return( 0 ); +} +UINT8 HealthRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_BODYBUILDING ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + + return( 0 ); +} +UINT8 WisdomRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_NIGHT_OPS ] && gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_SCOUTING ] ) + { + // 70 is minimum if having both, +20 is addition to other preset requirements + if( (iInitialValue + 20) < 70 ) + { + // if less than minimum, add how much we need + return ( 70 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 20 ); + } + } + else if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_NIGHT_OPS ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + else if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_SCOUTING ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 60 ) + { + // if less than minimum, add how much we need + return ( 60 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + + return( 0 ); +} +UINT8 LeaderShipRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_TEACHING ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 45 ) + { + // if less than minimum, add how much we need + return ( 45 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + + return( 0 ); +} +UINT8 MarksmanshipRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + // nothing here + return( 0 ); +} +UINT8 MechanicalRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + // nothing here + return( 0 ); +} +UINT8 MedicalRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + // nothing here + return( 0 ); +} +UINT8 ExplosivesRequiredAdjustmentForMinorTraits( INT32 iInitialValue ) +{ + if ( gfMinorTraitQuestions[ IMP_SKILL_TRAITS_NEW_DEMOLITIONS ] ) + { + // 60 is minimum, +10 is addition to other preset requirements + if( (iInitialValue + 10) < 45 ) + { + // if less than minimum, add how much we need + return ( 45 - iInitialValue ); + } + else + { + // otherwise just add 10 on top + return ( 10 ); + } + } + + return( 0 ); +} + +void AssignMinorTraitHelpText( UINT8 ubNumber ) +{ + CHAR16 apStr[ 5000 ]; + CHAR16 atStr[ 1500 ]; + + switch( ubNumber ) + { + case IMP_SKILL_TRAITS_NEW_AMBIDEXTROUS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubAMPenaltyDoubleReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[0], gSkillTraitValues.ubAMPenaltyDoubleReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMReloadSpeedMagazines != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[1], gSkillTraitValues.ubAMReloadSpeedMagazines, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMReloadSpeedLoose != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[2], gSkillTraitValues.ubAMReloadSpeedLoose, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMPickItemsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[3], gSkillTraitValues.ubAMPickItemsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMWorkBackpackAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[4], gSkillTraitValues.ubAMWorkBackpackAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMHandleDoorsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[5], gSkillTraitValues.ubAMHandleDoorsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMHandleBombsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[6], gSkillTraitValues.ubAMHandleBombsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMAttachingItemsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[7], gSkillTraitValues.ubAMAttachingItemsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_MELEE: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubMEBladesAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[0], gSkillTraitValues.ubMEBladesAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtHBladesBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[1], gSkillTraitValues.ubMECtHBladesBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtHBluntBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[2], gSkillTraitValues.ubMECtHBluntBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDamageBonusBlades != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[3], gSkillTraitValues.ubMEDamageBonusBlades, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDamageBonusBlunt != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[4], gSkillTraitValues.ubMEDamageBonusBlunt, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usMEAimedMeleeAttackDamageBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[5], gSkillTraitValues.usMEAimedMeleeAttackDamageBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDodgeBladesBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[6], gSkillTraitValues.ubMEDodgeBladesBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtDBladesOnTopWithBladeInHands != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[7], gSkillTraitValues.ubMECtDBladesOnTopWithBladeInHands, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDodgeBluntBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[8], gSkillTraitValues.ubMEDodgeBluntBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtDBluntOnTopWithBladeInHands != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[9], gSkillTraitValues.ubMECtDBluntOnTopWithBladeInHands, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_THROWING: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubTHBladesAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[0], gSkillTraitValues.ubTHBladesAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesMaxRange != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[1], gSkillTraitValues.ubTHBladesMaxRange, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesCtHBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[2], gSkillTraitValues.ubTHBladesCtHBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesCtHBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[3], gSkillTraitValues.ubTHBladesCtHBonusPerClick, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesDamageBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[4], gSkillTraitValues.ubTHBladesDamageBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesDamageBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[5], gSkillTraitValues.ubTHBladesDamageBonusPerClick, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesSilentCriticalHitChance != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[6], gSkillTraitValues.ubTHBladesSilentCriticalHitChance, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesCriticalHitMultiplierBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[7], gSkillTraitValues.ubTHBladesCriticalHitMultiplierBonus); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesAimClicksAdded != 0 ) + { + if( gSkillTraitValues.ubTHBladesAimClicksAdded == 1 ) + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[8], gSkillTraitValues.ubTHBladesAimClicksAdded ); + else + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[9], gSkillTraitValues.ubTHBladesAimClicksAdded ); + + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_NIGHT_OPS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubNOeSightRangeBonusInDark != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[0], gSkillTraitValues.ubNOeSightRangeBonusInDark, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNOHearingRangeBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[1], gSkillTraitValues.ubNOHearingRangeBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNOHearingRangeBonusInDark != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[2], gSkillTraitValues.ubNOHearingRangeBonusInDark, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNOIterruptsBonusInDark != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[3], gSkillTraitValues.ubNOIterruptsBonusInDark, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNONeedForSleepReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[4], gSkillTraitValues.ubNONeedForSleepReduction); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_STEALTHY: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSTStealthModeSpeedBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[0], gSkillTraitValues.ubSTStealthModeSpeedBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSTBonusToMoveQuietly != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[1], gSkillTraitValues.ubSTBonusToMoveQuietly, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSTStealthBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[2], gSkillTraitValues.ubSTStealthBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSTStealthPenaltyForMovingReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[3], gSkillTraitValues.ubSTStealthPenaltyForMovingReduction, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_ATHLETICS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubATAPsMovementReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAthletics[0], gSkillTraitValues.ubATAPsMovementReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubATBPsMovementReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAthletics[1], gSkillTraitValues.ubATBPsMovementReduction, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_BODYBUILDING: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubBBDamageResistance != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[0], gSkillTraitValues.ubBBDamageResistance, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubBBCarryWeightBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[1], gSkillTraitValues.ubBBCarryWeightBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubBBBreathLossForHtHImpactReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[2], gSkillTraitValues.ubBBBreathLossForHtHImpactReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usBBIncreasedNeededDamageToFallDown != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[3], gSkillTraitValues.usBBIncreasedNeededDamageToFallDown, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_DEMOLITIONS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[0], gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEMaxRangeToThrowGrenades != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[1], gSkillTraitValues.ubDEMaxRangeToThrowGrenades, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDECtHWhenThrowingGrenades != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[2], gSkillTraitValues.ubDECtHWhenThrowingGrenades, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEDamageOfBombsAndMines != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[3], gSkillTraitValues.ubDEDamageOfBombsAndMines, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEAttachDetonatorCheckBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[4], gSkillTraitValues.ubDEAttachDetonatorCheckBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[5], gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEPlacedBombLevelBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[6], gSkillTraitValues.ubDEPlacedBombLevelBonus); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEShapedChargeDamageMultiplier != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[7], gSkillTraitValues.ubDEShapedChargeDamageMultiplier); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_TEACHING: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubTGBonusToTrainMilitia != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[0], gSkillTraitValues.ubTGBonusToTrainMilitia, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[1], gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGBonusToTeachOtherMercs != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[2], gSkillTraitValues.ubTGBonusToTeachOtherMercs, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGEffectiveSkillValueForTeaching != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[3], gSkillTraitValues.ubTGEffectiveSkillValueForTeaching); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGBonusOnPractising != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[4], gSkillTraitValues.ubTGBonusOnPractising, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_SCOUTING: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSCSightRangebonusWithScopes != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[0], gSkillTraitValues.ubSCSightRangebonusWithScopes, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usSCSightRangebonusWithBinoculars != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[1], gSkillTraitValues.usSCSightRangebonusWithBinoculars, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSCTunnelVisionReducedWithBinoculars != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[2], gSkillTraitValues.ubSCTunnelVisionReducedWithBinoculars, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.fSCCanDetectEnemyPresenseAround ) + { + if( gSkillTraitValues.fSCCanDetermineEnemyNumbersAround ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[3]); + wcscat( apStr, atStr ); + } + else + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[4]); + wcscat( apStr, atStr ); + } + } + if( gSkillTraitValues.fSCPreventsTheEnemyToAmbushMercs ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[5]); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.fSCPreventsBloodcatsAmbushes ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[6]); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_MINOR_NONE: + { + swprintf( apStr, gzIMPMinorTraitsHelpTextsNone[0] ); + break; + } + } + + // Set region help text + SetRegionFastHelpText( &(gMR_MinorTraitHelpTextRegions[ubNumber]), apStr ); + SetRegionHelpEndCallback( &gMR_MinorTraitHelpTextRegions[ubNumber], MSYS_NO_CALLBACK ); + + return; +} \ No newline at end of file diff --git a/Laptop/IMP Minor Trait.h b/Laptop/IMP Minor Trait.h new file mode 100644 index 00000000..f99267fc --- /dev/null +++ b/Laptop/IMP Minor Trait.h @@ -0,0 +1,44 @@ +#ifndef __IMP_MINOR_TRAIT__H_ +#define __IMP_MINOR_TRAIT__H_ + +#include "Types.h" + +void EnterIMPMinorTrait( void ); +void RenderIMPMinorTrait( void ); +void ExitIMPMinorTrait( void ); +void HandleIMPMinorTrait( void ); + +enum +{ + // minor traits + IMP_SKILL_TRAITS_NEW_AMBIDEXTROUS, + IMP_SKILL_TRAITS_NEW_MELEE, + IMP_SKILL_TRAITS_NEW_THROWING, + IMP_SKILL_TRAITS_NEW_NIGHT_OPS, + IMP_SKILL_TRAITS_NEW_STEALTHY, + IMP_SKILL_TRAITS_NEW_ATHLETICS, + IMP_SKILL_TRAITS_NEW_BODYBUILDING, + IMP_SKILL_TRAITS_NEW_DEMOLITIONS, + IMP_SKILL_TRAITS_NEW_TEACHING, + IMP_SKILL_TRAITS_NEW_SCOUTING, + ////// + IMP_SKILL_TRAITS_NEW_MINOR_NONE, + IMP_SKILL_TRAITS_NEW_NUMBER_MINOR_SKILLS, +}; + +void AddSelectedMinorTraitsToSkillsList(); + +INT8 CountNumMinorTraitsSelected( BOOLEAN fIncludeNoneSkill ); + +UINT8 StrengthRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 DexterityRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 AgilityRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 HealthRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 WisdomRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 LeaderShipRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 MarksmanshipRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 MechanicalRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 MedicalRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); +UINT8 ExplosivesRequiredAdjustmentForMinorTraits( INT32 iInitialValue ); + +#endif diff --git a/Laptop/IMP Personality Entrance.h b/Laptop/IMP Personality Entrance.h index dc82d663..6e0a9d83 100644 --- a/Laptop/IMP Personality Entrance.h +++ b/Laptop/IMP Personality Entrance.h @@ -7,4 +7,6 @@ void RenderIMPPersonalityEntrance( void ); void ExitIMPPersonalityEntrance( void ); void HandleIMPPersonalityEntrance( void ); +STR16 pSkillTraitBeginIMPStrings[]; + #endif \ No newline at end of file diff --git a/Laptop/IMP Personality Quiz.cpp b/Laptop/IMP Personality Quiz.cpp index 8d381ffe..3a27cb5d 100644 --- a/Laptop/IMP Personality Quiz.cpp +++ b/Laptop/IMP Personality Quiz.cpp @@ -21,6 +21,7 @@ #include "english.h" #endif + // Kaiden this line was commented before I screwed with it //extern struct POINT; @@ -207,10 +208,10 @@ void CreateIMPPersonalityQuizButtons( void ) // ths Done button giIMPPersonalityQuizButtonImage[0]= LoadButtonImage( "LAPTOP\\button_7.sti" ,-1,0,-1,1,-1 ); -/* giIMPPersonalityQuizButton[0] = QuickCreateButton( giIMPPersonalityQuizButtonImage[0], LAPTOP_SCREEN_UL_X + ( 197 ), LAPTOP_SCREEN_WEB_UL_Y + ( 310 ), - BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, - BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnIMPPersonalityQuizAnswerConfirmCallback); -*/ +// giIMPPersonalityQuizButton[0] = QuickCreateButton( giIMPPersonalityQuizButtonImage[0], LAPTOP_SCREEN_UL_X + ( 197 ), LAPTOP_SCREEN_WEB_UL_Y + ( 310 ), +// BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, +// BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnIMPPersonalityQuizAnswerConfirmCallback); +// giIMPPersonalityQuizButton[0] = CreateIconAndTextButton( giIMPPersonalityQuizButtonImage[0], pImpButtonText[ 8 ], FONT12ARIAL, FONT_WHITE, DEFAULT_SHADOW, FONT_WHITE, DEFAULT_SHADOW, @@ -221,10 +222,10 @@ void CreateIMPPersonalityQuizButtons( void ) // start over giIMPPersonalityQuizButtonImage[ 1 ]= LoadButtonImage( "LAPTOP\\button_5.sti" ,-1,0,-1,1,-1 ); - /* giIMPPersonalityQuizButton[ 1 ] = QuickCreateButton( giIMPPersonalityQuizButtonImage[1], LAPTOP_SCREEN_UL_X + ( BTN_FIRST_COLUMN_X ), LAPTOP_SCREEN_WEB_UL_Y + ( 310 ), - BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, - BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnIMPPersonalityQuizStartOverCallback); -*/ + // giIMPPersonalityQuizButton[ 1 ] = QuickCreateButton( giIMPPersonalityQuizButtonImage[1], LAPTOP_SCREEN_UL_X + ( BTN_FIRST_COLUMN_X ), LAPTOP_SCREEN_WEB_UL_Y + ( 310 ), +// BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, +// BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnIMPPersonalityQuizStartOverCallback); +// giIMPPersonalityQuizButton[ 1 ] = CreateIconAndTextButton( giIMPPersonalityQuizButtonImage[ 1 ], pImpButtonText[ 7 ], FONT12ARIAL, FONT_WHITE, DEFAULT_SHADOW, @@ -1024,12 +1025,12 @@ void CompileQuestionsInStatsAndWhatNot( void ) if( fCharacterIsMale ) { // Martial arts - AddSkillToSkillList( MARTIALARTS ); + AddSkillToSkillList( MARTIALARTS_OT ); } else { // for women, ambidexterious - AddSkillToSkillList( AMBIDEXT ); + AddSkillToSkillList( AMBIDEXT_OT ); } break; case( 1 ): @@ -1037,15 +1038,15 @@ void CompileQuestionsInStatsAndWhatNot( void ) break; case( 2 ): // hand to hand - AddSkillToSkillList( HANDTOHAND ); + AddSkillToSkillList( HANDTOHAND_OT ); break; case( 3 ): // lock picking - AddSkillToSkillList( LOCKPICKING ); + AddSkillToSkillList( LOCKPICKING_OT ); break; case( 4 ): // throwing - AddSkillToSkillList( THROWING ); + AddSkillToSkillList( THROWING_OT ); break; case( 5 ): // optimist @@ -1058,10 +1059,10 @@ void CompileQuestionsInStatsAndWhatNot( void ) { case( 0 ): // teaching - AddSkillToSkillList( TEACHING ); + AddSkillToSkillList( TEACHING_OT ); break; case( 1 ): - AddSkillToSkillList( STEALTHY ); + AddSkillToSkillList( STEALTHY_OT ); break; case( 2 ): // psycho @@ -1077,14 +1078,14 @@ void CompileQuestionsInStatsAndWhatNot( void ) { case( 0 ): // lock picking - AddSkillToSkillList( LOCKPICKING ); + AddSkillToSkillList( LOCKPICKING_OT ); break; case( 1 ): // arrogant AddAnAttitudeToAttitudeList( ATT_ARROGANT ); break; case( 2 ): - AddSkillToSkillList( STEALTHY ); + AddSkillToSkillList( STEALTHY_OT ); break; case( 3 ): // normal @@ -1098,7 +1099,7 @@ void CompileQuestionsInStatsAndWhatNot( void ) { case( 0 ): // automatic weapons - AddSkillToSkillList( AUTO_WEAPS ); + AddSkillToSkillList( AUTO_WEAPS_OT ); break; case( 1 ): // friendly @@ -1146,7 +1147,7 @@ void CompileQuestionsInStatsAndWhatNot( void ) AddAnAttitudeToAttitudeList( ATT_COWARD ); break; case( 1 ): - AddSkillToSkillList( NIGHTOPS ); + AddSkillToSkillList( NIGHTOPS_OT ); break; case( 2 ): // dont like boxes much @@ -1165,14 +1166,14 @@ void CompileQuestionsInStatsAndWhatNot( void ) { case( 0 ): // electronics - AddSkillToSkillList( ELECTRONICS ); + AddSkillToSkillList( ELECTRONICS_OT ); break; case( 1 ): //knifing - AddSkillToSkillList( KNIFING ); + AddSkillToSkillList( KNIFING_OT ); break; case( 2 ): - AddSkillToSkillList( NIGHTOPS ); + AddSkillToSkillList( NIGHTOPS_OT ); break; case( 3 ): // none @@ -1184,7 +1185,7 @@ void CompileQuestionsInStatsAndWhatNot( void ) { case( 0 ): // ambidexterous - AddSkillToSkillList( AMBIDEXT ); + AddSkillToSkillList( AMBIDEXT_OT ); break; case( 1 ): // none @@ -1247,7 +1248,7 @@ void CompileQuestionsInStatsAndWhatNot( void ) break; case( 1 ): // teaching - AddSkillToSkillList( TEACHING ); + AddSkillToSkillList( TEACHING_OT ); break; case( 2 ): // aggressive @@ -1269,32 +1270,32 @@ void CompileQuestionsInStatsAndWhatNot( void ) if( fCharacterIsMale ) { // Martial arts - AddSkillToSkillList( MARTIALARTS ); + AddSkillToSkillList( MARTIALARTS_OT ); } else { // for women, ambidexterious - AddSkillToSkillList( AMBIDEXT ); + AddSkillToSkillList( AMBIDEXT_OT ); } break; case( 1 ): //knifing - AddSkillToSkillList( KNIFING ); + AddSkillToSkillList( KNIFING_OT ); break; case( 2 ): // none break; case( 3 ): // automatic weapons - AddSkillToSkillList( AUTO_WEAPS ); + AddSkillToSkillList( AUTO_WEAPS_OT ); break; case( 4 ): // hand to hand - AddSkillToSkillList( HANDTOHAND ); + AddSkillToSkillList( HANDTOHAND_OT ); break; case( 5 ): // electronics - AddSkillToSkillList( ELECTRONICS ); + AddSkillToSkillList( ELECTRONICS_OT ); break; case( 6 ): // ashole @@ -1350,11 +1351,11 @@ void CompileQuestionsInStatsAndWhatNot( void ) { case( 0 ): // throwing - AddSkillToSkillList( THROWING ); + AddSkillToSkillList( THROWING_OT ); break; case( 1 ): // ambidexterous - AddSkillToSkillList( AMBIDEXT ); + AddSkillToSkillList( AMBIDEXT_OT ); break; case( 3 ): // none @@ -1622,71 +1623,71 @@ void HandleIMPQuizKeyBoard( void ) // HOOK INTO MOUSE HOOKS - /* - if( (InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam >= '1' ) && ( InputEvent.usParam <= '9') ) - { - if( ( UINT16 )( iNumberOfPersonaButtons ) >= InputEvent.usParam - '0' ) - { + // + //if( (InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam >= '1' ) && ( InputEvent.usParam <= '9') ) + //{ + // if( ( UINT16 )( iNumberOfPersonaButtons ) >= InputEvent.usParam - '0' ) + // { // reset buttons - ResetQuizAnswerButtons( ); + // ResetQuizAnswerButtons( ); // ok, check to see if button was disabled, if so, re enable - CheckStateOfTheConfirmButton( ); + // CheckStateOfTheConfirmButton( ); // toggle this button on - ButtonList[ giIMPPersonalityQuizAnswerButton[ InputEvent.usParam - '1' ] ]->uiFlags |= (BUTTON_CLICKED_ON); + // ButtonList[ giIMPPersonalityQuizAnswerButton[ InputEvent.usParam - '1' ] ]->uiFlags |= (BUTTON_CLICKED_ON); - iCurrentAnswer = InputEvent.usParam - '1'; + // iCurrentAnswer = InputEvent.usParam - '1'; - PrintImpText( ); + // PrintImpText( ); // the current and last question numbers - PrintQuizQuestionNumber( ); + // PrintQuizQuestionNumber( ); - fReDrawCharProfile = TRUE; - fSkipFrame = TRUE; - } - } - else if( ( iCurrentAnswer != -1 ) && ( InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam == ENTER ) ) - { + // fReDrawCharProfile = TRUE; + // fSkipFrame = TRUE; + // } +// } +// else if( ( iCurrentAnswer != -1 ) && ( InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam == ENTER ) ) +// { // reset all the buttons - ResetQuizAnswerButtons( ); +// ResetQuizAnswerButtons( ); // copy the answer into the list - iQuizAnswerList[ giCurrentPersonalityQuizQuestion ] = iCurrentAnswer; +// iQuizAnswerList[ giCurrentPersonalityQuizQuestion ] = iCurrentAnswer; // reset answer for next question - iCurrentAnswer = -1; +// iCurrentAnswer = -1; // next question, JOHNNY! - giCurrentPersonalityQuizQuestion++; - giMaxPersonalityQuizQuestion++; +// giCurrentPersonalityQuizQuestion++; +// giMaxPersonalityQuizQuestion++; // OPPS!, done..time to finish up - if( giCurrentPersonalityQuizQuestion > 15) - { - iCurrentImpPage = IMP_PERSONALITY_FINISH; +// if( giCurrentPersonalityQuizQuestion > 15) +// { +// iCurrentImpPage = IMP_PERSONALITY_FINISH; // process - CompileQuestionsInStatsAndWhatNot( ); - } +// CompileQuestionsInStatsAndWhatNot( ); +// } - fSkipFrame = TRUE; - } - else if( ( InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam == '=' ) ) - { - MoveAheadAQuestion( ); - fSkipFrame = TRUE; - } - else if( ( InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam == '-' ) ) - { - MoveBackAQuestion( ); - fSkipFrame = TRUE; - } - else - { +// fSkipFrame = TRUE; +// } +// else if( ( InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam == '=' ) ) +// { +// MoveAheadAQuestion( ); +// fSkipFrame = TRUE; +// } +// else if( ( InputEvent.usEvent == KEY_DOWN ) && ( InputEvent.usParam == '-' ) ) +// { +// MoveBackAQuestion( ); +// fSkipFrame = TRUE; +// } +// else +// { -*/ switch(InputEvent.usEvent) + switch(InputEvent.usEvent) { case LEFT_BUTTON_DOWN: MouseSystemHook(LEFT_BUTTON_DOWN, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown); @@ -1761,19 +1762,19 @@ void MoveAheadAQuestion( void ) CheckAndUpdateNextPreviousIMPQuestionButtonStates( ); -/* - EnableButton( giPreviousQuestionButton ); - if( giCurrentPersonalityQuizQuestion >= giMaxPersonalityQuizQuestion ) - { - DisableButton( giNextQuestionButton ); - iCurrentAnswer = -1; - } - else - { - EnableButton( giNextQuestionButton ); - } -*/ +// EnableButton( giPreviousQuestionButton ); + +// if( giCurrentPersonalityQuizQuestion >= giMaxPersonalityQuizQuestion ) +// { +// DisableButton( giNextQuestionButton ); +// iCurrentAnswer = -1; +// } +// else +// { +// EnableButton( giNextQuestionButton ); +// } + return; } @@ -1792,16 +1793,16 @@ void MoveBackAQuestion( void ) EnableButton( giNextQuestionButton ); CheckAndUpdateNextPreviousIMPQuestionButtonStates( ); -/* - if( giCurrentPersonalityQuizQuestion == 0 ) - { - DisableButton( giPreviousQuestionButton ); - } - else - { - EnableButton( giPreviousQuestionButton ); - } -*/ + +// if( giCurrentPersonalityQuizQuestion == 0 ) +// { +// DisableButton( giPreviousQuestionButton ); +// } +// else +// { +// EnableButton( giPreviousQuestionButton ); +// } + return; } diff --git a/Laptop/IMP Portraits.cpp b/Laptop/IMP Portraits.cpp index 3887af43..48a45fac 100644 --- a/Laptop/IMP Portraits.cpp +++ b/Laptop/IMP Portraits.cpp @@ -21,10 +21,15 @@ #include "IMP Compile Character.h" #endif +#include "IMP Confirm.h" + //current and last pages INT32 iCurrentPortrait = 0; INT32 iLastPicture = 7; +INT32 iLastPictureF; +INT32 iLastPictureM; + // buttons needed for the IMP portrait screen INT32 giIMPPortraitButton[ 3 ]; INT32 giIMPPortraitButtonImage[ 3 ]; @@ -52,6 +57,7 @@ void BtnIMPPortraitDoneCallback(GUI_BUTTON *btn,INT32 reason); void EnterIMPPortraits( void ) { + iCurrentPortrait = 0; // create buttons CreateIMPPortraitButtons( ); @@ -121,7 +127,15 @@ BOOLEAN RenderPortrait( INT16 sX, INT16 sY ) // load it VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; - FilenameForBPP( pPlayerSelectedBigFaceFileNames[ iCurrentPortrait ] , VObjectDesc.ImageFile); + + + if ( gIMPMaleValues[ iCurrentPortrait ].Enabled == 1 ) + { + sprintf( VObjectDesc.ImageFile, "Faces\\BigFaces\\%02d.sti", gIMPMaleValues[ iCurrentPortrait ].PortraitId ); + } + + + //FilenameForBPP( pPlayerSelectedBigFaceFileNames[ iCurrentPortrait ] , VObjectDesc.ImageFile); CHECKF(AddVideoObject(&VObjectDesc, &uiGraphicHandle)); // show it @@ -138,7 +152,15 @@ BOOLEAN RenderPortrait( INT16 sX, INT16 sY ) { // load it VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; - FilenameForBPP( pPlayerSelectedBigFaceFileNames[ iCurrentPortrait + 8 ] , VObjectDesc.ImageFile); + + //FilenameForBPP( pPlayerSelectedBigFaceFileNames[ iCurrentPortrait + 8 ] , VObjectDesc.ImageFile); + + if ( gIMPFemaleValues[ iCurrentPortrait ].Enabled == 1 ) + { + sprintf( VObjectDesc.ImageFile, "Faces\\BigFaces\\%02d.sti", gIMPFemaleValues[ iCurrentPortrait ].PortraitId ); + } + + CHECKF(AddVideoObject(&VObjectDesc, &uiGraphicHandle)); // show it @@ -154,12 +176,35 @@ BOOLEAN RenderPortrait( INT16 sX, INT16 sY ) return ( TRUE ); } - - void IncrementPictureIndex( void ) { - // cycle to next picture +iCurrentPortrait++; +if( fCharacterIsMale ) +{ + if( gIMPMaleValues[iCurrentPortrait].uiIndex == iCurrentPortrait && gIMPMaleValues[iCurrentPortrait].PortraitId !=0 ) + { + iCurrentPortrait = gIMPMaleValues[iCurrentPortrait].uiIndex; + } + else + { + iCurrentPortrait = 0; + } +} +else +{ + if( gIMPFemaleValues[iCurrentPortrait].uiIndex == iCurrentPortrait && gIMPFemaleValues[iCurrentPortrait].PortraitId !=0 ) + { + iCurrentPortrait = gIMPFemaleValues[iCurrentPortrait].uiIndex; + } + else + { + iCurrentPortrait = 0; + } + +} + // cycle to next picture +/* iCurrentPortrait++; // gone too far? @@ -168,23 +213,64 @@ void IncrementPictureIndex( void ) iCurrentPortrait = 0; } - +*/ return; } - void DecrementPicture( void ) { - // cycle to previous picture +UINT32 cnt; +UINT32 idPort = 0; - iCurrentPortrait--; +if( fCharacterIsMale ) +{ + for ( cnt = 0; cnt < MAX_NEW_IMP_PORTRAITS; cnt++ ) + { + if ( gIMPMaleValues[cnt].uiIndex == cnt && gIMPMaleValues[cnt].PortraitId !=0 ) + { + iLastPictureM = gIMPMaleValues[cnt].uiIndex; + } + } + + iLastPicture = iLastPictureM; +} +else +{ + for ( cnt = 0; cnt < MAX_NEW_IMP_PORTRAITS; cnt++ ) + { + if ( gIMPFemaleValues[cnt].uiIndex == cnt && gIMPFemaleValues[cnt].PortraitId !=0 ) + { + iLastPictureF = gIMPFemaleValues[cnt].uiIndex; + } + } + + iLastPicture = iLastPictureF; +} + +iCurrentPortrait--; +if( fCharacterIsMale ) +{ + if( iCurrentPortrait < 0 ) + { + iCurrentPortrait = iLastPicture; + } +} +else +{ + if( iCurrentPortrait < 0 ) + { + iCurrentPortrait = iLastPicture; + } + +} +/* // gone too far? if( iCurrentPortrait < 0 ) { - iCurrentPortrait = iLastPicture; + iCurrentPortrait = iLastPicture; } - +*/ return; } @@ -364,18 +450,20 @@ void BtnIMPPortraitDoneCallback(GUI_BUTTON *btn,INT32 reason) }*/ // grab picture number + + + if( fCharacterIsMale ) { - // male - iPortraitNumber = iCurrentPortrait; + // male + iPortraitNumber = gIMPMaleValues[ iCurrentPortrait ].uiIndex; //iCurrentPortrait } else { - // female - iPortraitNumber = iCurrentPortrait + ( 8 ); - + // female + iPortraitNumber = gIMPFemaleValues[ iCurrentPortrait ].uiIndex; //iCurrentPortrait ;//+ ( 8 ); } - + fButtonPendingFlag = TRUE; } } diff --git a/Laptop/IMP Skill Trait.cpp b/Laptop/IMP Skill Trait.cpp index 3beae54f..7bd7b652 100644 --- a/Laptop/IMP Skill Trait.cpp +++ b/Laptop/IMP Skill Trait.cpp @@ -21,6 +21,8 @@ #include "IMP Compile Character.h" #include "GameSettings.h" // added by SANDRO #include "IMP Color Choosing.h" // added by SANDRO + #include "IMP Minor Trait.h" + #include "Soldier Profile.h" #endif @@ -37,14 +39,6 @@ #define IMP_SKILL_TRAIT__COLOR FONT_MCOLOR_WHITE - -enum -{ - IMP_SKILL_TRAIT__TITLE_TEXT=IMP_SKILL_TRAITS__NUMBER_SKILLS, -}; - - - #define IMP_SKILL_TRAIT__LEFT_COLUMN_START_X ( LAPTOP_SCREEN_UL_X + 15 ) #define IMP_SKILL_TRAIT__LEFT_COLUMN_START_Y ( LAPTOP_SCREEN_WEB_UL_Y + 40 ) @@ -53,9 +47,10 @@ enum #define IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS 38 -#define IMP_SKILL_TRAIT__SKILL_TRAIT_TO_START_RIGHT_COL 6 +//#define IMP_SKILL_TRAIT__SKILL_TRAIT_TO_START_RIGHT_COL 6 #define IMP_SKILL_TRAIT__NONE_BTN_LOC_X ( LAPTOP_SCREEN_UL_X + 136 ) +#define IMP_SKILL_TRAIT__NONE_BTN_LOC_Y ( LAPTOP_SCREEN_WEB_UL_Y + 306 ) // added this one - SANDRO #define IMP_SKILL_TRAIT__TEXT_OFFSET_X 65 #define IMP_SKILL_TRAIT__TEXT_OFFSET_Y 12 @@ -73,14 +68,17 @@ enum // Global Variables // //******************************************************************* +BOOLEAN gfSkillTraitQuestions[ 20 ]; +BOOLEAN gfSkillTraitQuestions2[ 20 ]; + BOOLEAN gfIST_Redraw=FALSE; -BOOLEAN gfSkillTraitQuestions[ IMP_SKILL_TRAITS__NUMBER_SKILLS ]; - // these are the buttons for the questions -INT32 giIMPSkillTraitAnswerButton[ IMP_SKILL_TRAITS__NUMBER_SKILLS ]; -INT32 giIMPSkillTraitAnswerButtonImage[ IMP_SKILL_TRAITS__NUMBER_SKILLS ]; +INT32 giIMPSkillTraitAnswerButton[ 20 ]; +INT32 giIMPSkillTraitAnswerButton2[ 20 ]; +INT32 giIMPSkillTraitAnswerButtonImage[ 20 ]; +INT32 giIMPSkillTraitAnswerButtonImage2[ 20 ]; // this is the Done buttons INT32 giIMPSkillTraitFinsihButton; @@ -88,8 +86,7 @@ INT32 giIMPSkillTraitFinsihButtonImage; //BOOLEAN gfSkillTraitButtonChanged=FALSE; -#define IST__NUM_SELECTABLE_TRAITS 2 -INT8 gbLastSelectedTraits[ IST__NUM_SELECTABLE_TRAITS ]; +INT8 gbLastSelectedTraits[ 10 ]; //image handle UINT32 guiIST_GreyGoldBox; @@ -101,16 +98,23 @@ UINT32 guiIST_GreyGoldBox; //******************************************************************* void BtnIMPSkillTraitAnswerCallback(GUI_BUTTON *btn,INT32 reason); +void BtnIMPSkillTraitAnswerCallback2(GUI_BUTTON *btn,INT32 reason); void BtnIMPSkillTraitFinishCallback(GUI_BUTTON *btn,INT32 reason); void AddImpSkillTraitButtons(); void HandleSkillTraitButtonStates( ); -void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fResetAllButtons ); +void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fSecondTrait ); void IMPSkillTraitDisplaySkills(); -INT8 CountNumSkillStraitsSelected( BOOLEAN fIncludeNoneSkill ); BOOLEAN ShouldTraitBeSkipped( UINT32 uiTrait ); -void AddSelectedSkillsToSkillsList(); +//void AddSelectedSkillsToSkillsList(); // SANDRO - second declaration not needed void HandleLastSelectedTraits( INT8 bNewTrait ); +INT8 GetLastSelectedSkill( void ); BOOLEAN CameBackToSpecialtiesPageButNotFinished(); + +BOOLEAN DoesSkillHaveExpertLevel( UINT32 uiSkillTrait ); + +MOUSE_REGION gMR_SkillTraitHelpTextRegions[IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS]; + +void AssignSkillTraitHelpText( UINT8 ubTraitNumber, BOOLEAN fExpertLevel ); //ppp //******************************************************************* @@ -157,13 +161,66 @@ void EnterIMPSkillTrait( void ) if( iCurrentProfileMode != IMP__FINISH ) { //Have the NONE trait initially selected - gfSkillTraitQuestions[ IMP_SKILL_TRAITS__NONE ] = TRUE; + if( gGameOptions.fNewTraitSystem ) + { + gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_MAJOR_NONE ] = TRUE; + gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MAJOR_NONE ] = TRUE; + } + else + { + gfSkillTraitQuestions[ IMP_SKILL_TRAITS__NONE ] = TRUE; + gfSkillTraitQuestions2[ IMP_SKILL_TRAITS__NONE ] = TRUE; + } } HandleSkillTraitButtonStates( ); + // add regions for help texts + UINT16 usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X + 62; + UINT16 usPosY = IMP_SKILL_TRAIT__LEFT_COLUMN_START_Y + 8; + for( UINT32 uiCnt=0; uiCnt < (UINT8)( gGameOptions.fNewTraitSystem ? IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS : IMP_SKILL_TRAITS__NUMBER_SKILLS ); uiCnt++ ) + { + if( ShouldTraitBeSkipped( uiCnt ) ) + { + //if its the none button + if( uiCnt == ( gGameOptions.fNewTraitSystem ? (IMP_SKILL_TRAITS_NEW_MAJOR_NONE-1) : (IMP_SKILL_TRAITS__NONE-1) ) ) + { + usPosX = IMP_SKILL_TRAIT__NONE_BTN_LOC_X + 62; + usPosY = IMP_SKILL_TRAIT__NONE_BTN_LOC_Y + 8; + } + continue; + } + MSYS_DefineRegion( &gMR_SkillTraitHelpTextRegions[uiCnt], ( usPosX ), ( usPosY ), + (usPosX + 156), ( usPosY + 17), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gMR_SkillTraitHelpTextRegions[uiCnt] ); + + //Determine the next x location + if( uiCnt < (UINT8)(gGameOptions.fNewTraitSystem ? 4 : 6) ) + usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X + 62; + else + usPosX = IMP_SKILL_TRAIT__RIGHT_COLUMN_START_X + 62; + + //Determine the next Y location + if( uiCnt == (gGameOptions.fNewTraitSystem ? 4 : 6) ) + usPosY = IMP_SKILL_TRAIT__RIGHT_COLUMN_START_Y + 8; + else + { + if( gGameOptions.fNewTraitSystem ) + usPosY += IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS + 5; + else + usPosY += IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS; + } + //if its the none button + if( uiCnt == (gGameOptions.fNewTraitSystem ? (IMP_SKILL_TRAITS_NEW_MAJOR_NONE-1) : (IMP_SKILL_TRAITS__NONE-1) ) ) + { + usPosX = IMP_SKILL_TRAIT__NONE_BTN_LOC_X + 62; + usPosY = IMP_SKILL_TRAIT__NONE_BTN_LOC_Y + 8; + } + } + //reset last selecterd trait - memset( gbLastSelectedTraits, -1, IST__NUM_SELECTABLE_TRAITS ); + memset( gbLastSelectedTraits, -1, 10 ); } @@ -183,7 +240,7 @@ void ExitIMPSkillTrait( void ) DeleteVideoObjectFromIndex( guiIST_GreyGoldBox ); //remove the skill buttons - for(iCnt = 0; iCnt < IMP_SKILL_TRAITS__NUMBER_SKILLS; iCnt++) + for(iCnt = 0; iCnt < ( gGameOptions.fNewTraitSystem ? IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS : IMP_SKILL_TRAITS__NUMBER_SKILLS ); iCnt++) { //if there is a button allocated if( giIMPSkillTraitAnswerButton[iCnt] != -1 ) @@ -193,8 +250,28 @@ void ExitIMPSkillTrait( void ) } } + //remove the skill buttons + for(iCnt = 0; iCnt < ( gGameOptions.fNewTraitSystem ? IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS : IMP_SKILL_TRAITS__NUMBER_SKILLS ); iCnt++) + { + //if there is a button allocated + if( giIMPSkillTraitAnswerButton2[iCnt] != -1 ) + { + RemoveButton(giIMPSkillTraitAnswerButton2[ iCnt ] ); + UnloadButtonImage(giIMPSkillTraitAnswerButtonImage2[ iCnt ] ); + } + } + RemoveButton( giIMPSkillTraitFinsihButton ); UnloadButtonImage( giIMPSkillTraitFinsihButtonImage ); + + // SANDRO - remove regions + for( iCnt=0; iCnt < ( gGameOptions.fNewTraitSystem ? IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS : IMP_SKILL_TRAITS__NUMBER_SKILLS); iCnt++ ) + { + if( ShouldTraitBeSkipped( iCnt ) ) + continue; + + MSYS_RemoveRegion( &gMR_SkillTraitHelpTextRegions[iCnt] ); + } } @@ -212,13 +289,30 @@ void HandleIMPSkillTrait( void ) void AddImpSkillTraitButtons() { INT32 iCnt = 0; - UINT16 usPosX, usPosY; + INT32 iCntMax = 0; + INT8 iNumSkillsToStartRightColumn = 0; + UINT16 usPosX, usPosY, usSpaceBetweenButtons; + + if ( gGameOptions.fNewTraitSystem ) + { + iCntMax = IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS; + iNumSkillsToStartRightColumn = 4; + usSpaceBetweenButtons = IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS + 5; + } + else + { + iCntMax = IMP_SKILL_TRAITS__NUMBER_SKILLS; + iNumSkillsToStartRightColumn = 6; + usSpaceBetweenButtons = IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // FIRST COLUMN OF BUTTONS usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X; usPosY = IMP_SKILL_TRAIT__LEFT_COLUMN_START_Y; - - for(iCnt = 0; iCnt < IMP_SKILL_TRAITS__NUMBER_SKILLS; iCnt++) + for(iCnt = 0; iCnt < (iCntMax); iCnt++) { //reset giIMPSkillTraitAnswerButton[iCnt] = -1; @@ -232,18 +326,17 @@ void AddImpSkillTraitButtons() //if the merc is a FEMALE, skip this skill cause there isnt any fenmal martial artists if( ShouldTraitBeSkipped( iCnt ) ) { - usPosY += IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS; - //if its the none button - if( iCnt == IMP_SKILL_TRAITS__NONE-1 ) + if( iCnt == iCntMax-2 ) { usPosX = IMP_SKILL_TRAIT__NONE_BTN_LOC_X; + usPosY = IMP_SKILL_TRAIT__NONE_BTN_LOC_Y; } continue; } if( iCnt == 0 ) - giIMPSkillTraitAnswerButtonImage[ iCnt ] = LoadButtonImage( "LAPTOP\\button_6.sti", -1,0,-1,1,-1 ); + giIMPSkillTraitAnswerButtonImage[ iCnt ] = LoadButtonImage( "LAPTOP\\button_9a.sti", -1,0,-1,1,-1 ); else giIMPSkillTraitAnswerButtonImage[ iCnt ] = UseLoadedButtonImage( giIMPSkillTraitAnswerButtonImage[ 0 ], -1,0,-1,1,-1 ); @@ -259,21 +352,87 @@ void AddImpSkillTraitButtons() //ButtonList[ giIMPSkillTraitAnswerButton[ iCnt ] ]->ubSoundSchemeID = 0; // - This would disable the sounds totally resulted to play no sound - SANDRO //Determine the next x location - if( iCnt < IMP_SKILL_TRAIT__SKILL_TRAIT_TO_START_RIGHT_COL ) + if( iCnt < iNumSkillsToStartRightColumn ) usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X; else usPosX = IMP_SKILL_TRAIT__RIGHT_COLUMN_START_X; //Determine the next Y location - if( iCnt == IMP_SKILL_TRAIT__SKILL_TRAIT_TO_START_RIGHT_COL ) + if( iCnt == iNumSkillsToStartRightColumn ) usPosY = IMP_SKILL_TRAIT__RIGHT_COLUMN_START_Y; else - usPosY += IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS; + usPosY += usSpaceBetweenButtons; //if its the none button - if( iCnt == IMP_SKILL_TRAITS__NONE-1 ) + if( iCnt == iCntMax-2 ) { usPosX = IMP_SKILL_TRAIT__NONE_BTN_LOC_X; + usPosY = IMP_SKILL_TRAIT__NONE_BTN_LOC_Y; + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // SECOND COLUMN OF BUTTONS + + usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X + 26; + usPosY = IMP_SKILL_TRAIT__LEFT_COLUMN_START_Y; + + for(iCnt = 0; iCnt < (iCntMax); iCnt++) + { + //reset + giIMPSkillTraitAnswerButton2[iCnt] = -1; + + //if we are not DONE and are just reviewing + if( iCurrentProfileMode != IMP__FINISH ) + { + gfSkillTraitQuestions2[ iCnt ] = FALSE; + } + + //if the merc is a FEMALE, skip this skill cause there isnt any fenmal martial artists + if( ShouldTraitBeSkipped( iCnt ) ) + { + //if its the none button + if( iCnt == iCntMax-2 ) + { + usPosX = IMP_SKILL_TRAIT__NONE_BTN_LOC_X + 26; + usPosY = IMP_SKILL_TRAIT__NONE_BTN_LOC_Y; + } + continue; + } + + if( iCnt == 0 ) + giIMPSkillTraitAnswerButtonImage2[ iCnt ] = LoadButtonImage( "LAPTOP\\button_9b.sti", -1,0,-1,1,-1 ); + else + giIMPSkillTraitAnswerButtonImage2[ iCnt ] = UseLoadedButtonImage( giIMPSkillTraitAnswerButtonImage2[ 0 ], -1,0,-1,1,-1 ); + + giIMPSkillTraitAnswerButton2[iCnt] = QuickCreateButton( giIMPSkillTraitAnswerButtonImage2[ iCnt ], usPosX, usPosY, + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 3, + MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnIMPSkillTraitAnswerCallback2); + + //Set the button data + MSYS_SetBtnUserData( giIMPSkillTraitAnswerButton2[iCnt], 0, iCnt ); + SetButtonCursor( giIMPSkillTraitAnswerButton2[iCnt], CURSOR_WWW); + + //Get rid of playing the button sound, it will be handled here + //ButtonList[ giIMPSkillTraitAnswerButton[ iCnt ] ]->ubSoundSchemeID = 0; // - This would disable the sounds totally resulted to play no sound - SANDRO + + //Determine the next x location + if( iCnt < iNumSkillsToStartRightColumn ) + usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X + 26; + else + usPosX = IMP_SKILL_TRAIT__RIGHT_COLUMN_START_X + 26; + + //Determine the next Y location + if( iCnt == iNumSkillsToStartRightColumn ) + usPosY = IMP_SKILL_TRAIT__RIGHT_COLUMN_START_Y; + else + usPosY += usSpaceBetweenButtons; + + //if its the none button + if( iCnt == iCntMax-2 ) + { + usPosX = IMP_SKILL_TRAIT__NONE_BTN_LOC_X + 26; + usPosY = IMP_SKILL_TRAIT__NONE_BTN_LOC_Y; } } } @@ -295,9 +454,30 @@ void BtnIMPSkillTraitAnswerCallback(GUI_BUTTON *btn,INT32 reason) } } -void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fResetAllButtons ) +void BtnIMPSkillTraitAnswerCallback2(GUI_BUTTON *btn,INT32 reason) { - UINT32 uiCnt; + // btn callback for IMP personality quiz answer button + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { +// btn->uiFlags|=(BUTTON_CLICKED_ON); + + INT32 iSkillTrait = MSYS_GetBtnUserData( btn, 0 ); + + HandleIMPSkillTraitAnswers( iSkillTrait, TRUE ); + } +} + +void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fSecondTrait ) +{ + UINT32 uiCnt, uiCntMax; + + if ( gGameOptions.fNewTraitSystem ) + uiCntMax = IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS; + else + uiCntMax = IMP_SKILL_TRAITS__NUMBER_SKILLS; //if we are DONE and are just reviewing if( iCurrentProfileMode == IMP__FINISH ) @@ -305,78 +485,240 @@ void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fResetAllButtons return; } - //if we are to reset all the buttons - if( fResetAllButtons ) - { - //loop through all the skill and reset them - for( uiCnt=0; uiCnt IMP_SKILL_TRAITS__NUMBER_SKILLS ) + if( uiSkillPressed > uiCntMax ) { Assert( 0 ); return; } - - //if its allready set - if( gfSkillTraitQuestions[ uiSkillPressed ] ) + if( !fSecondTrait ) { - //dont need to do anything - return; - } + //if its allready set + if( gfSkillTraitQuestions[ uiSkillPressed ] ) + { + gfSkillTraitQuestions[ uiSkillPressed ] = FALSE; - HandleLastSelectedTraits( (INT8)uiSkillPressed ); + BOOLEAN fNoSkillSelected = TRUE; + for ( uiCnt=0; uiCnt<(uiCntMax-1); uiCnt++ ) + { + if ( gfSkillTraitQuestions[ uiCnt ] == TRUE ) + fNoSkillSelected = FALSE; + } + if ( fNoSkillSelected ) + { + // select NONE button + gfSkillTraitQuestions[ uiCntMax-1 ] = TRUE; + } + } + // if cannot have expert level of skill, don't continue + else if ( gfSkillTraitQuestions2[ uiSkillPressed ] && !DoesSkillHaveExpertLevel( uiSkillPressed ) ) + { + //dont need to do anything + return; + } + else + { + // if the other trait has not been set yet, we rather set it now, + // instead of deselecting the already set one + if( gfSkillTraitQuestions2[ uiCntMax-1 ] == TRUE && gfSkillTraitQuestions[ uiCntMax-1 ] == FALSE && (uiSkillPressed != (uiCntMax-1)) ) + { + // Unselect NONE button + gfSkillTraitQuestions2[ uiCntMax-1 ] = FALSE; + //Set the skill + gfSkillTraitQuestions2[ uiSkillPressed ] = TRUE; + } + else + { + if ( CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubNumberOfMajorTraitsAllowed && CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubMaxNumberOfTraits ) + { + // we can select next one, simply do so + gfSkillTraitQuestions[ uiSkillPressed ] = TRUE; + // Unselect NONE button if necessary + gfSkillTraitQuestions[ uiCntMax-1 ] = FALSE; -/* - //if there are already 2 skills selected, and we are trying to PRESS a new button ( skill isnt currently set ) - if( CountNumSkillStraitsSelected() == 2 && - !gfSkillTraitQuestions[ uiSkillPressed ] && - uiSkillPressed != IMP_SKILL_TRAITS__NONE ) - { - //if we have to, unselect an existing trait + HandleLastSelectedTraits( (INT8)uiSkillPressed ); + } + else + { + if ( gSkillTraitValues.ubNumberOfMajorTraitsAllowed == 2 ) + { + //loop through all the skill and reset them + for( uiCnt=0; uiCnt= (uiCntMax-2) ) + { + for( uiCnt=0; uiCnt<(uiCntMax-1); uiCnt++ ) + { + if ( gfSkillTraitQuestions2[ uiCnt ] == TRUE ) + { + gfSkillTraitQuestions2[ uiCnt ] = FALSE; + break; + } + } + } + } + } + } + //Set the skill + gfSkillTraitQuestions[ uiSkillPressed ] = TRUE; - //play the diosabld sound -// PlayButtonSound( giIMPSkillTraitAnswerButton[ uiSkillPressed ], BUTTON_SOUND_DISABLED_CLICK ); - - //dont select a new one -// return; - } -*/ - - //Set the skill -// gfSkillTraitQuestions[ uiSkillPressed ] = !gfSkillTraitQuestions[ uiSkillPressed ]; - gfSkillTraitQuestions[ uiSkillPressed ] = TRUE; - - //if the NONE trait was selected, clear the rest of the buttons - if( uiSkillPressed == IMP_SKILL_TRAITS__NONE ) - { - //reset all the traits - HandleIMPSkillTraitAnswers( 0, TRUE ); - - gfSkillTraitQuestions[ IMP_SKILL_TRAITS__NONE ] = TRUE; - } - - - //make sure the none skill is NOT selected if we select anything else - if( uiSkillPressed != IMP_SKILL_TRAITS__NONE ) - { - gfSkillTraitQuestions[ IMP_SKILL_TRAITS__NONE ] = FALSE; - } - - //Play the button sound - if( gfSkillTraitQuestions[ uiSkillPressed ] ) - { - PlayButtonSound( giIMPSkillTraitAnswerButton[ uiSkillPressed ], BUTTON_SOUND_CLICKED_ON ); + HandleLastSelectedTraits( (INT8)uiSkillPressed ); + } + } + } + + //Play the button sound + if( gfSkillTraitQuestions[ uiSkillPressed ] ) + { + PlayButtonSound( giIMPSkillTraitAnswerButton[ uiSkillPressed ], BUTTON_SOUND_CLICKED_ON ); + } + else + { + PlayButtonSound( giIMPSkillTraitAnswerButton[ uiSkillPressed ], BUTTON_SOUND_CLICKED_OFF ); + } } else { - PlayButtonSound( giIMPSkillTraitAnswerButton[ uiSkillPressed ], BUTTON_SOUND_CLICKED_OFF ); + //if its allready set + if( gfSkillTraitQuestions2[ uiSkillPressed ] ) + { + gfSkillTraitQuestions2[ uiSkillPressed ] = FALSE; + + BOOLEAN fNoSkillSelected = TRUE; + for ( uiCnt=0; uiCnt<(uiCntMax-1); uiCnt++ ) + { + if ( gfSkillTraitQuestions2[ uiCnt ] == TRUE ) + fNoSkillSelected = FALSE; + } + if ( fNoSkillSelected ) + { + // select NONE button + gfSkillTraitQuestions2[ uiCntMax-1 ] = TRUE; + } + } + // if cannot have expert level of skill, don't continue + else if ( gfSkillTraitQuestions[ uiSkillPressed ] && !DoesSkillHaveExpertLevel( uiSkillPressed ) ) + { + //dont need to do anything + return; + } + else + { + // if the other trait has not been set yet, we rather set it now, + // instead of deselecting the already set one + if( gfSkillTraitQuestions[ uiCntMax-1 ] == TRUE && gfSkillTraitQuestions2[ uiCntMax-1 ] == FALSE && (uiSkillPressed != (uiCntMax-1)) ) + { + // Unselect NONE button + gfSkillTraitQuestions[ uiCntMax-1 ] = FALSE; + //Set the skill + gfSkillTraitQuestions[ uiSkillPressed ] = TRUE; + } + else + { + if ( CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubNumberOfMajorTraitsAllowed && CountNumSkillTraitsSelected( FALSE ) < gSkillTraitValues.ubMaxNumberOfTraits ) + { + // we can select next one, simply do so + gfSkillTraitQuestions2[ uiSkillPressed ] = TRUE; + // Unselect NONE button if necessary + gfSkillTraitQuestions2[ uiCntMax-1 ] = FALSE; + + HandleLastSelectedTraits( (INT8)uiSkillPressed ); + } + else + { + if ( gSkillTraitValues.ubNumberOfMajorTraitsAllowed == 2 ) + { + //loop through all the skill and reset them + for( uiCnt=0; uiCnt= (uiCntMax-2) ) + { + for( uiCnt=0; uiCnt<(uiCntMax-1); uiCnt++ ) + { + if ( gfSkillTraitQuestions[ uiCnt ] == TRUE ) + { + gfSkillTraitQuestions[ uiCnt ] = FALSE; + break; + } + } + } + } + } + } + //Set the skill + gfSkillTraitQuestions2[ uiSkillPressed ] = TRUE; + + HandleLastSelectedTraits( (INT8)uiSkillPressed ); + } + } + } + + //Play the button sound + if( gfSkillTraitQuestions2[ uiSkillPressed ] ) + { + PlayButtonSound( giIMPSkillTraitAnswerButton2[ uiSkillPressed ], BUTTON_SOUND_CLICKED_ON ); + } + else + { + PlayButtonSound( giIMPSkillTraitAnswerButton2[ uiSkillPressed ], BUTTON_SOUND_CLICKED_OFF ); + } } //update buttons @@ -386,28 +728,30 @@ void HandleIMPSkillTraitAnswers( UINT32 uiSkillPressed, BOOLEAN fResetAllButtons gfIST_Redraw = TRUE; } -INT8 CountNumSkillStraitsSelected( BOOLEAN fIncludeNoneSkill ) +INT8 CountNumSkillTraitsSelected( BOOLEAN fIncludeNoneSkill ) { - UINT32 uiCnt; + UINT32 uiCnt, uiCntMax; INT8 iNumberSkills=0; - UINT32 uiUpperLimit; - if( fIncludeNoneSkill ) - { - uiUpperLimit = IMP_SKILL_TRAITS__NUMBER_SKILLS; - } + if ( gGameOptions.fNewTraitSystem ) + uiCntMax = IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS; else - { - uiUpperLimit = IMP_SKILL_TRAITS__NONE; - } + uiCntMax = IMP_SKILL_TRAITS__NUMBER_SKILLS; - for( uiCnt=0; uiCnt < uiUpperLimit; uiCnt++ ) + for( uiCnt=0; uiCnt < uiCntMax; uiCnt++ ) { + if( !fIncludeNoneSkill && (uiCnt == (uiCntMax-1)) ) + continue; + //if the skill is selected ( ie depressed ) if( gfSkillTraitQuestions[ uiCnt ] ) { iNumberSkills++; } + if( gfSkillTraitQuestions2[ uiCnt ] ) + { + iNumberSkills++; + } } return( iNumberSkills ); @@ -416,9 +760,9 @@ INT8 CountNumSkillStraitsSelected( BOOLEAN fIncludeNoneSkill ) void HandleSkillTraitButtonStates( ) { - UINT32 uiCnt; + INT32 uiCnt; - for( uiCnt=0; uiCntuiFlags &= ~BUTTON_CLICKED_ON; } + + if( gfSkillTraitQuestions2[ uiCnt ] ) + { + ButtonList[ giIMPSkillTraitAnswerButton2[ uiCnt ] ]->uiFlags |= BUTTON_CLICKED_ON; + } + else + { + ButtonList[ giIMPSkillTraitAnswerButton2[ uiCnt ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + } } } void IMPSkillTraitDisplaySkills() { - UINT32 uiCnt; + UINT32 uiCnt, uiCntMax; UINT16 usPosX, usPosY; UINT16 usBoxPosX, usBoxPosY; + INT16 usSpaceBetweenButtons; + UINT8 uiNumSkillsToStartRightColumn; HVOBJECT hImageHandle; + if ( gGameOptions.fNewTraitSystem ) + { + uiCntMax = IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS; + uiNumSkillsToStartRightColumn = 4; + usSpaceBetweenButtons = IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS + 5; - //Display the title - DrawTextToScreen( gzIMPSkillTraitsText[ IMP_SKILL_TRAIT__TITLE_TEXT ], IMP_SKILL_TRAIT__TITLE_X, IMP_SKILL_TRAIT__TITLE_Y, IMP_SKILL_TRAIT__TITLE_WIDTH, IMP_SKILL_TRAIT__TITLE_FONT, IMP_SKILL_TRAIT__COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + //Display the title + DrawTextToScreen( gzIMPSkillTraitsTextNewMajor[ IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS ], IMP_SKILL_TRAIT__TITLE_X, IMP_SKILL_TRAIT__TITLE_Y, IMP_SKILL_TRAIT__TITLE_WIDTH, IMP_SKILL_TRAIT__TITLE_FONT, IMP_SKILL_TRAIT__COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } + else + { + uiCntMax = IMP_SKILL_TRAITS__NUMBER_SKILLS; + uiNumSkillsToStartRightColumn = 6; + usSpaceBetweenButtons = IMP_SKILL_TRAIT__SPACE_BTN_BUTTONS; + + //Display the title + DrawTextToScreen( gzIMPSkillTraitsText[ IMP_SKILL_TRAITS__NUMBER_SKILLS ], IMP_SKILL_TRAIT__TITLE_X, IMP_SKILL_TRAIT__TITLE_Y, IMP_SKILL_TRAIT__TITLE_WIDTH, IMP_SKILL_TRAIT__TITLE_FONT, IMP_SKILL_TRAIT__COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + } // Stats GetVideoObject(&hImageHandle, guiIST_GreyGoldBox ); @@ -455,7 +825,7 @@ void IMPSkillTraitDisplaySkills() usPosX = IMP_SKILL_TRAIT__LEFT_COLUMN_START_X + IMP_SKILL_TRAIT__TEXT_OFFSET_X; usPosY = IMP_SKILL_TRAIT__LEFT_COLUMN_START_Y + IMP_SKILL_TRAIT__TEXT_OFFSET_Y; - for( uiCnt=0; uiCntuiFlags|=(BUTTON_CLICKED_ON); - //if we are just reviewing the page - if( iCurrentProfileMode == IMP__FINISH ) + if( gGameOptions.fNewTraitSystem ) { - //go back tot he done screen - iCurrentImpPage = IMP_FINISH; + iCurrentImpPage = IMP_MINOR_TRAITS_PAGE; + fButtonPendingFlag = TRUE; } else { - iCurrentImpPage = IMP_MAIN_PAGE; - - if( CameBackToSpecialtiesPageButNotFinished() ) + //if we are just reviewing the page + if( iCurrentProfileMode == IMP__FINISH ) { + //go back tot he done screen + iCurrentImpPage = IMP_FINISH; } else { - //We are finished on this page - iCurrentProfileMode = IMP__ATTRIBUTES; - } + iCurrentImpPage = IMP_MAIN_PAGE; + + if( CameBackToSpecialtiesPageButNotFinished() ) + { + } + else + { + //We are finished on this page + iCurrentProfileMode = IMP__ATTRIBUTES; + } + } } } } - BOOLEAN CameBackToSpecialtiesPageButNotFinished() { //if we are in a page that comes after this one @@ -554,131 +952,308 @@ BOOLEAN CameBackToSpecialtiesPageButNotFinished() } } - - - - -INT8 DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection() +INT32 DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection() { - INT8 bExtraPoints=10; - INT8 bNumSkills=0; + INT32 iExtraPoints=0; // set to zero - SANDRO + INT32 bNumSkills=0; //Count the number of skills selected - bNumSkills = CountNumSkillStraitsSelected( FALSE ); + bNumSkills = CountNumSkillTraitsSelected( FALSE ); - //if there NONE selected - if( bNumSkills == 0 ) + // Externilized bonus for not taking skills - SANDRO + if( gGameOptions.fNewTraitSystem ) { - // Externilized bonus for not taking skills - SANDRO - bExtraPoints = 2 * (gGameExternalOptions.iBonusPointsPerSkillNotTaken); - } + // add selected minor traits + bNumSkills += CountNumMinorTraitsSelected( FALSE ); - //if there is 1 trait selected - else if( bNumSkills == 1 ) - { - //if the trait is not the ones you cant be expert in ) - if( gfSkillTraitQuestions[ IMP_SKILL_TRAITS__ELECTRONICS ] || - gfSkillTraitQuestions[ IMP_SKILL_TRAITS__AMBIDEXTROUS ] ) // Actually camo skill can be achived at expert level, although it does nothing now - SANDRO - // || gfSkillTraitQuestions[ IMP_SKILL_TRAITS__CAMO ] ) - { - // Externilized bonus for not taking skills - SANDRO - bExtraPoints = gGameExternalOptions.iBonusPointsPerSkillNotTaken; - } - else - { - bExtraPoints = 0; - } + iExtraPoints = (max( 0, 3 - bNumSkills)) * (gGameExternalOptions.iBonusPointsPerSkillNotTaken); } - - //else both traits selected else { - bExtraPoints = 0; + iExtraPoints = (max( 0, 2 - bNumSkills)) * (gGameExternalOptions.iBonusPointsPerSkillNotTaken); } - return( bExtraPoints ); + return( iExtraPoints ); } BOOLEAN ShouldTraitBeSkipped( UINT32 uiTrait ) { - // added a check to not offer martial arts to big mercs - SANDRO - if( uiTrait == IMP_SKILL_TRAITS__MARTIAL_ARTS && (!fCharacterIsMale || bBigBodySelected()) ) - return( TRUE ); - else + // there are no traits discriminating any gender in new trait system + if( gGameOptions.fNewTraitSystem ) + { return( FALSE ); + } + else + { + if( uiTrait == IMP_SKILL_TRAITS__MARTIAL_ARTS && (!fCharacterIsMale || bBigBodySelected()) ) + return( TRUE ); + else + return( FALSE ); + } } +BOOLEAN DoesSkillHaveExpertLevel( UINT32 uiSkillTrait ) +{ + if( gGameOptions.fNewTraitSystem ) + { + return( TRUE ); + } + else + { + if (uiSkillTrait == IMP_SKILL_TRAITS__ELECTRONICS || + uiSkillTrait == IMP_SKILL_TRAITS__AMBIDEXTROUS || + uiSkillTrait == IMP_SKILL_TRAITS__CAMO ) + { + return( FALSE ); + } + else + { + return( TRUE ); + } + } + return( TRUE ); +} void AddSelectedSkillsToSkillsList() { - UINT32 uiCnt; + INT32 uiCnt; //loop through all the buttons and reset them - for( uiCnt=0; uiCnt=0; iCnt-- ) + { + if ( gbLastSelectedTraits[ iCnt ] > 0 ) + { + gbLastSelectedTraits[ iCnt ] = 0; + break; + } + } + } - else { - //unselect old trait - gfSkillTraitQuestions[ gbLastSelectedTraits[ 1 ] ] = FALSE; - - gbLastSelectedTraits[ 1 ] = gbLastSelectedTraits[ 0 ]; + for( iCnt=0; iCnt<9; iCnt++ ) + { + gbLastSelectedTraits[ (iCnt + 1) ] = gbLastSelectedTraits[ iCnt ]; + } gbLastSelectedTraits[ 0 ] = bNewTrait; } } + +INT8 GetLastSelectedSkill( void ) +{ + INT16 iCnt; + + for( iCnt=9; iCnt>=0; iCnt-- ) + { + if ( gbLastSelectedTraits[ iCnt ] > 0 ) + { + return ( gbLastSelectedTraits[ iCnt ] ); + break; + } + } + return ( 0 ); +} + +INT32 StrengthRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + return (60); + else + return (45); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + return (55); + else + return (40); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + return (45); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + return (40); + } + + return(0); +} +INT32 AgilityRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + return (45); + } + + return(0); +} +INT32 DexterityRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + return (45); + } + + return(0); +} +INT32 HealthRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + return (60); + else + return (45); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + return (45); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS ]) + { + return (45); + } + + return(0); +} +INT32 LeadershipRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_SQUADLEADER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_SQUADLEADER ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + return (50); + else + return (35); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_SQUADLEADER ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + return (35); + } + + return(0); +} +INT32 WisdomRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_SQUADLEADER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_SQUADLEADER ]) + return (75); + else + return (60); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + return (65); + else + return (50); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_SQUADLEADER ]) + { + return (60); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + { + return (50); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + return (45); + } + + return(0); +} +INT32 MarksmanshipRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + return (80); + else + return (65); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + return (70); + else + return (55); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_PROF_SNIPER ]) + { + return (65); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_RANGER ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_GUNSLINGER ]) + { + return (55); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS ]) + { + return (45); + } + + return(0); +} +INT32 MechanicalRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + return (45); + } + + return(0); +} +INT32 MedicalRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_DOCTOR ]) + { + return (45); + } + + return(0); +} +INT32 ExplosivesRequiredDueToMajorSkills( void ) +{ + // Only for new trait system + if (!gGameOptions.fNewTraitSystem) + { + return (0); + } + + // Check first skill trait (plus second for double trait) + if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + return (60); + else + return (45); + } + else if (gfSkillTraitQuestions[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + return (60); + else + return (45); + } + // Check the second skill trait + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS ]) + { + return (45); + } + else if (gfSkillTraitQuestions2[ IMP_SKILL_TRAITS_NEW_TECHNICIAN ]) + { + return (45); + } + + return(0); +} + +void AssignSkillTraitHelpText( UINT8 ubTraitNumber, BOOLEAN fExpertLevel ) +{ + CHAR16 apStr[ 5000 ]; + CHAR16 atStr[ 1500 ]; + + if( gGameOptions.fNewTraitSystem ) + { + switch( ubTraitNumber ) + { + case IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubAWBonusCtHAssaultRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[0], ( gSkillTraitValues.ubAWBonusCtHAssaultRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWBonusCtHSMGs != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[1], ( gSkillTraitValues.ubAWBonusCtHSMGs * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWBonusCtHLMGs != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[2], ( gSkillTraitValues.ubAWBonusCtHLMGs * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWFiringSpeedBonusLMGs != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[3], ( gSkillTraitValues.ubAWFiringSpeedBonusLMGs * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWPercentReadyLMGReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[4], ( gSkillTraitValues.ubAWPercentReadyLMGReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWAutoFirePenaltyReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[5], ( gSkillTraitValues.ubAWAutoFirePenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWUnwantedBulletsReduction > 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[6]); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[0], ( gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWRocketLaunchersAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[1], ( gSkillTraitValues.ubHWRocketLaunchersAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWBonusCtHGrenadeLaunchers != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[2], ( gSkillTraitValues.ubHWBonusCtHGrenadeLaunchers * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWBonusCtHRocketLaunchers != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[3], ( gSkillTraitValues.ubHWBonusCtHRocketLaunchers * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWMortarAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[4], ( gSkillTraitValues.ubHWMortarAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWMortarCtHPenaltyReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[5], ( gSkillTraitValues.ubHWMortarCtHPenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWDamageTanksBonusPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[6], ( gSkillTraitValues.ubHWDamageTanksBonusPercent * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWDamageBonusPercentForHW != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[7], ( gSkillTraitValues.ubHWDamageBonusPercentForHW * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_PROF_SNIPER: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSNBonusCtHRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[0], ( gSkillTraitValues.ubSNBonusCtHRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNBonusCtHSniperRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[1], ( gSkillTraitValues.ubSNBonusCtHSniperRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNEffRangeToTargetReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[2], ( gSkillTraitValues.ubSNEffRangeToTargetReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNAimingBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[3], ( gSkillTraitValues.ubSNAimingBonusPerClick * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNDamageBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[4], ( gSkillTraitValues.ubSNDamageBonusPerClick * (fExpertLevel ? 2 : 1)), L"%"); + if( gSkillTraitValues.ubSNDamageBonusFromNumClicks == 0) + { + wcscat( apStr, gzIMPMajorTraitsHelpTextsSniper[5] ); + wcscat( apStr, gzIMPMajorTraitsHelpTextsSniper[6] ); + } + else if( gSkillTraitValues.ubSNDamageBonusFromNumClicks == 1 ) + { + wcscat( atStr, gzIMPMajorTraitsHelpTextsSniper[6] ); + } + else + { + wcscat( atStr, gzIMPMajorTraitsHelpTextsSniper[6] ); + wcscat( atStr, gzIMPMajorTraitsHelpTextsSniper[gSkillTraitValues.ubSNDamageBonusFromNumClicks + 4] ); + } + wcscat( atStr, L"\n" ); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNChamberRoundAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[14], ( gSkillTraitValues.ubSNChamberRoundAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNAimClicksAdded != 0 ) + { + if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[15]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[16], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); + + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_RANGER: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubRABonusCtHRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[0], ( gSkillTraitValues.ubRABonusCtHRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRABonusCtHShotguns != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[1], ( gSkillTraitValues.ubRABonusCtHShotguns * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAPumpShotgunsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[2], ( gSkillTraitValues.ubRAPumpShotgunsAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAGroupTimeSpentForTravellingFoot != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[3], ( gSkillTraitValues.ubRAGroupTimeSpentForTravellingFoot * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAGroupTimeSpentForTravellingVehicle != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[4], ( gSkillTraitValues.ubRAGroupTimeSpentForTravellingVehicle * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRABreathForTravellingReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[5], ( gSkillTraitValues.ubRABreathForTravellingReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAWeatherPenaltiesReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[6], ( gSkillTraitValues.ubRAWeatherPenaltiesReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + // if( gSkillTraitValues.ubRACamoEffectivenessBonus != 0 ) + // { + // swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[7], ( gSkillTraitValues.ubRACamoEffectivenessBonus * (fExpertLevel ? 2 : 1)), L"%"); + // wcscat( apStr, atStr ); + // } + if( gSkillTraitValues.ubRACamoWornountSpeedReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[8], ( gSkillTraitValues.ubRACamoWornountSpeedReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_GUNSLINGER: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubGSFiringSpeedBonusPistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[0], ( gSkillTraitValues.ubGSFiringSpeedBonusPistols * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSEffectiveRangeBonusPistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[1], ( gSkillTraitValues.ubGSEffectiveRangeBonusPistols * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSBonusCtHPistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[2], ( gSkillTraitValues.ubGSBonusCtHPistols * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSBonusCtHMachinePistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[3], ( gSkillTraitValues.ubGSBonusCtHMachinePistols * (fExpertLevel ? 2 : 1)), L"%"); + if( gSkillTraitValues.ubGSCtHMPExcludeAuto ) + wcscat( atStr, gzIMPMajorTraitsHelpTextsGunslinger[4] ); + wcscat( atStr, L"\n"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSAimingBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[5], ( gSkillTraitValues.ubGSAimingBonusPerClick * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSPercentReadyPistolsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[6], ( gSkillTraitValues.ubGSPercentReadyPistolsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSRealoadSpeedHandgunsBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[7], ( gSkillTraitValues.ubGSRealoadSpeedHandgunsBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSAimClicksAdded != 0 ) + { + if( gSkillTraitValues.ubGSAimClicksAdded == 1 && !fExpertLevel ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[8], ( gSkillTraitValues.ubGSAimClicksAdded * (fExpertLevel ? 2 : 1))); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[9], ( gSkillTraitValues.ubGSAimClicksAdded * (fExpertLevel ? 2 : 1))); + + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubMAPunchAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[0], ( gSkillTraitValues.ubMAPunchAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusCtHBareHands != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[1], ( gSkillTraitValues.ubMABonusCtHBareHands * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusCtHBrassKnuckles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[2], ( gSkillTraitValues.ubMABonusCtHBrassKnuckles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusDamageHandToHand != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[3], ( gSkillTraitValues.ubMABonusDamageHandToHand * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusBreathDamageHandToHand != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[4], ( gSkillTraitValues.ubMABonusBreathDamageHandToHand * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usMALostBreathRegainPenalty != 0 ) + { + if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 25) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[5]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 50) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[6]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 100) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[7]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 200) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[8]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 400) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[9]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 700) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[10]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[11]); + + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usMAAimedPunchDamageBonus != 0 ) + { + if (!fCharacterIsMale || bBigBodySelected() || (gSkillTraitValues.fPermitExtraAnimationsOnlyToMA && (!gfSkillTraitQuestions[ubTraitNumber] || !gfSkillTraitQuestions2[ubTraitNumber]))) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[12], ( gSkillTraitValues.usMAAimedPunchDamageBonus * (fExpertLevel ? 2 : 1)), L"%"); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[13], ( gSkillTraitValues.usMAAimedPunchDamageBonus * (fExpertLevel ? 2 : 1)), L"%"); + + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAChanceToDodgeHtH != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[14], ( gSkillTraitValues.ubMAChanceToDodgeHtH * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAOnTopCTDHtHBareHanded != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[15], ( gSkillTraitValues.ubMAOnTopCTDHtHBareHanded * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + if( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles == gSkillTraitValues.ubMAOnTopCTDHtHBareHanded ) + wcscat( apStr, gzIMPMajorTraitsHelpTextsMartialArts[16] ); + else if( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles > 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[17], ( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + wcscat( apStr, L"\n" ); + } + else if( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[18], ( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAChanceToDodgeMelee != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[19], ( gSkillTraitValues.ubMAChanceToDodgeMelee * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAReducedAPsToSteal != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[20], ( gSkillTraitValues.ubMAReducedAPsToSteal * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAAPsChangeStanceReduction != 0 && ( gSkillTraitValues.ubMAAPsChangeStanceReduction == gSkillTraitValues.ubMAApsTurnAroundReduction == gSkillTraitValues.ubMAAPsClimbOrJumpReduction )) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[21], ( gSkillTraitValues.ubMAAPsChangeStanceReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + else + { + if( gSkillTraitValues.ubMAAPsChangeStanceReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[22], ( gSkillTraitValues.ubMAAPsChangeStanceReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAApsTurnAroundReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[23], ( gSkillTraitValues.ubMAApsTurnAroundReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAAPsClimbOrJumpReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[24], ( gSkillTraitValues.ubMAAPsClimbOrJumpReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + } + if( gSkillTraitValues.ubMAChanceToCkickDoors != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[25], ( gSkillTraitValues.ubMAChanceToCkickDoors * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if (fCharacterIsMale && !bBigBodySelected() && + ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA && fExpertLevel) || + !gSkillTraitValues.fPermitExtraAnimationsOnlyToMA )) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[26]); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_SQUADLEADER: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSLBonusAPsPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[0], ( gSkillTraitValues.ubSLBonusAPsPercent * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLEffectiveLevelInRadius != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[1], ( gSkillTraitValues.ubSLEffectiveLevelInRadius * (fExpertLevel ? 2 : 1)), (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLEffectiveLevelAsStandby != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[2], ( gSkillTraitValues.ubSLEffectiveLevelAsStandby * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLOverallSuppresionBonusPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[3], ( gSkillTraitValues.ubSLOverallSuppresionBonusPercent * (fExpertLevel ? 2 : 1)), L"%", (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLMoraleGainBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[4], ( gSkillTraitValues.ubSLMoraleGainBonus * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLMoraleLossReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[5], ( gSkillTraitValues.ubSLMoraleLossReduction * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[6], gSkillTraitValues.usSLRadiusNormal); + wcscat( apStr, atStr ); + if( gSkillTraitValues.usSLRadiusExtendedEar > gSkillTraitValues.usSLRadiusNormal ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[7], gSkillTraitValues.usSLRadiusExtendedEar); + + wcscat( apStr, atStr ); + wcscat( apStr, L"\n" ); + + if( gSkillTraitValues.ubSLMaxBonuses > 1 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[8], gSkillTraitValues.ubSLMaxBonuses ) ; + wcscat( apStr, atStr ); + } + + if( gSkillTraitValues.ubSLFearResistance != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[9], ( gSkillTraitValues.ubSLFearResistance * (fExpertLevel ? 2 : 1)), L"%", (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLDeathMoralelossMultiplier != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[10], (1 + ( gSkillTraitValues.ubSLDeathMoralelossMultiplier * (fExpertLevel ? 2 : 1))), (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_TECHNICIAN: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.usTERepairSpeedBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[0], ( gSkillTraitValues.usTERepairSpeedBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usTELockpickingBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[1], ( gSkillTraitValues.usTELockpickingBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usTEDisarmElTrapBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[2], ( gSkillTraitValues.usTEDisarmElTrapBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usTEAttachingItemsBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[3], ( gSkillTraitValues.usTEAttachingItemsBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTEUnjamGunBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[4], ( gSkillTraitValues.ubTEUnjamGunBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTERepairElectronicsPenaltyReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[5], ( gSkillTraitValues.ubTERepairElectronicsPenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTEChanceToDetectTrapsBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[6], ( gSkillTraitValues.ubTEChanceToDetectTrapsBonus * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTECtHControlledRobotBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[7], ( gSkillTraitValues.ubTECtHControlledRobotBonus * (fExpertLevel ? 2 : 1)), L"%", (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTETraitsNumToRepairRobot == 2 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[8], (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + } + else if( gSkillTraitValues.ubTETraitsNumToRepairRobot == 1 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[8], (fExpertLevel ? gzIMPSkillTraitsTextNewMajor[ubTraitNumber + 11] : gzIMPSkillTraitsTextNewMajor[ubTraitNumber])); + wcscat( apStr, atStr ); + + if( gSkillTraitValues.ubTERepairRobotPenaltyReduction != 0 && fExpertLevel) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[9], ( gSkillTraitValues.ubTERepairRobotPenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + } + break; + } + case IMP_SKILL_TRAITS_NEW_DOCTOR: + { + BOOLEAN fCanSurgery = FALSE; + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubDONumberTraitsNeededForSurgery != 0 && ((gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop) > 0)) + { + if( gSkillTraitValues.ubDONumberTraitsNeededForSurgery <= (fExpertLevel ? 2 : 1)) + { + fCanSurgery = TRUE; + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[0]); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[1], (gSkillTraitValues.ubDOSurgeryHealPercentBase + ( gSkillTraitValues.ubDOSurgeryHealPercentOnTop * (fExpertLevel ? 2 : 1))), L"%"); + wcscat( apStr, atStr ); + if( gSkillTraitValues.usDOSurgeryMedBagConsumption >= 60 ) + wcscat( apStr, gzIMPMajorTraitsHelpTextsDoctor[2] ); + + wcscat( apStr, L"\n" ); + } + } + if( (gSkillTraitValues.usDORepairStatsRateBasic + gSkillTraitValues.usDORepairStatsRateOnTop) > 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[3]); + wcscat( apStr, atStr ); + if( fCanSurgery ) + wcscat( apStr, gzIMPMajorTraitsHelpTextsDoctor[4] ); + + wcscat( apStr, gzIMPMajorTraitsHelpTextsDoctor[5] ); + } + if( gSkillTraitValues.usDODoctorAssignmentBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[6], ( gSkillTraitValues.usDODoctorAssignmentBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDOBandagingSpeedPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[7], ( gSkillTraitValues.ubDOBandagingSpeedPercent * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDONaturalRegenBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[8], ( gSkillTraitValues.ubDONaturalRegenBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + if( gSkillTraitValues.ubDOMaxRegenBonuses > 1 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[9], gSkillTraitValues.ubDOMaxRegenBonuses ) ; + wcscat( apStr, atStr ); + } + wcscat( apStr, L"\n" ); + } + break; + } + case IMP_SKILL_TRAITS_NEW_MAJOR_NONE: + { + swprintf( apStr, gzIMPMajorTraitsHelpTextsNone[0] ); + break; + } + } + } + else + { + switch( ubTraitNumber ) + { + case IMP_SKILL_TRAITS__LOCKPICK: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[LOCKPICKING_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[0], ( gbSkillTraitBonus[LOCKPICKING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__HAND_2_HAND: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[HANDTOHAND_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[1], ( gbSkillTraitBonus[HANDTOHAND_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[2], ( 3 * gbSkillTraitBonus[HANDTOHAND_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[3], ( gbSkillTraitBonus[HANDTOHAND_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__ELECTRONICS: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[4] ); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__NIGHT_OPS: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[5], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[6], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[7], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[8], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[9], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__THROWING: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[THROWING_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[10], ( gbSkillTraitBonus[THROWING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[11], ( gbSkillTraitBonus[THROWING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[12], ( 10 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__TEACHING: + { + swprintf( apStr, L"" ); + if( gGameExternalOptions.ubTeachBonusToTrain != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[13], ( gGameExternalOptions.ubTeachBonusToTrain * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( (gGameExternalOptions.usTeacherTraitEffectOnLeadership - 100) > 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[14], ( (gGameExternalOptions.usTeacherTraitEffectOnLeadership - 100) * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__HEAVY_WEAPONS: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[HEAVY_WEAPS_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[15], ( gbSkillTraitBonus[HEAVY_WEAPS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__AUTO_WEAPONS: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[16], ( 2 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[17] ); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__STEALTHY: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[18], ( 25 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + if( gGameExternalOptions.ubStealthTraitCoverValue != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[19], ( gGameExternalOptions.ubStealthTraitCoverValue * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__AMBIDEXTROUS: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[20] ); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__KNIFING: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[KNIFING_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[21], ( gbSkillTraitBonus[KNIFING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[22], ( gbSkillTraitBonus[KNIFING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[23], ( gbSkillTraitBonus[KNIFING_OT] / 3 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[24], ( gbSkillTraitBonus[KNIFING_OT] / 2 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case IMP_SKILL_TRAITS__PROF_SNIPER: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[PROF_SNIPER_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[25], ( gbSkillTraitBonus[PROF_SNIPER_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[26], ( 10 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__CAMO: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[27] ); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__MARTIAL_ARTS: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[MARTIALARTS_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[28], ( gbSkillTraitBonus[MARTIALARTS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[29], ( gbSkillTraitBonus[MARTIALARTS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[30], ( gbSkillTraitBonus[MARTIALARTS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[31], ( gbSkillTraitBonus[MARTIALARTS_OT] * 2 / 3 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[32], ( gbSkillTraitBonus[MARTIALARTS_OT] / 2 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[33]); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[34]); + wcscat( apStr, atStr ); + break; + } + case IMP_SKILL_TRAITS__NONE: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[35] ); + wcscat( apStr, atStr ); + break; + } + } + } + + // Set region help text + SetRegionFastHelpText( &(gMR_SkillTraitHelpTextRegions[ubTraitNumber]), apStr ); + SetRegionHelpEndCallback( &gMR_SkillTraitHelpTextRegions[ubTraitNumber], MSYS_NO_CALLBACK ); + + return; +} \ No newline at end of file diff --git a/Laptop/IMP Skill Trait.h b/Laptop/IMP Skill Trait.h index a141a704..34bf42f0 100644 --- a/Laptop/IMP Skill Trait.h +++ b/Laptop/IMP Skill Trait.h @@ -28,10 +28,37 @@ enum IMP_SKILL_TRAITS__NUMBER_SKILLS, }; -// STR16 gzIMPSkillTraitsText[]; +// other set for new traits - SANDRO +enum +{ + // major traits + IMP_SKILL_TRAITS_NEW_AUTO_WEAPONS, + IMP_SKILL_TRAITS_NEW_HEAVY_WEAPONS, + IMP_SKILL_TRAITS_NEW_PROF_SNIPER, + IMP_SKILL_TRAITS_NEW_RANGER, + IMP_SKILL_TRAITS_NEW_GUNSLINGER, + IMP_SKILL_TRAITS_NEW_MARTIAL_ARTS, + IMP_SKILL_TRAITS_NEW_SQUADLEADER, + IMP_SKILL_TRAITS_NEW_TECHNICIAN, + IMP_SKILL_TRAITS_NEW_DOCTOR, + IMP_SKILL_TRAITS_NEW_MAJOR_NONE, + IMP_SKILL_TRAITS_NEW_NUMBER_MAJOR_SKILLS, +}; -INT8 DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection(); +INT8 CountNumSkillTraitsSelected( BOOLEAN fIncludeNoneSkill ); +INT32 DoesPlayerHaveExtraAttibutePointsToDistributeBasedOnSkillSelection(); void AddSelectedSkillsToSkillsList(); +INT32 StrengthRequiredDueToMajorSkills( void ); +INT32 AgilityRequiredDueToMajorSkills( void ); +INT32 DexterityRequiredDueToMajorSkills( void ); +INT32 HealthRequiredDueToMajorSkills( void ); +INT32 LeadershipRequiredDueToMajorSkills( void ); +INT32 WisdomRequiredDueToMajorSkills( void ); +INT32 MarksmanshipRequiredDueToMajorSkills( void ); +INT32 MechanicalRequiredDueToMajorSkills( void ); +INT32 MedicalRequiredDueToMajorSkills( void ); +INT32 ExplosivesRequiredDueToMajorSkills( void ); + #endif diff --git a/Laptop/IMP Text System.cpp b/Laptop/IMP Text System.cpp index 790cf8d8..a5686932 100644 --- a/Laptop/IMP Text System.cpp +++ b/Laptop/IMP Text System.cpp @@ -12,6 +12,11 @@ #include "IMP Personality Finish.h" #include "IMP Attribute Selection.h" #include "IMP MainPage.h" + // added by SANDRO + #include "IMP Confirm.h" + #include "GameSettings.h" + #include "Text.h" + #include "_Ja25Englishtext.h" #endif #define IMP_SEEK_AMOUNT 5 * 80 * 2 @@ -180,14 +185,20 @@ void PrintImpText( void ) break; case ( IMP_PERSONALITY ): - // SANDRO - I HAVE CHANGED THESE TO BE ABLE TO EDIT THE TEXTS BEFORE SKILL TRAITS (THE TEXTS ARE ABOVE HERE) - // EVEN IF IT IS A LITTLE STUPID WAY, I HAVEN'T FOUND A WAY HOW TO EDIT IMPtext.edt.. - // THE TEXTS OF "pSkillTraitBeginIMPStrings" ARE IN "_EnglishText.cpp" at the end + // SANDRO - I HAVE CHANGED THESE TO BE ABLE TO EDIT THE TEXTS BEFORE SKILL TRAITS + // EVEN IF IT IS A LITTLE STUPID WAY, I HAVEN'T FOUND A DIFFERENT WAY //LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 60, ( 456 - 200 ), IMP_PERS_1, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); //LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 130, ( 456 - 200 ), IMP_PERS_2, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); - DisplayWrappedString( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 57, ( 456 - 200 ), 2, FONT12ARIAL, FONT_WHITE, pSkillTraitBeginIMPStrings[ 0 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); - DisplayWrappedString( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 140, ( 456 - 200 ), 2, FONT12ARIAL, FONT_WHITE, pSkillTraitBeginIMPStrings[ 1 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); - + if ( gGameOptions.fNewTraitSystem ) + { + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 57, ( 456 - 200 ), 2, FONT12ARIAL, FONT_WHITE, pSkillTraitBeginIMPStrings[ 2 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 155, ( 456 - 200 ), 2, FONT12ARIAL, FONT_WHITE, pSkillTraitBeginIMPStrings[ 3 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); + } + else + { + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 57, ( 456 - 200 ), 2, FONT12ARIAL, FONT_WHITE, pSkillTraitBeginIMPStrings[ 0 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 130, LAPTOP_SCREEN_WEB_UL_Y + 140, ( 456 - 200 ), 2, FONT12ARIAL, FONT_WHITE, pSkillTraitBeginIMPStrings[ 1 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); + } LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X - 111, LAPTOP_SCREEN_WEB_UL_Y + 7, sWidth, IMP_PERS_6, FONT14ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED ); @@ -217,11 +228,21 @@ void PrintImpText( void ) } break; case( IMP_ATTRIBUTE_ENTRANCE ): - LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X - 111, LAPTOP_SCREEN_WEB_UL_Y + 7, sWidth, IMP_ATTRIB_1 - 1, FONT14ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); - LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 110, LAPTOP_SCREEN_WEB_UL_Y + 50, ( 300 ), IMP_ATTRIB_5, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); - LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 110, LAPTOP_SCREEN_WEB_UL_Y + 130, ( 300 ), IMP_ATTRIB_6, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); - LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 110, LAPTOP_SCREEN_WEB_UL_Y + 200, ( 300 ), IMP_ATTRIB_7, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); - + if ( gGameOptions.fNewTraitSystem ) + { + CHAR16 sMinAttr[400]; + swprintf( sMinAttr, sgAttributeSelectionText[ 4 ], gGameExternalOptions.iMinAttribute ); + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 122, LAPTOP_SCREEN_WEB_UL_Y + 57, ( 466 - 190 ), 2, FONT12ARIAL, FONT_WHITE, sMinAttr,FONT_BLACK,FALSE,CENTER_JUSTIFIED); + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 122, LAPTOP_SCREEN_WEB_UL_Y + 116, ( 466 - 190 ), 2, FONT12ARIAL, FONT_WHITE, sgAttributeSelectionText[ 5 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 122, LAPTOP_SCREEN_WEB_UL_Y + 163, ( 466 - 190 ), 2, FONT12ARIAL, FONT_WHITE, sgAttributeSelectionText[ 6 ],FONT_BLACK,FALSE,CENTER_JUSTIFIED); + } + else + { + LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X - 111, LAPTOP_SCREEN_WEB_UL_Y + 7, sWidth, IMP_ATTRIB_1 - 1, FONT14ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); + LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 110, LAPTOP_SCREEN_WEB_UL_Y + 50, ( 300 ), IMP_ATTRIB_5, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); + LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 110, LAPTOP_SCREEN_WEB_UL_Y + 130, ( 300 ), IMP_ATTRIB_6, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); + LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 110, LAPTOP_SCREEN_WEB_UL_Y + 200, ( 300 ), IMP_ATTRIB_7, FONT12ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); + } break; case( IMP_ATTRIBUTE_PAGE ): LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X - 111, LAPTOP_SCREEN_WEB_UL_Y + 7, sWidth, IMP_ATTRIB_1 - 1, FONT14ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); @@ -284,9 +305,13 @@ void PrintImpText( void ) LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 150, LAPTOP_SCREEN_WEB_UL_Y + 55, ( 200 ), IMP_FIN_2 - 1, FONT12ARIAL, FONT_WHITE, TRUE, 0); break; case( IMP_CONFIRM ): - LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X - 111, LAPTOP_SCREEN_WEB_UL_Y + 7, sWidth, IMP_CON_1 , FONT14ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); + LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X - 111, LAPTOP_SCREEN_WEB_UL_Y + 7, sWidth, IMP_CON_1 , FONT14ARIAL, FONT_WHITE, TRUE, CENTER_JUSTIFIED); LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 160, LAPTOP_SCREEN_WEB_UL_Y + 60, ( 200 ), IMP_CON_2 , FONT12ARIAL, FONT_WHITE, TRUE, 0); - LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 160, LAPTOP_SCREEN_WEB_UL_Y + 145, ( 200 ), IMP_CON_3 , FONT12ARIAL, FONT_WHITE, TRUE, 0); + //LoadAndDisplayIMPText( LAPTOP_SCREEN_UL_X + 160, LAPTOP_SCREEN_WEB_UL_Y + 145, ( 200 ), IMP_CON_3 , FONT12ARIAL, FONT_WHITE, TRUE, 0); + // SANDRO - changed to show exact cost of profile + CHAR16 chPayCost[1000]; + swprintf( chPayCost, gzIMPProfileCostText[ 0 ], iGetProfileCost() ); + DisplayWrappedString( LAPTOP_SCREEN_UL_X + 160, LAPTOP_SCREEN_WEB_UL_Y + 145, ( 200 ), 2, FONT12ARIAL, FONT_WHITE, chPayCost,FONT_BLACK,FALSE,LEFT_JUSTIFIED); break; } diff --git a/Laptop/IMP Voices.cpp b/Laptop/IMP Voices.cpp index c222ab7c..1773589e 100644 --- a/Laptop/IMP Voices.cpp +++ b/Laptop/IMP Voices.cpp @@ -381,41 +381,7 @@ void BtnIMPVoicesDoneCallback(GUI_BUTTON *btn,INT32 reason) iCurrentImpPage = IMP_COLOR_CHOICE_PAGE; // Following part removed - // go to main page - /*iCurrentImpPage = IMP_MAIN_PAGE; - - // if we are already done, leave - if( iCurrentProfileMode == IMP__FINISH ) - { - iCurrentImpPage = IMP_FINISH; - } - else - { - if( CameBackToVoicePageButNotFinished() ) - { - iCurrentImpPage = IMP_MAIN_PAGE; - } - else - { - iCurrentProfileMode = IMP__PERSONALITY; - } - }*/ -/* - // current mode now is voice - else if( iCurrentProfileMode < IMP__PORTRAIT ) - { - iCurrentProfileMode = IMP__PORTRAIT; - } - - else if( iCurrentProfileMode == IMP__PORTRAIT ) - { - // all done profiling - iCurrentProfileMode = IMP__VOICE; - iCurrentImpPage = IMP_FINISH; - } -*/ // set voice id, to grab character slot - // WDS: Allow flexible numbers of IMPs of each sex LaptopSaveInfo.iIMPIndex = gGameExternalOptions.iaIMPSlots[iCurrentVoice]; diff --git a/Laptop/Laptop_VS2005.vcproj b/Laptop/Laptop_VS2005.vcproj new file mode 100644 index 00000000..5080264e --- /dev/null +++ b/Laptop/Laptop_VS2005.vcproj @@ -0,0 +1,895 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Laptop/Laptop_VS2008.vcproj b/Laptop/Laptop_VS2008.vcproj index 7451ae38..f1651a76 100644 --- a/Laptop/Laptop_VS2008.vcproj +++ b/Laptop/Laptop_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -507,6 +507,10 @@ RelativePath="IMP MainPage.h" > + + @@ -779,6 +783,10 @@ RelativePath="IMP MainPage.cpp" > + + @@ -863,10 +871,22 @@ RelativePath="Store Inventory.cpp" > + + + + + + diff --git a/Laptop/Laptop_VS2010.vcxproj b/Laptop/Laptop_VS2010.vcxproj new file mode 100644 index 00000000..d2144bc7 --- /dev/null +++ b/Laptop/Laptop_VS2010.vcxproj @@ -0,0 +1,350 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D} + Win32Proj + Laptop + Laptop + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Laptop/Laptop_VS2010.vcxproj.filters b/Laptop/Laptop_VS2010.vcxproj.filters new file mode 100644 index 00000000..ac5f0a25 --- /dev/null +++ b/Laptop/Laptop_VS2010.vcxproj.filters @@ -0,0 +1,426 @@ + + + + + {84a4f64f-bc1b-4e0c-848c-2b7c145ae615} + + + {b159d1de-d6d6-4531-b86a-b991f7210268} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Laptop/PostalService.cpp b/Laptop/PostalService.cpp index c6952b8a..dc36da2e 100644 --- a/Laptop/PostalService.cpp +++ b/Laptop/PostalService.cpp @@ -313,8 +313,11 @@ BOOLEAN CPostalService::DeliverShipment(UINT16 usShipmentID) if( (shs.pDestination->ubMapX > 0) && (shs.pDestination->ubMapX < MAP_WORLD_X - 1) && (shs.pDestination->ubMapY > 0) && - (shs.pDestination->ubMapY < MAP_WORLD_Y - 1) && - GridNoOnVisibleWorldTile(shs.pDestination->sGridNo) ) + (shs.pDestination->ubMapY < MAP_WORLD_Y - 1) ) //&& + //GridNoOnVisibleWorldTile(shs.pDestination->sGridNo) ) + // silversurfer: wtf? This test checked if the delivery tile was valid for the currently loaded sector + // which is not necessarily the delivery sector + // if we are currently below ground it will crash the game... { BOOLEAN fSectorLoaded = ( gWorldSectorX == shs.pDestination->ubMapX ) && ( gWorldSectorY == shs.pDestination->ubMapY ) && @@ -417,8 +420,6 @@ BOOLEAN CPostalService::DeliverShipment(UINT16 usShipmentID) tempObject[0]->data.gun.ubGunShotsLeft = 0; } - // TODO.RW: Hier Pablo stealing code einfgen und ubItemsDelivered reduzieren!!! - UINT8 cnt = -1; // Loop through the items of a package while ( ubItemsDelivered ) diff --git a/Laptop/XML_AIMAvailability.cpp b/Laptop/XML_AIMAvailability.cpp new file mode 100644 index 00000000..fb76224c --- /dev/null +++ b/Laptop/XML_AIMAvailability.cpp @@ -0,0 +1,234 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" + #include "aim.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + AIM_AVAILABLE curAimAvailability; + AIM_AVAILABLE * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef aimAvailabilityParseData; + +BOOLEAN AimAvailability_TextOnly; + +static void XMLCALL +aimAvailabilityStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + aimAvailabilityParseData * pData = (aimAvailabilityParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "AIM_AVAILABLES") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "AIM") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "ProfilId") == 0 || + strcmp(name, "AimBioID") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +aimCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + aimAvailabilityParseData * pData = (aimAvailabilityParseData *)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 +aimAvailabilityEndElementHandle(void *userData, const XML_Char *name) +{ + aimAvailabilityParseData * pData = (aimAvailabilityParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "AIM_AVAILABLES") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "AIM") == 0) + { + pData->curElement = ELEMENT_LIST; + + if (!AimAvailability_TextOnly) + { + gAimAvailability[pData->curAimAvailability.uiIndex].uiIndex = pData->curAimAvailability.uiIndex; + gAimAvailability[pData->curAimAvailability.uiIndex].ProfilId = pData->curAimAvailability.ProfilId; + gAimAvailability[pData->curAimAvailability.uiIndex].ubAimArrayID = pData->curAimAvailability.uiIndex; + gAimAvailability[pData->curAimAvailability.uiIndex].AimBio = pData->curAimAvailability.AimBio; + + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].uiIndex = pData->curAimAvailability.uiIndex; + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].ProfilId = pData->curAimAvailability.ProfilId; + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].ubAimArrayID = pData->curAimAvailability.uiIndex; + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].AimBio = pData->curAimAvailability.AimBio; + } + else + { + gAimAvailability[pData->curAimAvailability.uiIndex].uiIndex = pData->curAimAvailability.uiIndex; + gAimAvailability[pData->curAimAvailability.uiIndex].ProfilId = pData->curAimAvailability.ProfilId; + gAimAvailability[pData->curAimAvailability.uiIndex].ubAimArrayID = pData->curAimAvailability.uiIndex; + gAimAvailability[pData->curAimAvailability.uiIndex].AimBio = pData->curAimAvailability.AimBio; + + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].uiIndex = pData->curAimAvailability.uiIndex; + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].ProfilId = pData->curAimAvailability.ProfilId; + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].ubAimArrayID = pData->curAimAvailability.uiIndex; + gAimAvailabilityTemp[pData->curAimAvailability.uiIndex].AimBio = pData->curAimAvailability.AimBio; + } + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curAimAvailability.uiIndex = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "ProfilId") == 0) + { + pData->curElement = ELEMENT; + pData->curAimAvailability.ProfilId = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "AimBioID") == 0) + { + pData->curElement = ELEMENT; + pData->curAimAvailability.AimBio = (UINT8) atol(pData->szCharData); + } + + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInAimAvailability(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + aimAvailabilityParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading AimAvailability.xml" ); + + AimAvailability_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, aimAvailabilityStartElementHandle, aimAvailabilityEndElementHandle); + XML_SetCharacterDataHandler(parser, aimCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in AimAvailability.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + + +BOOLEAN WriteAimAvailability(STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < NUM_PROFILES;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", cnt); + // FilePrintf(hFile,"\t\t-1\r\n"); + // FilePrintf(hFile,"\t\t0\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", gAimAvailability[cnt].ProfilId); + FilePrintf(hFile,"\t\t%d\r\n", gAimAvailability[cnt].AimBio); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} \ No newline at end of file diff --git a/Laptop/XML_ConditionsForMercAvailability.cpp b/Laptop/XML_ConditionsForMercAvailability.cpp new file mode 100644 index 00000000..929d574f --- /dev/null +++ b/Laptop/XML_ConditionsForMercAvailability.cpp @@ -0,0 +1,294 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" + #include "mercs.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + CONTITION_FOR_MERC_AVAILABLE curMercAvailability; + CONTITION_FOR_MERC_AVAILABLE * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef mercAvailabilityParseData; + +BOOLEAN MercAvailability_TextOnly; + +static void XMLCALL +mercAvailabilityStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + mercAvailabilityParseData * pData = (mercAvailabilityParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "MERC_AVAILABLES") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "MERC") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "ProfilId") == 0 || + strcmp(name, "usMoneyPaid") == 0 || + strcmp(name, "Available") == 0 || + strcmp(name, "NewMercsAvailable") == 0 || + strcmp(name, "StartMercsAvailable") == 0 || + strcmp(name, "MercBioID") == 0 || + strcmp(name, "Drunk") == 0 || + strcmp(name, "uiAlternateIndex") == 0 || + strcmp(name, "usDay") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +mercCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + mercAvailabilityParseData * pData = (mercAvailabilityParseData *)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 +mercAvailabilityEndElementHandle(void *userData, const XML_Char *name) +{ + mercAvailabilityParseData * pData = (mercAvailabilityParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "MERC_AVAILABLES") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "MERC") == 0) + { + pData->curElement = ELEMENT_LIST; + + if (!MercAvailability_TextOnly) + { + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].uiIndex = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].ProfilId = pData->curMercAvailability.ProfilId; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].usMoneyPaid = pData->curMercAvailability.usMoneyPaid; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].usDay = pData->curMercAvailability.usDay; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].ubMercArrayID = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].NewMercsAvailable = pData->curMercAvailability.NewMercsAvailable; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].StartMercsAvailable = pData->curMercAvailability.StartMercsAvailable; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].MercBio = pData->curMercAvailability.MercBio; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].Drunk = pData->curMercAvailability.Drunk; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].uiAlternateIndex = pData->curMercAvailability.uiAlternateIndex; + + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].uiIndex = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].ProfilId = pData->curMercAvailability.ProfilId; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].usMoneyPaid = pData->curMercAvailability.usMoneyPaid; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].usDay = pData->curMercAvailability.usDay; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].ubMercArrayID = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].NewMercsAvailable = pData->curMercAvailability.NewMercsAvailable; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].StartMercsAvailable = pData->curMercAvailability.StartMercsAvailable; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].MercBio = pData->curMercAvailability.MercBio; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].Drunk = pData->curMercAvailability.Drunk; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].uiAlternateIndex = pData->curMercAvailability.uiAlternateIndex; + } + else + { + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].uiIndex = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].ProfilId = pData->curMercAvailability.ProfilId; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].usMoneyPaid = pData->curMercAvailability.usMoneyPaid; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].usDay = pData->curMercAvailability.usDay; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].ubMercArrayID = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].NewMercsAvailable = pData->curMercAvailability.NewMercsAvailable; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].StartMercsAvailable = pData->curMercAvailability.StartMercsAvailable; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].MercBio = pData->curMercAvailability.MercBio; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].Drunk = pData->curMercAvailability.Drunk; + gConditionsForMercAvailability[pData->curMercAvailability.uiIndex].uiAlternateIndex = pData->curMercAvailability.uiAlternateIndex; + + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].uiIndex = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].ProfilId = pData->curMercAvailability.ProfilId; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].usMoneyPaid = pData->curMercAvailability.usMoneyPaid; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].usDay = pData->curMercAvailability.usDay; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].ubMercArrayID = pData->curMercAvailability.uiIndex; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].NewMercsAvailable = pData->curMercAvailability.NewMercsAvailable; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].StartMercsAvailable = pData->curMercAvailability.StartMercsAvailable; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].MercBio = pData->curMercAvailability.MercBio; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].Drunk = pData->curMercAvailability.Drunk; + gConditionsForMercAvailabilityTemp[pData->curMercAvailability.uiIndex].uiAlternateIndex = pData->curMercAvailability.uiAlternateIndex; + + } + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.uiIndex = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "usMoneyPaid") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.usMoneyPaid = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "usDay") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.usDay = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "ProfilId") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.ProfilId = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "NewMercsAvailable") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.NewMercsAvailable = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "StartMercsAvailable") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.StartMercsAvailable = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "MercBioID") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.MercBio = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "Drunk") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.Drunk = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "uiAlternateIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curMercAvailability.uiAlternateIndex = (UINT8) atol(pData->szCharData); + } + + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInMercAvailability(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + mercAvailabilityParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading MercAvailability.xml" ); + + MercAvailability_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, mercAvailabilityStartElementHandle, mercAvailabilityEndElementHandle); + XML_SetCharacterDataHandler(parser, mercCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in MercAvailability.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + + +BOOLEAN WriteMercAvailability(STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < NUM_PROFILES;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t%d\r\n", gConditionsForMercAvailability[cnt].usMoneyPaid); + FilePrintf(hFile,"\t\t%d\r\n", gConditionsForMercAvailability[cnt].usDay); + FilePrintf(hFile,"\t\t%d\r\n", gConditionsForMercAvailability[cnt].ProfilId); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} \ No newline at end of file diff --git a/Laptop/XML_IMPPortraits.cpp b/Laptop/XML_IMPPortraits.cpp new file mode 100644 index 00000000..6aff0331 --- /dev/null +++ b/Laptop/XML_IMPPortraits.cpp @@ -0,0 +1,315 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" + #include "IMP Confirm.h" + #include "IMP Portraits.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + IMP_FACE_VALUES curIMPPortraits; + IMP_FACE_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; + //CHAR16 gzIMPPortraits[MAX_IMP_NAMES_CHARS]; +} +typedef impPortraitsParseData; + +BOOLEAN IMPPortraits_TextOnly; + +static void XMLCALL +impPortraitsStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + impPortraitsParseData * pData = (impPortraitsParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "IMPPORTRAITSLIST") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "IMP") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "PortraitId") == 0 || + strcmp(name, "bSex") == 0 || + strcmp(name, "usEyesX") == 0 || + strcmp(name, "usEyesY") == 0 || + strcmp(name, "usMouthY") == 0 || + strcmp(name, "usMouthX") == 0 || + strcmp(name, "DefaultSkin") == 0 || + strcmp(name, "DefaultHair") == 0 || + strcmp(name, "DefaultShirt") == 0 || + strcmp(name, "DefaultPants") == 0 || + strcmp(name, "DefaultBigBody") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +impPortraitsCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + impPortraitsParseData * pData = (impPortraitsParseData *)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 +impPortraitsEndElementHandle(void *userData, const XML_Char *name) +{ + impPortraitsParseData * pData = (impPortraitsParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "IMPPORTRAITSLIST") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "IMP") == 0) + { + pData->curElement = ELEMENT_LIST; + + if (!IMPPortraits_TextOnly) + { + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiEyeXPositions = pData->curIMPPortraits.uiEyeXPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiEyeYPositions = pData->curIMPPortraits.uiEyeYPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiMouthXPositions = pData->curIMPPortraits.uiMouthXPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiMouthYPositions = pData->curIMPPortraits.uiMouthYPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].PortraitId = pData->curIMPPortraits.PortraitId; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].bSex = pData->curIMPPortraits.bSex; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentSkin = pData->curIMPPortraits.iCurrentSkin; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentShirt = pData->curIMPPortraits.iCurrentShirt; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentHair = pData->curIMPPortraits.iCurrentHair; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentPants = pData->curIMPPortraits.iCurrentPants; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].bBigBody = pData->curIMPPortraits.bBigBody; + + } + else + { + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiEyeXPositions = pData->curIMPPortraits.uiEyeXPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiEyeYPositions = pData->curIMPPortraits.uiEyeYPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiMouthXPositions = pData->curIMPPortraits.uiMouthXPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].uiMouthYPositions = pData->curIMPPortraits.uiMouthYPositions; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].PortraitId = pData->curIMPPortraits.PortraitId; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].bSex = pData->curIMPPortraits.bSex; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentSkin = pData->curIMPPortraits.iCurrentSkin; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentShirt = pData->curIMPPortraits.iCurrentShirt; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentHair = pData->curIMPPortraits.iCurrentHair; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].iCurrentPants = pData->curIMPPortraits.iCurrentPants; + gIMPFaceValues[pData->curIMPPortraits.uiIndex].bBigBody = pData->curIMPPortraits.bBigBody; + + } + + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "PortraitId") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.PortraitId = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "bSex") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.bSex = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "usEyesX") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.uiEyeXPositions = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "usEyesY") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.uiEyeYPositions = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "usMouthX") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.uiMouthXPositions = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "usMouthY") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.uiMouthYPositions = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "DefaultSkin") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.iCurrentSkin = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "DefaultHair") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.iCurrentHair = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "DefaultShirt") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.iCurrentShirt = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "DefaultPants") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.iCurrentPants = (INT32) atol(pData->szCharData); + } + else if(strcmp(name, "DefaultBigBody") == 0) + { + pData->curElement = ELEMENT; + pData->curIMPPortraits.bBigBody = (INT32) atol(pData->szCharData); + } + + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInIMPPortraits(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + impPortraitsParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading IMPPortraits.xml" ); + + IMPPortraits_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, impPortraitsStartElementHandle, impPortraitsEndElementHandle); + XML_SetCharacterDataHandler(parser, impPortraitsCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in IMPPortraits.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 ); +} + + +void LoadIMPPortraitsTEMP() +{ +UINT32 cnt; +UINT32 cnt2 = 0; +UINT32 cnt3 = 0; + + for ( cnt = 0; cnt < 200; cnt++ ) + { + if (gIMPFaceValues[cnt].bSex == 1 && gIMPFaceValues[cnt].PortraitId !=0) + { + gIMPFemaleValues[cnt2].uiIndex = cnt2; + + gIMPFemaleValues[cnt2].Enabled = 1; + + gIMPFemaleValues[cnt2].uiEyeXPositions = gIMPFaceValues[cnt].uiEyeXPositions; + gIMPFemaleValues[cnt2].uiEyeYPositions = gIMPFaceValues[cnt].uiEyeYPositions; + gIMPFemaleValues[cnt2].uiMouthXPositions = gIMPFaceValues[cnt].uiMouthXPositions; + gIMPFemaleValues[cnt2].uiMouthYPositions = gIMPFaceValues[cnt].uiMouthYPositions; + gIMPFemaleValues[cnt2].PortraitId = gIMPFaceValues[cnt].PortraitId; + gIMPFemaleValues[cnt2].bSex = gIMPFaceValues[cnt].bSex; + gIMPFemaleValues[cnt2].iCurrentSkin = gIMPFaceValues[cnt].iCurrentSkin; + gIMPFemaleValues[cnt2].iCurrentShirt = gIMPFaceValues[cnt].iCurrentShirt; + gIMPFemaleValues[cnt2].iCurrentHair = gIMPFaceValues[cnt].iCurrentHair; + gIMPFemaleValues[cnt2].iCurrentPants = gIMPFaceValues[cnt].iCurrentPants; + gIMPFemaleValues[cnt2].bBigBody = gIMPFaceValues[cnt].bBigBody; + cnt2++; + } + } + + for ( cnt = 0; cnt < 200; cnt++ ) + { + if (gIMPFaceValues[cnt].bSex == 0 && gIMPFaceValues[cnt].PortraitId !=0) + { + gIMPMaleValues[cnt3].uiIndex = cnt3; + gIMPMaleValues[cnt3].Enabled = 1; + gIMPMaleValues[cnt3].uiEyeXPositions = gIMPFaceValues[cnt].uiEyeXPositions; + gIMPMaleValues[cnt3].uiEyeYPositions = gIMPFaceValues[cnt].uiEyeYPositions; + gIMPMaleValues[cnt3].uiMouthXPositions = gIMPFaceValues[cnt].uiMouthXPositions; + gIMPMaleValues[cnt3].uiMouthYPositions = gIMPFaceValues[cnt].uiMouthYPositions; + gIMPMaleValues[cnt3].PortraitId = gIMPFaceValues[cnt].PortraitId; + gIMPMaleValues[cnt3].bSex = gIMPFaceValues[cnt].bSex; + gIMPMaleValues[cnt3].iCurrentSkin = gIMPFaceValues[cnt].iCurrentSkin; + gIMPMaleValues[cnt3].iCurrentShirt = gIMPFaceValues[cnt].iCurrentShirt; + gIMPMaleValues[cnt3].iCurrentHair = gIMPFaceValues[cnt].iCurrentHair; + gIMPMaleValues[cnt3].iCurrentPants = gIMPFaceValues[cnt].iCurrentPants; + gIMPMaleValues[cnt3].bBigBody = gIMPFaceValues[cnt].bBigBody; + cnt3++; + } + } + +} diff --git a/Laptop/aim.cpp b/Laptop/aim.cpp index 37754e33..fafcbcc3 100644 --- a/Laptop/aim.cpp +++ b/Laptop/aim.cpp @@ -14,11 +14,18 @@ #include "Text.h" #include "LaptopSave.h" #include "Multi Language Graphic Utils.h" + #include "GameSettings.h" #endif +#include "LocalizedStrings.h" +#include "Soldier Profile.h" +UINT8 MAX_NUMBER_MERCS = 0; -UINT8 AimMercArray[ MAX_NUMBER_MERCS ]; +UINT8 AimMercArray[ NUM_PROFILES ]; //MAX_NUMBER_MERCS ]; + +AIM_AVAILABLE_TEMP gAimAvailabilityTemp[ NUM_PROFILES ]; +AIM_AVAILABLE gAimAvailability[ NUM_PROFILES ]; UINT8 gCurrentAimPage[ NUM_AIM_SCREENS ] = { @@ -470,14 +477,27 @@ BOOLEAN InitAimDefaults() CHECKF(AddVideoObject(&VObjectDesc, &guiRustBackGround)); // load the Aim Symbol graphic and add it - VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; - GetMLGFilename( VObjectDesc.ImageFile, MLG_AIMSYMBOL ); - CHECKF(AddVideoObject(&VObjectDesc, &guiAimSymbol)); + if(gGameExternalOptions.gfUseNewStartingGearInterface) + { + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + GetMLGFilename( VObjectDesc.ImageFile, MLG_AIMSYMBOL_SMALL ); + CHECKF(AddVideoObject(&VObjectDesc, &guiAimSymbol)); + //Mouse region for the Links + MSYS_DefineRegion( &gSelectedAimLogo, AIM_SYMBOL_SMALL_X, AIM_SYMBOL_SMALL_Y, AIM_SYMBOL_SMALL_X+AIM_SYMBOL_SMALL_WIDTH, AIM_SYMBOL_SMALL_Y+AIM_SYMBOL_SMALL_HEIGHT, MSYS_PRIORITY_HIGH, + CURSOR_WWW, MSYS_NO_CALLBACK, SelectAimLogoRegionCallBack); + MSYS_AddRegion(&gSelectedAimLogo); + } + else + { + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + GetMLGFilename( VObjectDesc.ImageFile, MLG_AIMSYMBOL ); + CHECKF(AddVideoObject(&VObjectDesc, &guiAimSymbol)); + //Mouse region for the Links + MSYS_DefineRegion( &gSelectedAimLogo, AIM_SYMBOL_X, AIM_SYMBOL_Y, AIM_SYMBOL_X+AIM_SYMBOL_WIDTH, AIM_SYMBOL_Y+AIM_SYMBOL_HEIGHT, MSYS_PRIORITY_HIGH, + CURSOR_WWW, MSYS_NO_CALLBACK, SelectAimLogoRegionCallBack); + MSYS_AddRegion(&gSelectedAimLogo); + } - //Mouse region for the Links - MSYS_DefineRegion( &gSelectedAimLogo, AIM_SYMBOL_X, AIM_SYMBOL_Y, AIM_SYMBOL_X+AIM_SYMBOL_WIDTH, AIM_SYMBOL_Y+AIM_SYMBOL_HEIGHT, MSYS_PRIORITY_HIGH, - CURSOR_WWW, MSYS_NO_CALLBACK, SelectAimLogoRegionCallBack); - MSYS_AddRegion(&gSelectedAimLogo); return(TRUE); @@ -514,8 +534,16 @@ BOOLEAN DrawAimDefaults() } // Aim Symbol - GetVideoObject(&hAimSymbolHandle, guiAimSymbol); - BltVideoObject(FRAME_BUFFER, hAimSymbolHandle, 0,AIM_SYMBOL_X, AIM_SYMBOL_Y, VO_BLT_SRCTRANSPARENCY,NULL); + if(gGameExternalOptions.gfUseNewStartingGearInterface) + { + GetVideoObject(&hAimSymbolHandle, guiAimSymbol); + BltVideoObject(FRAME_BUFFER, hAimSymbolHandle, 0,AIM_SYMBOL_SMALL_X, AIM_SYMBOL_SMALL_Y, VO_BLT_SRCTRANSPARENCY,NULL); + } + else + { + GetVideoObject(&hAimSymbolHandle, guiAimSymbol); + BltVideoObject(FRAME_BUFFER, hAimSymbolHandle, 0,AIM_SYMBOL_X, AIM_SYMBOL_Y, VO_BLT_SRCTRANSPARENCY,NULL); + } return(TRUE); } @@ -541,8 +569,14 @@ void SelectAimLogoRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) BOOLEAN DisplayAimSlogan() { CHAR16 sSlogan[400]; - - LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, 0, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, 0, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", 0, sSlogan, 400); + } //Display Aim Text under the logo DisplayWrappedString(AIM_LOGO_TEXT_X, AIM_LOGO_TEXT_Y, AIM_LOGO_TEXT_WIDTH, 2, AIM_LOGO_FONT, AIM_FONT_MCOLOR_WHITE, sSlogan, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); @@ -550,27 +584,37 @@ BOOLEAN DisplayAimSlogan() } - BOOLEAN DisplayAimCopyright() { CHAR16 sSlogan[400]; - UINT32 uiStartLoc=0; //Load and Display the copyright notice + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc=0; + uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_COPYRIGHT_1; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, uiStartLoc, AIM_HISTORY_LINE_SIZE); + DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); - uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_COPYRIGHT_1; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, uiStartLoc, AIM_HISTORY_LINE_SIZE); - DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_COPYRIGHT_2; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, uiStartLoc, AIM_HISTORY_LINE_SIZE); + DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y + AIM_COPYRIGHT_GAP, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); - uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_COPYRIGHT_2; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, uiStartLoc, AIM_HISTORY_LINE_SIZE); - DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y + AIM_COPYRIGHT_GAP, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); - - uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_COPYRIGHT_3; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, uiStartLoc, AIM_HISTORY_LINE_SIZE); - DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y + AIM_COPYRIGHT_GAP*2, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_COPYRIGHT_3; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sSlogan, uiStartLoc, AIM_HISTORY_LINE_SIZE); + DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y + AIM_COPYRIGHT_GAP*2, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", AIM_COPYRIGHT_1, sSlogan, 400); + DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + Loc::GetString(Loc::AIM_HISTORY, L"Line", AIM_COPYRIGHT_2, sSlogan, 400); + DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y + AIM_COPYRIGHT_GAP, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + Loc::GetString(Loc::AIM_HISTORY, L"Line", AIM_COPYRIGHT_3, sSlogan, 400); + DrawTextToScreen(sSlogan, AIM_COPYRIGHT_X, AIM_COPYRIGHT_Y + AIM_COPYRIGHT_GAP*2, AIM_COPYRIGHT_WIDTH, AIM_COPYRIGHT_FONT, FONT_MCOLOR_DKWHITE, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); + } return(TRUE); } @@ -847,25 +891,30 @@ BOOLEAN DisplayFlowerAd( BOOLEAN fInit, BOOLEAN fRedraw ) BOOLEAN DrawWarningBox( BOOLEAN fInit, BOOLEAN fRedraw ) { - static UINT32 uiLastTime; - static UINT8 ubSubImage=0; - UINT32 uiCurTime = GetJA2Clock(); + static UINT32 uiLastTime; + static UINT8 ubSubImage = 0; + UINT32 uiCurTime = GetJA2Clock(); if( fInit || fRedraw) { - CHAR16 sText[400]; - UINT32 uiStartLoc=0; + CHAR16 sText[400]; //UINT16 usLocY = AIM_WARNING_TEXT_Y + (GetFontHeight(AIM_WARNING_FONT) + 2) * 2; - HVOBJECT hWarningHandle; + HVOBJECT hWarningHandle; //Warning GetVideoObject(&hWarningHandle, guiWarning); BltVideoObject(FRAME_BUFFER, hWarningHandle, 0,WARNING_X, WARNING_Y, VO_BLT_SRCTRANSPARENCY,NULL); - - uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_WARNING_1; - LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + if(!g_bUseXML_Strings) + { + UINT32 uiStartLoc = AIM_HISTORY_LINE_SIZE * AIM_WARNING_1; + LoadEncryptedDataFromFile(AIMHISTORYFILE, sText, uiStartLoc, AIM_HISTORY_LINE_SIZE); + } + else + { + Loc::GetString(Loc::AIM_HISTORY, L"Line", AIM_WARNING_1, sText, 400); + } //Display Aim Warning Text DisplayWrappedString(AIM_WARNING_TEXT_X, AIM_WARNING_TEXT_Y, AIM_WARNING_TEXT_WIDTH, 2, AIM_WARNING_FONT, FONT_RED, sText, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED); diff --git a/Laptop/aim.h b/Laptop/aim.h index 7995a778..15d933aa 100644 --- a/Laptop/aim.h +++ b/Laptop/aim.h @@ -2,7 +2,7 @@ #define __AIM_H #include "Cursors.h" - +#include "Soldier Profile.h" // // AIM defines @@ -12,8 +12,32 @@ #define AIMHISTORYFILE "BINARYDATA\\AimHist.edt" #define AIM_HISTORY_LINE_SIZE 400 * 2 -#define MAX_NUMBER_MERCS 40 -extern UINT8 AimMercArray[ MAX_NUMBER_MERCS ]; +//#define MAX_NUMBER_MERCS 40 + +extern UINT8 MAX_NUMBER_MERCS; + +extern UINT8 AimMercArray[ NUM_PROFILES ];//MAX_NUMBER_MERCS ]; + +typedef struct +{ + UINT8 ubAimArrayID; + UINT8 uiIndex; + UINT8 ProfilId; + UINT8 AimBio; + +} AIM_AVAILABLE; + +typedef struct +{ + UINT8 ubAimArrayID; + UINT8 uiIndex; + UINT8 ProfilId; + UINT8 AimBio; + +} AIM_AVAILABLE_TEMP; + +extern AIM_AVAILABLE_TEMP gAimAvailabilityTemp[ NUM_PROFILES ]; +extern AIM_AVAILABLE gAimAvailability[ NUM_PROFILES ]; #define NUM_AIM_SCREENS 6 @@ -34,6 +58,13 @@ extern UINT8 AimMercArray[ MAX_NUMBER_MERCS ]; #define AIM_SYMBOL_WIDTH 203 #define AIM_SYMBOL_HEIGHT 51 +//tais: small logo for nsgi +#define AIM_SYMBOL_SMALL_X IMAGE_OFFSET_X + 3 +#define AIM_SYMBOL_SMALL_Y IMAGE_OFFSET_Y + 3 +#define AIM_SYMBOL_SMALL_WIDTH 102 +#define AIM_SYMBOL_SMALL_HEIGHT 26 + + // RustBackGround #define RUSTBACKGROUND_SIZE_X 125 #define RUSTBACKGROUND_SIZE_Y 100 diff --git a/Laptop/email.cpp b/Laptop/email.cpp index 392c0273..f62f968b 100644 --- a/Laptop/email.cpp +++ b/Laptop/email.cpp @@ -22,6 +22,8 @@ #include "LaptopSave.h" #include "finances.h" #include "PostalService.h" + #include "faces.h" + #include "GameSettings.h" #include #endif using namespace std; @@ -693,6 +695,26 @@ void AddEmailWithSpecialData(INT32 iMessageOffset, INT32 iMessageLength, UINT8 u return; } +void AddEmailWFMercLevelUp(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate, INT32 iCurrentIMPPosition) +{ + CHAR16 pSubject[320]; + + UINT8 subjectLine = (170 - iMessageLength) * 2; + wcscpy( pSubject, New113AIMMercMailTexts[subjectLine] ); + + AddEmailMessage(iMessageOffset,iMessageLength, pSubject, iDate, ubSender, FALSE, 0, 0, iCurrentIMPPosition ); + + // if we are in fact int he laptop, redraw icons, might be change in mail status + + if( fCurrentlyInLaptop == TRUE ) + { + // redraw icons, might be new mail + DrawLapTopIcons(); + } + + return; +} + void AddEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate, INT32 iCurrentIMPPosition) { CHAR16 pSubject[320]; @@ -700,7 +722,6 @@ void AddEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 //MessagePtr pMessage; //CHAR16 pMessageString[320]; - // WANNE: Short work in both ways LoadEncryptedDataFromFile("BINARYDATA\\Email.edt", pSubject, 640*(iMessageOffset), 640); @@ -711,8 +732,8 @@ void AddEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 if( fCurrentlyInLaptop == TRUE ) { - // redraw icons, might be new mail - DrawLapTopIcons(); + // redraw icons, might be new mail + DrawLapTopIcons(); } return; @@ -784,10 +805,23 @@ void AddEmailMessage(INT32 iMessageOffset, INT32 iMessageLength,STR16 pSubject, //} //pTempEmail->pText[iCounter]=NULL; + /* + // WANNE: Not needed anymore, bug is fixed!! + // WANNE: Fix the memory heap problem -> CTD (fix by BirdFlu) + // The text for the wildfire merc is too long (> 128 characters)!! + // copy subject + int _len = wcslen(pSubject); + pTempEmail->pSubject = (STR16) MemAlloc( (_len + 1) * sizeof(CHAR16) ); + memset( pTempEmail->pSubject, 0, sizeof( CHAR16 ) * (_len + 1) ); + wcsncpy(pTempEmail->pSubject,pSubject,_len); + pTempEmail->pSubject[_len] = 0; + */ + // copy subject pTempEmail->pSubject = (STR16) MemAlloc( 128 * sizeof(CHAR16) ); memset( pTempEmail->pSubject, 0, sizeof( CHAR16 ) * 128 ); wcscpy(pTempEmail->pSubject,pSubject); + // copy offset and length of the actual message in email.edt pTempEmail->usOffset =(UINT16)iMessageOffset; @@ -3414,10 +3448,10 @@ void HandleIMPCharProfileResultsMessage( void) } // personality itself - switch( gMercProfiles[ iCurrentIMPSlot ].bPersonalityTrait) + switch( gMercProfiles[ iCurrentIMPSlot ].bDisability) { // normal as can be - case( NO_PERSONALITYTRAIT ): + case( NO_DISABILITY ): iOffSet = IMP_PERSONALITY_NORMAL; break; case( HEAT_INTOLERANT ): @@ -3456,7 +3490,7 @@ void HandleIMPCharProfileResultsMessage( void) AddEmailRecordToList( pString ); // extra paragraph for bugs - if( gMercProfiles[ iCurrentIMPSlot ].bPersonalityTrait == FEAR_OF_INSECTS ) + if( gMercProfiles[ iCurrentIMPSlot ].bDisability == FEAR_OF_INSECTS ) { // persoanlity paragraph LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( iOffSet + IMP_PERSONALITY_LENGTH + 1 ), MAIL_STRING_SIZE ); @@ -3830,163 +3864,235 @@ void HandleIMPCharProfileResultsMessage( void) iCounter++; } - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == KNIFING )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == KNIFING ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_KNIFE ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - // lockpick - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == LOCKPICKING)||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == LOCKPICKING) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_LOCK ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - // hand to hand - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == HANDTOHAND )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == HANDTOHAND ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_HAND ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - // electronics - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == ELECTRONICS )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == ELECTRONICS ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_ELEC ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == NIGHTOPS )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == NIGHTOPS ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_NIGHT ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == THROWING)||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == THROWING) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_THROW ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == TEACHING )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == TEACHING ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_TEACH ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == HEAVY_WEAPS )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == HEAVY_WEAPS ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_HEAVY ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == AUTO_WEAPS )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == AUTO_WEAPS ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_AUTO ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == STEALTHY )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == STEALTHY ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_STEALTH ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == AMBIDEXT)||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == AMBIDEXT) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_AMBI ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == THIEF )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == THIEF ) ) - { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_THIEF ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); - } - - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == MARTIALARTS )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == MARTIALARTS ) ) + /////////////////////////////////////////////////////////////////////////////// + // SANDRO - switch for old/new traits + if ( gGameOptions.fNewTraitSystem ) { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_MARTIAL ), MAIL_STRING_SIZE ); - - // add to list - AddEmailRecordToList( pString ); + // Auto Weapons + if ( ProfileHasSkillTrait( iCurrentIMPSlot, AUTO_WEAPONS_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_AUTO ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Heavy Weapons + if ( ProfileHasSkillTrait( iCurrentIMPSlot, HEAVY_WEAPONS_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_HEAVY ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Sniper + if ( ProfileHasSkillTrait( iCurrentIMPSlot, SNIPER_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[0]); + AddEmailRecordToList( pString ); + } + // Ranger + if ( ProfileHasSkillTrait( iCurrentIMPSlot, RANGER_NT ) > 0 ) + { + if ( gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + gCamoFace[iCurrentIMPSlot].gCamoface = TRUE; + gCamoFace[iCurrentIMPSlot].gUrbanCamoface = FALSE; + gCamoFace[iCurrentIMPSlot].gDesertCamoface = FALSE; + gCamoFace[iCurrentIMPSlot].gSnowCamoface = FALSE; + } + wcscpy(pString, MissingIMPSkillsDescriptions[2]); + AddEmailRecordToList( pString ); + } + // Gunslinger + if ( ProfileHasSkillTrait( iCurrentIMPSlot, GUNSLINGER_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[3]); + AddEmailRecordToList( pString ); + } + // Martial Artist + if ( ProfileHasSkillTrait( iCurrentIMPSlot, MARTIAL_ARTS_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_MARTIAL ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Squadleader + if ( ProfileHasSkillTrait( iCurrentIMPSlot, SQUADLEADER_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[4]); + AddEmailRecordToList( pString ); + } + // Technician + if ( ProfileHasSkillTrait( iCurrentIMPSlot, TECHNICIAN_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[5]); + AddEmailRecordToList( pString ); + } + // Doctor + if ( ProfileHasSkillTrait( iCurrentIMPSlot, DOCTOR_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[6]); + AddEmailRecordToList( pString ); + } + // Ambidextrous + if ( ProfileHasSkillTrait( iCurrentIMPSlot, AMBIDEXTROUS_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_AMBI ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Melee + if ( ProfileHasSkillTrait( iCurrentIMPSlot, MELEE_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_KNIFE ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Throwing + if ( ProfileHasSkillTrait( iCurrentIMPSlot, THROWING_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_THROW ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Night Ops + if ( ProfileHasSkillTrait( iCurrentIMPSlot, NIGHT_OPS_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_NIGHT ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Stealthy + if ( ProfileHasSkillTrait( iCurrentIMPSlot, STEALTHY_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_STEALTH ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Athletics + if ( ProfileHasSkillTrait( iCurrentIMPSlot, ATHLETICS_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[7]); + AddEmailRecordToList( pString ); + } + // Bodybuilding + if ( ProfileHasSkillTrait( iCurrentIMPSlot, BODYBUILDING_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[8]); + AddEmailRecordToList( pString ); + } + // Demolitions + if ( ProfileHasSkillTrait( iCurrentIMPSlot, DEMOLITIONS_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[9]); + AddEmailRecordToList( pString ); + } + // Teaching + if ( ProfileHasSkillTrait( iCurrentIMPSlot, TEACHING_NT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_TEACH ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Scouting + if ( ProfileHasSkillTrait( iCurrentIMPSlot, SCOUTING_NT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[10]); + AddEmailRecordToList( pString ); + } + } + else + { + // Lockpick + if ( ProfileHasSkillTrait( iCurrentIMPSlot, LOCKPICKING_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_LOCK ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Hand to Hand + if ( ProfileHasSkillTrait( iCurrentIMPSlot, HANDTOHAND_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_HAND ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Electronics + if ( ProfileHasSkillTrait( iCurrentIMPSlot, ELECTRONICS_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_ELEC ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Night Ops + if ( ProfileHasSkillTrait( iCurrentIMPSlot, NIGHTOPS_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_NIGHT ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Throwing + if ( ProfileHasSkillTrait( iCurrentIMPSlot, THROWING_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_THROW ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Teaching + if ( ProfileHasSkillTrait( iCurrentIMPSlot, TEACHING_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_TEACH ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Heavy Weapons + if ( ProfileHasSkillTrait( iCurrentIMPSlot, HEAVY_WEAPS_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_HEAVY ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Auto Weapons + if ( ProfileHasSkillTrait( iCurrentIMPSlot, AUTO_WEAPS_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_AUTO ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Stealthy + if ( ProfileHasSkillTrait( iCurrentIMPSlot, STEALTHY_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_STEALTH ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Ambidextrous + if ( ProfileHasSkillTrait( iCurrentIMPSlot, AMBIDEXT_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_AMBI ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Thief + /*if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == THIEF_OT )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == THIEF_OT ) ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_THIEF ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + }*/ + // Martial Arts + if ( ProfileHasSkillTrait( iCurrentIMPSlot, MARTIALARTS_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_MARTIAL ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Knifing + if ( ProfileHasSkillTrait( iCurrentIMPSlot, KNIFING_OT ) > 0 ) + { + LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_KNIFE ), MAIL_STRING_SIZE ); + AddEmailRecordToList( pString ); + } + // Sniper + if ( ProfileHasSkillTrait( iCurrentIMPSlot, PROF_SNIPER_OT ) > 0 ) + { + wcscpy(pString, MissingIMPSkillsDescriptions[0]); + // add to list + AddEmailRecordToList( pString ); + } + // Camouflage + if ( ProfileHasSkillTrait( iCurrentIMPSlot, CAMOUFLAGED_OT ) > 0 ) + { + if ( gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + gCamoFace[iCurrentIMPSlot].gCamoface = TRUE; + gCamoFace[iCurrentIMPSlot].gUrbanCamoface = FALSE; + gCamoFace[iCurrentIMPSlot].gDesertCamoface = FALSE; + gCamoFace[iCurrentIMPSlot].gSnowCamoface = FALSE; + } + wcscpy(pString, MissingIMPSkillsDescriptions[1]); + AddEmailRecordToList( pString ); + } } - // rooftop - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == PROF_SNIPER )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == PROF_SNIPER ) ) - { - // WANNE: No entry in the Impass.edt for rooftop, so add any static text here - // read one record from email file - //LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_ONROOF ), MAIL_STRING_SIZE ); - - wcscpy(pString, MissingIMPSkillsDescriptions[0]); - - //#ifdef GERMAN - // wcscpy(pString, L"Dach-Treffer Bonus: "); - //#else - //wcscpy(pString, L"Sniper: "); - //#endif - - // add to list - AddEmailRecordToList( pString ); - } - - // camouflage - if( ( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait == CAMOUFLAGED )||( gMercProfiles[ iCurrentIMPSlot ].bSkillTrait2 == CAMOUFLAGED ) ) - { - // WANNE: No entry in the Impass.edt for camouflage, so add any static text here - // read one record from email file - //LoadEncryptedDataFromFile( "BINARYDATA\\Impass.edt", pString, MAIL_STRING_SIZE * ( IMP_SKILLS_SPECIAL_CAMOUFLAGED ), MAIL_STRING_SIZE ); - - wcscpy(pString, MissingIMPSkillsDescriptions[1]); - - /*#ifdef GERMAN - wcscpy(pString, L"Getarnt: "); - #else - wcscpy(pString, L"Camouflage: "); - #endif*/ - - // add to list - AddEmailRecordToList( pString ); - } + /////////////////////////////////////////////////////////////////////////////// // now the physical // imperial physical @@ -4770,6 +4876,7 @@ void ShutDownEmailList() ClearPages(); } +// Pre Process the mail, when clicking on a mail in the mail list void PreProcessEmail( EmailPtr pMail ) { RecordPtr pTempRecord, pCurrentRecord, pLastRecord , pTempList; @@ -4791,21 +4898,31 @@ void PreProcessEmail( EmailPtr pMail ) // WANNE: Get the text and replace name! int iNew113MERCMerc = 0; + int iNew113AIMMerc = 0; + if (pMail->usLength == MERC_UP_LEVEL_GASTON || pMail->usLength == MERC_UP_LEVEL_STOGIE || pMail->usLength == MERC_UP_LEVEL_TEX || pMail->usLength == MERC_UP_LEVEL_BIGGENS) { iNew113MERCMerc = pMail->usLength; pMail->usLength = 2; } + else if (pMail->usLength >= 170 && pMail->usLength <= 177) + { + iNew113AIMMerc = pMail->usLength; + pMail->usLength = 2; + } // list doesn't exist, reload if( !pTempRecord ) { - while(pMail->usLength > iCounter) + while(pMail->usLength > iCounter) { - // read one record from email file - LoadEncryptedDataFromFile( "BINARYDATA\\Email.edt", pString, MAIL_STRING_SIZE * ( iOffSet + iCounter ), MAIL_STRING_SIZE ); + // read one record from email file + LoadEncryptedDataFromFile( "BINARYDATA\\Email.edt", pString, MAIL_STRING_SIZE * ( iOffSet + iCounter ), MAIL_STRING_SIZE ); + // ---------------- + // New MERC Merc + // ---------------- // WANNE: We have a new 1.13 MERC merc (Text, Gaston, Stogie or Biggens) if (iNew113MERCMerc != 0) { @@ -4815,8 +4932,7 @@ void PreProcessEmail( EmailPtr pMail ) wcscpy(pString, L"\0"); if (iNew113MERCMerc == MERC_UP_LEVEL_GASTON) { - wcscpy( pString, New113MERCMercMailTexts[0] ); - + wcscpy( pString, New113MERCMercMailTexts[0] ); } else if (iNew113MERCMerc == MERC_UP_LEVEL_STOGIE) { @@ -4832,21 +4948,73 @@ void PreProcessEmail( EmailPtr pMail ) } } } + + // ---------------- + // New AIM Merc + // ---------------- + // WANNE: We have a new 1.13 MERC merc (Text, Gaston, Stogie or Biggens) + if (iNew113AIMMerc != 0) + { + wcscpy(pString, L"\0"); + + // Only output the mail text, not the subject, cause we already have the subject as text + if (iCounter == 1) + { + if (iNew113AIMMerc == 170) + { + wcscpy( pString, New113AIMMercMailTexts[1] ); + } + else if (iNew113MERCMerc == 171) + { + wcscpy( pString, New113AIMMercMailTexts[3] ); + } + else if (iNew113MERCMerc == 172) + { + wcscpy( pString, New113AIMMercMailTexts[5] ); + } + else if (iNew113MERCMerc == 173) + { + wcscpy( pString, New113AIMMercMailTexts[7] ); + } + else if (iNew113MERCMerc == 174) + { + wcscpy( pString, New113AIMMercMailTexts[9] ); + } + else if (iNew113MERCMerc == 175) + { + wcscpy( pString, New113AIMMercMailTexts[11] ); + } + else if (iNew113MERCMerc == 176) + { + wcscpy( pString, New113AIMMercMailTexts[13] ); + } + else if (iNew113MERCMerc == 177) + { + wcscpy( pString, New113AIMMercMailTexts[15] ); + } + } + } // add to list AddEmailRecordToList( pString ); - // increment email record counter - iCounter++; - } + // increment email record counter + iCounter++; + } - // WANNE: Set the value back - if (iNew113MERCMerc != 0) - { - pMail->usLength = iNew113MERCMerc; - } + // WANNE: Set the value back + if (iNew113MERCMerc != 0) + { + pMail->usLength = iNew113MERCMerc; + } - giPrevMessageId = giMessageId; + // WANNE: Set the value back + if (iNew113AIMMerc != 0) + { + pMail->usLength = iNew113AIMMerc; + } + + giPrevMessageId = giMessageId; } diff --git a/Laptop/email.h b/Laptop/email.h index d9b072ac..c8112929 100644 --- a/Laptop/email.h +++ b/Laptop/email.h @@ -144,12 +144,12 @@ //#define MERC_UP_LEVEL_BIGGENS (MERC_UP_LEVEL_TEX + MERC_UP_LEVEL_TEX_LENGTH) //#define MERC_UP_LEVEL_BIGGENS_LENGTH 2 + #define MERC_UP_LEVEL_GASTON 165 #define MERC_UP_LEVEL_STOGIE 166 #define MERC_UP_LEVEL_TEX 167 #define MERC_UP_LEVEL_BIGGENS 168 - struct message{ STR16 pString; struct message *Next; @@ -299,6 +299,10 @@ void RemoveEmailMessage(INT32 iId); EmailPtr GetEmailMessage(INT32 iId); void LookForUnread(); void AddEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate, INT32 iCurrentIMPPosition); + +// WANNE: For the new WF merc +void AddEmailWFMercLevelUp(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate, INT32 iCurrentIMPPosition); + void AddPreReadEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate); BOOLEAN DisplayNewMailBox(); void CreateDestroyNewMailButton(); diff --git a/Laptop/finances.cpp b/Laptop/finances.cpp index 8aded9e3..1d3646cb 100644 --- a/Laptop/finances.cpp +++ b/Laptop/finances.cpp @@ -409,7 +409,7 @@ INT32 GetProjectedTotalDailyIncome( void ) // HEADROCK HAM 3.6: Facilities can make you money, and this is figured into your daily income. INT32 iRate = 0; - iRate = PredictIncomeFromPlayerMines() + (15 * GetTotalFacilityHourlyCosts( TRUE )); // 15 hours is the average time a merc can work per day + iRate = PredictIncomeFromPlayerMines(TRUE) + (15 * GetTotalFacilityHourlyCosts( TRUE )); // 15 hours is the average time a merc can work per day return( iRate ); } @@ -1167,21 +1167,23 @@ void OpenAndReadFinancesFile( void ) // file exists, read in data, continue until file end while( FileGetSize( hFileHandle ) > uiByteCount) { - // read in other data - FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; + // add transaction - ProcessAndEnterAFinacialRecord(ubCode, uiDate, iAmount, ubSecondCode, iBalanceToDate); + ProcessAndEnterAFinacialRecord(ubCode, uiDate, iAmount, ubSecondCode, iBalanceToDate); // increment byte counter - uiByteCount += sizeof( INT32 ) + sizeof( UINT32 ) + sizeof( UINT8 )+ sizeof(UINT8) + sizeof( INT32 ); + uiByteCount += sizeof( INT32 ) + sizeof( UINT32 ) + sizeof( UINT8 )+ sizeof(UINT8) + sizeof( INT32 ); } // close file @@ -1906,19 +1908,23 @@ BOOLEAN LoadInRecords( UINT32 uiPage ) { // read in data - FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + // WANNE: Do not add the fix + 1 day here, because otherwise we have a day + 1 offset + // WANNE: Fix uiDate (add 1 day!)! + //uiDate += 1500; + // add transaction - ProcessAndEnterAFinacialRecord(ubCode, uiDate, iAmount, ubSecondCode, iBalanceToDate); + ProcessAndEnterAFinacialRecord(ubCode, uiDate, iAmount, ubSecondCode, iBalanceToDate); // increment byte counter - uiByteCount += sizeof( INT32 ) + sizeof( UINT32 ) + sizeof( UINT8 )+ sizeof(UINT8) + sizeof( INT32 ); + uiByteCount += sizeof( INT32 ) + sizeof( UINT32 ) + sizeof( UINT8 )+ sizeof(UINT8) + sizeof( INT32 ); // we've overextended our welcome, and bypassed end of file, get out if( uiByteCount >= FileGetSize( hFileHandle ) ) @@ -2127,8 +2133,11 @@ INT32 GetPreviousDaysBalance( void ) FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; // check to see if we are far enough if( ( uiDate / ( 24 * 60 ) ) == ( iDateInMinutes / ( 24 * 60 ) ) - 2 ) @@ -2221,10 +2230,14 @@ INT32 GetTodaysBalance( void ) FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; + // check to see if we are far enough if( ( uiDate / ( 24 * 60 ) ) == ( iDateInMinutes / ( 24 * 60 ) ) - 1 ) { @@ -2301,15 +2314,19 @@ INT32 GetPreviousDaysIncome( void ) // incrment byte count iByteCount += RECORD_SIZE; - FileGetPos( hFileHandle ); + FileGetPos( hFileHandle ); FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; + // check to see if we are far enough if( ( uiDate / ( 24 * 60 ) )== ( iDateInMinutes / ( 24 * 60 ) ) - 2 ) { @@ -2318,7 +2335,7 @@ INT32 GetPreviousDaysIncome( void ) // there are no entries for the previous day if( ( uiDate / ( 24 * 60 ) ) < ( iDateInMinutes / ( 24 * 60 ) ) - 2 ) - { + { fGoneTooFar = TRUE; } @@ -2402,10 +2419,14 @@ INT32 GetTodaysDaysIncome( void ) FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; + // check to see if we are far enough if( ( uiDate / ( 24 * 60 ) ) == ( iDateInMinutes / ( 24 * 60 ) ) - 1 ) { @@ -2527,16 +2548,20 @@ INT32 GetTodaysOtherDeposits( void ) { FileSeek( hFileHandle, RECORD_SIZE * iCounter , FILE_SEEK_FROM_END ); - // incrment byte count - iByteCount += RECORD_SIZE; + // incrment byte count + iByteCount += RECORD_SIZE; FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; + // check to see if we are far enough if( ( uiDate / ( 24 * 60 ) ) == ( iDateInMinutes / ( 24 * 60 ) ) - 1 ) { @@ -2629,10 +2654,14 @@ INT32 GetYesterdaysOtherDeposits( void ) FileRead( hFileHandle, &ubCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &ubSecondCode, sizeof(UINT8), (UINT32 *)&iBytesRead ); FileRead( hFileHandle, &uiDate, sizeof(UINT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); - FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iAmount, sizeof(INT32), (UINT32 *)&iBytesRead ); + FileRead( hFileHandle, &iBalanceToDate, sizeof(INT32), (UINT32 *)&iBytesRead ); AssertMsg( iBytesRead, "Failed To Read Data Entry"); + + // WANNE: Fix uiDate (add 1 day!)! + uiDate += 1500; + // check to see if we are far enough if( ( uiDate / ( 24 * 60 ) )== ( iDateInMinutes / ( 24 * 60 ) ) - 2 ) { diff --git a/Laptop/finances.h b/Laptop/finances.h index f3185a0c..3da88793 100644 --- a/Laptop/finances.h +++ b/Laptop/finances.h @@ -53,6 +53,7 @@ enum SOLD_ITEMS, FACILITY_OPERATIONS, // HEADROCK HAM 3.6: Facility costs (daily payment) MILITIA_UPKEEP, // HEADROCK HAM 3.6: Militia Upkeep Costs (daily payment) + TEXT_NUM_FINCANCES }; diff --git a/Laptop/history.h b/Laptop/history.h index 826bc04c..027e14cb 100644 --- a/Laptop/history.h +++ b/Laptop/history.h @@ -103,6 +103,7 @@ enum{ HISTORY_GAVE_CARMEN_HEAD, HISTORY_SLAY_MYSTERIOUSLY_LEFT, HISTORY_MERC_KILLED_CHARACTER, + TEXT_NUM_HISTORY }; typedef struct history HistoryUnit; diff --git a/Laptop/laptop.h b/Laptop/laptop.h index b0898a47..8d279b98 100644 --- a/Laptop/laptop.h +++ b/Laptop/laptop.h @@ -194,6 +194,7 @@ enum{ FLORIST_BOOKMARK, INSURANCE_BOOKMARK, CANCEL_STRING, + TEXT_NUM_LAPTOP_BOOKMARKS }; diff --git a/Laptop/mercs Account.cpp b/Laptop/mercs Account.cpp index dc3c22fb..84dc2da4 100644 --- a/Laptop/mercs Account.cpp +++ b/Laptop/mercs Account.cpp @@ -189,9 +189,14 @@ INT32 GetNumberOfHiredMercs() for (i = 0; i<=(NUMBER_OF_MERCS - 1); i++) { - if( i == MERC_LARRY_ROACHBURN ) + // WANNE: If we have drunken merc, then skip otherwise is will exist 2 times! + if (gConditionsForMercAvailability[ i ].Drunk) continue; + // WANNE.LARRY + /*if( i == MERC_LARRY_ROACHBURN ) + continue;*/ + usMercID = GetMercIDFromMERCArray( i ); // Is the merc hired? @@ -489,6 +494,7 @@ void DisplayHiredMercs() usMercIDEnd = usMercIDStart + MAX_NUMBER_MERCS_ON_PAGE; } + // WANNE.LARRY: I don't understand why this is needed??? I did not change anything on this yet. // At least second page // This approach is needed, because auf LARRY_ROACHBURN if (usMercIDStart > 0) @@ -503,10 +509,15 @@ void DisplayHiredMercs() if (usCurrentRow == usMercIDEnd - 1) break; - //if it larry Roach burn advance. ( cause larry is in twice, a sober larry and a stoned larry ) - if( i == MERC_LARRY_ROACHBURN ) + // WANNE: If we have drunken merc, then skip otherwise is will exist 2 times! + if (gConditionsForMercAvailability[ i ].Drunk) continue; + // WANNE.LARRY + //if it larry Roach burn advance. ( cause larry is in twice, a sober larry and a stoned larry ) + /*if( i == MERC_LARRY_ROACHBURN ) + continue;*/ + usMercID = GetMercIDFromMERCArray( i ); //is the merc on the team, or is owed money @@ -741,9 +752,14 @@ UINT32 CalculateHowMuchPlayerOwesSpeck() for(i=0; i<(NUMBER_OF_MERCS - 1); i++) { - //if it larry Roach burn advance. ( cause larry is in twice, a sober larry and a stoned larry ) - if( i == MERC_LARRY_ROACHBURN ) + // WANNE: If we have drunken merc, then skip otherwise is will exist 2 times! + if (gConditionsForMercAvailability[ i ].Drunk) continue; + + // WANNE.LARRY + //if it larry Roach burn advance. ( cause larry is in twice, a sober larry and a stoned larry ) + //if( i == MERC_LARRY_ROACHBURN ) + // continue; usMercID = GetMercIDFromMERCArray( i ); //if( IsMercOnTeam( (UINT8)usMercID ) ) diff --git a/Laptop/mercs Files.cpp b/Laptop/mercs Files.cpp index 3e70115a..7a92745f 100644 Binary files a/Laptop/mercs Files.cpp and b/Laptop/mercs Files.cpp differ diff --git a/Laptop/mercs.cpp b/Laptop/mercs.cpp index 1aaa37eb..fc481d3b 100644 --- a/Laptop/mercs.cpp +++ b/Laptop/mercs.cpp @@ -29,8 +29,9 @@ #include "connect.h" -UINT8 NUMBER_OF_MERCS; -UINT8 LAST_MERC_ID; +UINT8 NUMBER_OF_MERCS = 0; +UINT8 LAST_MERC_ID = -1; +UINT8 NUMBER_OF_BAD_MERCS = -1; #define MERC_TEXT_FONT FONT12ARIAL #define MERC_TEXT_COLOR FONT_MCOLOR_WHITE @@ -117,30 +118,9 @@ UINT8 LAST_MERC_ID; #define MERC__AMOUNT_OF_MONEY_FOR_BUBBA 6000 #define MERC__DAY_WHEN_BUBBA_CAN_BECOME_AVAILABLE 10 - -enum -{ - MERC_ARRIVES_BUBBA, - MERC_ARRIVES_LARRY, - MERC_ARRIVES_NUMB, - MERC_ARRIVES_TEX, - MERC_ARRIVES_BIGGENS, - MERC_ARRIVES_COUGAR, - MERC_ARRIVES_GASTON, - MERC_ARRIVES_STOGIE, - - NUM_MERC_ARRIVALS, -}; - -typedef struct -{ - UINT16 usMoneyPaid; - UINT16 usDay; - UINT8 ubMercArrayID; - -} CONTITION_FOR_MERC_AVAILABLE; - -CONTITION_FOR_MERC_AVAILABLE gConditionsForMercAvailability[ NUM_MERC_ARRIVALS ] = +CONTITION_FOR_MERC_AVAILABLE_TEMP gConditionsForMercAvailabilityTemp[ NUM_PROFILES ]; +CONTITION_FOR_MERC_AVAILABLE gConditionsForMercAvailability[ NUM_PROFILES ]; //NUM_MERC_ARRIVALS ]; //= +/* { 5000, 8, 6, //BUBBA 10000, 15, 7, //Larry @@ -152,7 +132,7 @@ CONTITION_FOR_MERC_AVAILABLE gConditionsForMercAvailability[ NUM_MERC_ARRIVALS ] 26000, 31, 14, //Stogie }; - +*/ enum { @@ -183,7 +163,7 @@ UINT32 guiMercBackGround; UINT32 guiMercVideoFaceBackground; UINT32 guiMercVideoPopupBackground; -UINT8 gubMercArray[ MAX_NUMBER_OF_MERCS ]; +UINT8 gubMercArray[ NUM_PROFILES ]; //MAX_NUMBER_OF_MERCS UINT8 gubCurMercIndex; INT32 iMercPopUpBox = -1; @@ -281,6 +261,8 @@ MOUSE_REGION gMercSiteSubTitleMouseRegion; void MercSiteSubTitleRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ); +BOOLEAN LoadNewMercsFromLoadGameFile( HWFILE hFile ); +BOOLEAN SaveNewMercsToSaveGameFile( HWFILE hFile ); //******************************* @@ -324,47 +306,57 @@ BOOLEAN CanMercBeAvailableYet( UINT8 ubMercToCheck ); UINT32 CalcMercDaysServed(); //ppp +BOOLEAN SaveNewMercsToSaveGameFile( HWFILE hFile ) +{ + UINT32 uiNumBytesWritten; + + FileWrite( hFile, &gConditionsForMercAvailability, sizeof( gConditionsForMercAvailability), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gConditionsForMercAvailability ) ) + { + return( FALSE ); + } + + return( TRUE ); +} + +BOOLEAN LoadNewMercsFromLoadGameFile( HWFILE hFile ) +{ + UINT32 uiNumBytesRead; + + FileRead( hFile, &gConditionsForMercAvailability, sizeof( gConditionsForMercAvailability ), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gConditionsForMercAvailability ) ) + { + return( FALSE ); + } + + return( TRUE ); +} void GameInitMercs() { -// for(i=0; i fortlaufende ID, und nicht die mercID +// -> bei aktuellen Merc passt es +// -> bei departed Merc wird die MercId anstatt der fortlaufenden ID bergeben!! void RenderPersonnelFace(INT32 iId, INT32 iSlot, BOOLEAN fDead, BOOLEAN fFired, BOOLEAN fOther ) { + // Get the profile id (from profileId or slotId) + INT32 profileId = iId; + if (profileId == -1) + { + profileId = MercPtrs[iSlot]->ubProfile; + } + char sTemp[100]; HVOBJECT hFaceHandle; VOBJECT_DESC VObjectDesc; // draw face to soldier iId in slot iSlot + // Currently active merc! // special case?..player generated merc - if (fCurrentTeamMode) { - if( ( 50 < MercPtrs[iId]->ubProfile )&&( 57 > MercPtrs[iId]->ubProfile ) ) + if (fCurrentTeamMode) + { + if( ( 50 < profileId )&&( 57 > profileId ) ) { - sprintf( sTemp, "%s%03d.sti", FACES_DIR, gMercProfiles[ MercPtrs[iId]->ubProfile ].ubFaceIndex ); + sprintf( sTemp, "%s%03d.sti", FACES_DIR, gMercProfiles[profileId].ubFaceIndex ); } else - { - if (gGameExternalOptions.fReadProfileDataFromXML) - { - // HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value. - sprintf(sTemp, "%s%02d.sti", FACES_DIR, gMercProfiles[Menptr[ iId ].ubProfile].ubFaceIndex); - } - else - { - sprintf(sTemp, "%s%02d.sti", FACES_DIR, Menptr[ iId ].ubProfile); - } + { + sprintf(sTemp, "%s%02d.sti", FACES_DIR, gMercProfiles[profileId].ubFaceIndex); } - if( MercPtrs[iId]->flags.uiStatusFlags & SOLDIER_VEHICLE ) { + // TODO: Check if needed! + if( MercPtrs[iSlot]->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { return; } - } else { + } + // departed mercs + else + { //if this is not a valid merc - if( !fDead && !fFired && !fOther ) { + if( !fDead && !fFired && !fOther ) + { return; } - if( ( 50 < iId )&&( 57 > iId ) ) + if( ( 50 < profileId )&&( 57 > profileId ) ) { - sprintf( sTemp, "%s%03d.sti", FACES_DIR, gMercProfiles[ iId ].ubFaceIndex ); + sprintf( sTemp, "%s%03d.sti", FACES_DIR, gMercProfiles[profileId].ubFaceIndex ); } else { - if (gGameExternalOptions.fReadProfileDataFromXML) - { - // HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value. - sprintf(sTemp, "%s%02d.sti", FACES_DIR, gMercProfiles[Menptr[ iId ].ubProfile].ubFaceIndex ); - } - else - { - sprintf(sTemp, "%s%02d.sti", FACES_DIR, iId ); - } + sprintf(sTemp, "%s%02d.sti", FACES_DIR, gMercProfiles[profileId].ubFaceIndex ); } } @@ -876,34 +870,45 @@ void RenderPersonnelFace(INT32 iId, INT32 iSlot, BOOLEAN fDead, BOOLEAN fFired, //Blt face to screen to GetVideoObject(&hFaceHandle, guiFACE); - if (fCurrentTeamMode) { - if( MercPtrs[iId]->stats.bLife <= 0 ) { + if (fCurrentTeamMode) + { + if( MercPtrs[iSlot]->stats.bLife <= 0 ) + { hFaceHandle->pShades[ 0 ] = Create16BPPPaletteShaded( hFaceHandle->pPaletteEntry, DEAD_MERC_COLOR_RED, DEAD_MERC_COLOR_GREEN, DEAD_MERC_COLOR_BLUE, TRUE ); //set the red pallete to the face SetObjectHandleShade( guiFACE, 0 ); } - } else { - if (fDead == TRUE) { + } + else + { + if (fDead == TRUE) + { hFaceHandle->pShades[ 0 ] = Create16BPPPaletteShaded( hFaceHandle->pPaletteEntry, DEAD_MERC_COLOR_RED, DEAD_MERC_COLOR_GREEN, DEAD_MERC_COLOR_BLUE, TRUE ); //set the red pallete to the face SetObjectHandleShade( guiFACE, 0 ); } } - BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,IMAGE_BOX_X+(iSlot*IMAGE_BOX_WIDTH), IMAGE_BOX_Y, VO_BLT_SRCTRANSPARENCY,NULL); + // TODO:Check + BltVideoObject(FRAME_BUFFER, hFaceHandle, 0,IMAGE_BOX_X, IMAGE_BOX_Y, VO_BLT_SRCTRANSPARENCY,NULL); //if the merc is dead, display it - if (!fCurrentTeamMode) { - INT32 iHeightOfText = DisplayWrappedString(IMAGE_BOX_X, (UINT16)(IMAGE_BOX_Y+IMAGE_FULL_NAME_OFFSET_Y), IMAGE_NAME_WIDTH, 1, PERS_FONT, PERS_FONT_COLOR, gMercProfiles[ iId ].zName, 0, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ); + if (!fCurrentTeamMode) + { + INT32 iHeightOfText = DisplayWrappedString(IMAGE_BOX_X, (UINT16)(IMAGE_BOX_Y+IMAGE_FULL_NAME_OFFSET_Y), IMAGE_NAME_WIDTH, 1, PERS_FONT, PERS_FONT_COLOR, gMercProfiles[profileId].zName, 0, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT ); //if the string will rap - if( ( iHeightOfText - 2 ) > GetFontHeight( PERS_FONT ) ) { + if( ( iHeightOfText - 2 ) > GetFontHeight( PERS_FONT ) ) + { //raise where we display it, and rap it - DisplayWrappedString(IMAGE_BOX_X, (UINT16)(IMAGE_BOX_Y+IMAGE_FULL_NAME_OFFSET_Y - GetFontHeight( PERS_FONT )), IMAGE_NAME_WIDTH, 1, PERS_FONT, PERS_FONT_COLOR, gMercProfiles[ iId ].zName, 0, FALSE, CENTER_JUSTIFIED); - } else { - DrawTextToScreen( gMercProfiles[ iId ].zName, IMAGE_BOX_X, (UINT16)(IMAGE_BOX_Y+IMAGE_FULL_NAME_OFFSET_Y), IMAGE_NAME_WIDTH, PERS_FONT, PERS_FONT_COLOR, 0, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString(IMAGE_BOX_X, (UINT16)(IMAGE_BOX_Y+IMAGE_FULL_NAME_OFFSET_Y - GetFontHeight( PERS_FONT )), IMAGE_NAME_WIDTH, 1, PERS_FONT, PERS_FONT_COLOR, gMercProfiles[profileId].zName, 0, FALSE, CENTER_JUSTIFIED); + } + else + { + DrawTextToScreen( gMercProfiles[profileId].zName, IMAGE_BOX_X, (UINT16)(IMAGE_BOX_Y+IMAGE_FULL_NAME_OFFSET_Y), IMAGE_NAME_WIDTH, PERS_FONT, PERS_FONT_COLOR, 0, FALSE, CENTER_JUSTIFIED ); } } + DeleteVideoObjectFromIndex(guiFACE); } @@ -1343,6 +1348,15 @@ void DisplayCharStats(INT32 iId, INT32 iSlot) SOLDIERTYPE *pSoldier = &Menptr[iId]; BOOLEAN fAmIaRobot = AM_A_ROBOT( pSoldier ); + // SANDRO - remove the regions + for( INT8 i = 0; i < 13; i++ ) + { + if( fAddedTraitRegion[i] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[i] ); + fAddedTraitRegion[i] = FALSE; + } + } if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { @@ -1618,57 +1632,65 @@ void DisplayCharStats(INT32 iId, INT32 iSlot) mprintf(sX,pPersonnelScreenPoints[iCounter].y,sString); break; - case 14: - // kills - mprintf((INT16)(pPersonnelScreenPoints[21].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[21].y,pPersonnelScreenStrings[PRSNL_TXT_KILLS]); - swprintf(sString, L"%d",gMercProfiles[Menptr[iId].ubProfile].usKills); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[21].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[21].y,sString); - break; + ///////////////////////////////////////////////////////////////////////// + // Added by SANDRO case 15: - // assists - mprintf((INT16)(pPersonnelScreenPoints[22].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[22].y,pPersonnelScreenStrings[PRSNL_TXT_ASSISTS]); - swprintf(sString, L"%d",gMercProfiles[Menptr[iId].ubProfile].usAssists); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[22].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[22].y,sString); - break; - case 16: - // shots/hits - mprintf((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[23].y,pPersonnelScreenStrings[PRSNL_TXT_HIT_PERCENTAGE]); - uiHits = ( UINT32 )gMercProfiles[Menptr[iId].ubProfile].usShotsHit; - uiHits *= 100; + // Character Trait + mprintf((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[23].y + 15),pPersonnelRecordsHelpTexts[43]); //L"Character:" + swprintf(sString, gzIMPCharacterTraitText[gMercProfiles[Menptr[iId].ubProfile].bCharacterTrait]); - // check we have shot at least once - if( gMercProfiles[Menptr[iId].ubProfile].usShotsFired > 0 ) + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[23].y + 15),sString); + + //GetVideoObject(&hHandle, guiQMark); + //BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[23].x + 148), ( pPersonnelScreenPoints[23].y + 5), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[5] ) { - uiHits /= ( UINT32 )gMercProfiles[Menptr[iId].ubProfile].usShotsFired; - } - else - { - // no, set hit % to 0 - uiHits = 0; + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[5] ); } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[5], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[23].y + 10), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[23].y + 17 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + //MSYS_DefineRegion( &gSkillTraitHelpTextRegion[3], (UINT16)( pPersonnelScreenPoints[23].x + 147 ), (UINT16)(pPersonnelScreenPoints[23].y + 4), + // (UINT16)( pPersonnelScreenPoints[23].x + 166 ), (UINT16)(pPersonnelScreenPoints[23].y + 15), MSYS_PRIORITY_HIGH, + // MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[5] ); + fAddedTraitRegion[5] = TRUE; + // Assign the text + AssignPersonnelCharacterTraitHelpText( gMercProfiles[Menptr[iId].ubProfile].bCharacterTrait ); + break; - swprintf(sString, L"%d %%%%",uiHits); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - sX += StringPixLength( L"%", PERS_FONT ); - mprintf(sX,pPersonnelScreenPoints[23].y,sString); - break; - case 17: - // battles - mprintf((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[24].y,pPersonnelScreenStrings[PRSNL_TXT_BATTLES]); - swprintf(sString, L"%d",gMercProfiles[Menptr[iId].ubProfile].usBattlesFought); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[24].y,sString); - break; case 18: - // wounds - mprintf((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[25].y,pPersonnelScreenStrings[PRSNL_TXT_TIMES_WOUNDED]); - swprintf(sString, L"%d",gMercProfiles[Menptr[iId].ubProfile].usTimesWounded); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[25].y,sString); + // Disability + mprintf((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[25].y + 10),pPersonnelRecordsHelpTexts[44]); //L"Disability:" + swprintf(sString, gzIMPDisabilityTraitText[gMercProfiles[Menptr[iId].ubProfile].bDisability]); + + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[25].y + 10),sString); + + //GetVideoObject(&hHandle, guiQMark); + //BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[25].x + 148), ( pPersonnelScreenPoints[25].y ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[6] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[6] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[6], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[25].y + 10 ), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[25].y + 17 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + //MSYS_DefineRegion( &gSkillTraitHelpTextRegion[6], (UINT16)( pPersonnelScreenPoints[25].x + 147 ), (UINT16)( pPersonnelScreenPoints[25].y - 1), + // (UINT16)( pPersonnelScreenPoints[25].x + 166 ), (UINT16)(pPersonnelScreenPoints[25].y + 10), MSYS_PRIORITY_HIGH, + // MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[6] ); + fAddedTraitRegion[6] = TRUE; + // Assign the text + AssignPersonnelDisabilityHelpText( gMercProfiles[Menptr[iId].ubProfile].bDisability ); break; + ///////////////////////////////////////////////////////////////////////// // The Mercs Skills case 19: @@ -1678,7 +1700,7 @@ void DisplayCharStats(INT32 iId, INT32 iSlot) INT8 bScreenLocIndex = 19; //if you change the '19', change it below in the if statement //Display the 'Skills' text - mprintf( (INT16)( pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[bScreenLocIndex].y,pPersonnelScreenStrings[ PRSNL_TXT_SKILLS ] ); + mprintf( (INT16)( pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[bScreenLocIndex].y),pPersonnelScreenStrings[ PRSNL_TXT_SKILLS ] ); //KM: April 16, 1999 //Added support for the German version, which has potential string overrun problems. For example, the text "Skills:" can @@ -1689,67 +1711,256 @@ void DisplayCharStats(INT32 iId, INT32 iSlot) if( !fAmIaRobot ) { - INT8 bSkill1 = gMercProfiles[ Menptr[iId].ubProfile ].bSkillTrait; - INT8 bSkill2 = gMercProfiles[ Menptr[iId].ubProfile ].bSkillTrait2; - - //if the 2 skills are the same, add the '(expert)' at the end - if( bSkill1 == bSkill2 && bSkill1 != NO_SKILLTRAIT ) + if (gGameOptions.fNewTraitSystem) // SANDRO - old/new traits check { - swprintf( sString, L"%s %s", gzMercSkillText[bSkill1], gzMercSkillText[NUM_SKILLTRAITS] ); + UINT8 ubTempSkillArray[30]; + INT8 bNumSkillTraits = 0; - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - - //KM: April 16, 1999 - //Perform the potential overrun check - if( sX <= iMinimumX ) + // lets rearrange our skills to a temp array + // we also get the number of lines (skills) to be displayed + for ( UINT8 ubCnt = 1; ubCnt < NUM_SKILLTRAITS_NT; ubCnt++ ) { - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[iCounter].x+(iSlot*TEXT_BOX_WIDTH) + TEXT_BOX_WIDTH-20 +TEXT_DELTA_OFFSET),0,30,0,sString, PERS_FONT, &sX, &sY); - sX = (INT16)max( sX, iMinimumX ); + if ( ProfileHasSkillTrait( Menptr[iId].ubProfile, ubCnt ) == 2 ) + { + ubTempSkillArray[bNumSkillTraits] = (ubCnt + 19); + bNumSkillTraits++; + } + else if ( ProfileHasSkillTrait( Menptr[iId].ubProfile, ubCnt ) == 1 ) + { + ubTempSkillArray[bNumSkillTraits] = ubCnt; + bNumSkillTraits++; + } } - mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); - } - else - { - //Display the first skill - if( bSkill1 != NO_SKILLTRAIT ) - { - swprintf( sString, L"%s", gzMercSkillText[bSkill1] ); - - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - - //KM: April 16, 1999 - //Perform the potential overrun check - sX = (INT16)max( sX, iMinimumX ); - - mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); - - bScreenLocIndex++; - } - - //Display the second skill - if( bSkill2 != NO_SKILLTRAIT ) - { - swprintf( sString, L"%s", gzMercSkillText[bSkill2] ); - - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - - //KM: April 16, 1999 - //Perform the potential overrun check - sX = (INT16)max( sX, iMinimumX ); - - mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); - - bScreenLocIndex++; - } - - //if no skill was displayed - if( bScreenLocIndex == 19 ) + if ( bNumSkillTraits == 0 ) { swprintf( sString, L"%s", pPersonnelScreenStrings[ PRSNL_TXT_NOSKILLS ] ); FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); + + // Add specific region for fast help window + if( fAddedTraitRegion[0] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[0] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[0], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y ), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[0] ); + fAddedTraitRegion[0] = TRUE; + // Assign the text + AssignPersonnelSkillTraitHelpText( 0, FALSE, iId, 0 ); + + } + else + { + CHAR16 sString2[500]; + swprintf( sString2, L"" ); + BOOLEAN fDisplayMoreTraits = FALSE; + + for ( UINT8 ubCnt = 0; ubCnt < bNumSkillTraits; ubCnt++ ) + { + if ( ubCnt >= 4 && bNumSkillTraits > 4 ) + { + fDisplayMoreTraits = TRUE; + swprintf( sString, L"%s\n", gzMercSkillTextNew[ ubTempSkillArray[ubCnt] ] ); + wcscat( sString2, sString ); + } + else + { + swprintf( sString, L"%s", gzMercSkillTextNew[ ubTempSkillArray[ubCnt] ] ); + + if ( ubTempSkillArray[ubCnt] > 19 ) + { + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[19].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, FONT10ARIALBOLD, &sX, &sY); + + if( sX <= iMinimumX ) + { + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[19].x+(iSlot*TEXT_BOX_WIDTH) + TEXT_BOX_WIDTH-20 +TEXT_DELTA_OFFSET),0,30,0,sString, FONT10ARIALBOLD, &sX, &sY); + sX = (INT16)max( sX, iMinimumX ); + } + sY = (INT16)(pPersonnelScreenPoints[19].y + (ubCnt * 12)); + + SetFont( FONT10ARIALBOLD ); + mprintf(sX,sY,sString); + SetFont( PERS_FONT ); + } + else + { + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[19].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + if( sX <= iMinimumX ) + { + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[19].x+(iSlot*TEXT_BOX_WIDTH) + TEXT_BOX_WIDTH-20 +TEXT_DELTA_OFFSET),0,30,0,sString, PERS_FONT, &sX, &sY); + sX = (INT16)max( sX, iMinimumX ); + } + sY = (INT16)(pPersonnelScreenPoints[19].y + (ubCnt * 12)); + + mprintf(sX,sY,sString); + + } + + // Add specific region for fast help window + if( fAddedTraitRegion[ubCnt] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[ubCnt] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[ubCnt], ( sX ), ( sY ), + ( sX + StringPixLength(sString,PERS_FONT) ), ( sY + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[ubCnt] ); + fAddedTraitRegion[ubCnt] = TRUE; + // Assign the text + AssignPersonnelSkillTraitHelpText( ((ubTempSkillArray[ubCnt] > 19) ? (ubTempSkillArray[ubCnt]-19) : ubTempSkillArray[ubCnt]), ((ubTempSkillArray[ubCnt] > 19) ? TRUE : FALSE), Menptr[iId].ubProfile, ubCnt ); + } + } + + // if we have more skills than we can display, show "more" and create a tooltip box with the rest of them + if ( fDisplayMoreTraits ) + { + swprintf( sString, L"%s", gzMercSkillTextNew[ 29 ]); // dispaly "More..." + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[19].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + if( sX <= iMinimumX ) + { + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[19].x+(iSlot*TEXT_BOX_WIDTH) + TEXT_BOX_WIDTH-20 +TEXT_DELTA_OFFSET),0,30,0,sString, PERS_FONT, &sX, &sY); + sX = (INT16)max( sX, iMinimumX ); + } + sY = (INT16)(pPersonnelScreenPoints[19].y + 48); + + mprintf(sX,sY,sString); + + // Add specific region for fast help window + if( fAddedTraitRegion[4] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[4] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[4], ( sX ), ( sY ), + ( sX + StringPixLength(sString,PERS_FONT) ), ( sY + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[4] ); + fAddedTraitRegion[4] = TRUE; + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[4]), sString2 ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[4], MSYS_NO_CALLBACK ); + } + } + } + else + { + INT8 bSkill1 = 0, bSkill2 = 0; + bSkill1 = gMercProfiles[ Menptr[iId].ubProfile ].bSkillTraits[0]; + bSkill2 = gMercProfiles[ Menptr[iId].ubProfile ].bSkillTraits[1]; + + //if the 2 skills are the same, add the '(expert)' at the end + if( bSkill1 == bSkill2 && bSkill1 != 0 ) + { + swprintf( sString, L"%s %s", gzMercSkillText[bSkill1], gzMercSkillText[EXPERT] ); + + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + + //KM: April 16, 1999 + //Perform the potential overrun check + if( sX <= iMinimumX ) + { + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[iCounter].x+(iSlot*TEXT_BOX_WIDTH) + TEXT_BOX_WIDTH-20 +TEXT_DELTA_OFFSET),0,30,0,sString, PERS_FONT, &sX, &sY); + sX = (INT16)max( sX, iMinimumX ); + } + + mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); + + // Add specific region for fast help window + if( fAddedTraitRegion[0] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[0] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[0], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y ), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[0] ); + fAddedTraitRegion[0] = TRUE; + // Assign the text + AssignPersonnelSkillTraitHelpText( bSkill1, TRUE, iId, 0 ); + + } + else + { + //Display the first skill + if( bSkill1 != 0 ) + { + swprintf( sString, L"%s", gzMercSkillText[bSkill1] ); + + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + + //KM: April 16, 1999 + //Perform the potential overrun check + sX = (INT16)max( sX, iMinimumX ); + mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); + + // Add specific region for fast help window + if( fAddedTraitRegion[0] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[0] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[0], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y ), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[0] ); + fAddedTraitRegion[0] = TRUE; + // Assign the text + AssignPersonnelSkillTraitHelpText( bSkill1, FALSE, iId, 0 ); + + bScreenLocIndex++; + } + + //Display the second skill + if( bSkill2 != 0 ) + { + swprintf( sString, L"%s", gzMercSkillText[bSkill2] ); + + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + + //KM: April 16, 1999 + //Perform the potential overrun check + sX = (INT16)max( sX, iMinimumX ); + mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); + + // Add specific region for fast help window + if( fAddedTraitRegion[1] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[1] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[1], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y ), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[1] ); + fAddedTraitRegion[1] = TRUE; + // Assign the text + AssignPersonnelSkillTraitHelpText( bSkill2, FALSE, iId, 1 ); + + bScreenLocIndex++; + } + + //if no skill was displayed + if( bScreenLocIndex == 19 ) + { + swprintf( sString, L"%s", pPersonnelScreenStrings[ PRSNL_TXT_NOSKILLS ] ); + + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[bScreenLocIndex].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,pPersonnelScreenPoints[bScreenLocIndex].y,sString); + + // Add specific region for fast help window + if( fAddedTraitRegion[0] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[0] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[0], ( sX - 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y ), + ( sX + StringPixLength(sString,PERS_FONT) + 3 ), (UINT16)( pPersonnelScreenPoints[bScreenLocIndex].y + 7 ), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[0] ); + fAddedTraitRegion[0] = TRUE; + // Assign the text + AssignPersonnelSkillTraitHelpText( bSkill1, FALSE, iId, 0 ); + } } } } @@ -1759,22 +1970,6 @@ void DisplayCharStats(INT32 iId, INT32 iSlot) } } break; -/* - case 19: - // total contract time served - mprintf((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[24].y,pPersonnelScreenStrings[18]); - if( gMercProfiles[Menptr[iId].ubProfile].usTotalDaysServed > 0 ) - { - swprintf(sString, L"%d %s",gMercProfiles[Menptr[iId].ubProfile].usTotalDaysServed - 1, gpStrategicString[ STR_PB_DAYS_ABBREVIATION ] ); - } - else - { - swprintf(sString, L"%d %s",gMercProfiles[Menptr[iId].ubProfile].usTotalDaysServed, gpStrategicString[ STR_PB_DAYS_ABBREVIATION ] ); - } - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[24].y,sString); - break; -*/ } } return; @@ -1963,32 +2158,19 @@ void DisplayPicturesOfCurrentTeam( void ) } // if SOLDIERTYPE *pSoldier = MercPtrs[currentTeamList[currentOnSreenIndex]]; - if ((50 < pSoldier->ubProfile) && (57 > pSoldier->ubProfile)) { + if ((50 < pSoldier->ubProfile) && (57 > pSoldier->ubProfile)) + { sprintf( sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex ); - } else { + } + else + { if ( pSoldier->ubProfile < 100 ) { - if (gGameExternalOptions.fReadProfileDataFromXML) - { - // HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value. - sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex); - } - else - { - sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, pSoldier->ubProfile); - } + sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex); } else { - if (gGameExternalOptions.fReadProfileDataFromXML) - { - // HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value. - sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex); - } - else - { - sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, pSoldier->ubProfile); - } + sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex); } // else } // else @@ -2090,27 +2272,41 @@ void PersonnelPortraitCallback( MOUSE_REGION * pRegion, INT32 iReason ) void DisplayFaceOfDisplayedMerc( ) { // if showing inventory, leave - if (fCurrentTeamMode) { - if (currentTeamIndex == -1) { + if (fCurrentTeamMode) + { + if (currentTeamIndex == -1) + { return; } DisplayHighLightBox(); - RenderPersonnelFace(currentTeamList[currentTeamIndex], 0, FALSE, FALSE, FALSE ); + RenderPersonnelFace(-1, currentTeamList[currentTeamIndex], FALSE, FALSE, FALSE ); DisplayCharName(currentTeamList[currentTeamIndex], 0 ); - if( gubPersonnelInfoState == PRSNL_INV ) { + if( gubPersonnelInfoState == PRSNL_INV ) + { return; } + RenderPersonnelStats(currentTeamList[currentTeamIndex], 0 ); - } else { - if (iCurrentPersonSelectedId == -1) { + } + else + { + if (iCurrentPersonSelectedId == -1) + { return; } + DisplayHighLightBox(); + + // Hier drfte der Aufruf falsch sein + RenderPersonnelFace( GetIdOfPastMercInSlot( iCurrentPersonSelectedId ), 0, IsPastMercDead( iCurrentPersonSelectedId ), IsPastMercFired( iCurrentPersonSelectedId ), IsPastMercOther( iCurrentPersonSelectedId ) ); DisplayDepartedCharName( GetIdOfPastMercInSlot( iCurrentPersonSelectedId ), 0, GetTheStateOfDepartedMerc( GetIdOfPastMercInSlot( iCurrentPersonSelectedId ) ) ); - if( gubPersonnelInfoState == PRSNL_INV ) { + + if( gubPersonnelInfoState == PRSNL_INV ) + { return; } + DisplayDepartedCharStats( GetIdOfPastMercInSlot( iCurrentPersonSelectedId ), 0, GetTheStateOfDepartedMerc( GetIdOfPastMercInSlot( iCurrentPersonSelectedId ) ) ); } } @@ -2153,6 +2349,16 @@ void RenderInventoryForCharacter( INT32 iId, INT32 iSlot ) GetVideoObject(&hHandle, guiPersonnelInventory); BltVideoObject(FRAME_BUFFER, hHandle, 0,( INT16 ) ( iScreenWidthOffset + 397 ), ( INT16 ) ( iScreenHeightOffset + 200 ), VO_BLT_SRCTRANSPARENCY,NULL); + // SANDRO - remove the regions + for( INT8 i = 0; i < 13; i++ ) + { + if( fAddedTraitRegion[i] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[i] ); + fAddedTraitRegion[i] = FALSE; + } + } + if (!fCurrentTeamMode) { return; } @@ -2197,8 +2403,8 @@ void RenderInventoryForCharacter( INT32 iId, INT32 iSlot ) usHeight = (UINT32)pTrav->usHeight; usWidth = (UINT32)pTrav->usWidth; - sCenX = PosX + ( abs( 57 - usWidth ) / 2 ) - pTrav->sOffsetX; - sCenY = PosY + ( abs( 22 - usHeight ) / 2 ) - pTrav->sOffsetY; + sCenX = PosX + ( abs( 57 - (int)usWidth ) / 2 ) - pTrav->sOffsetX; + sCenY = PosY + ( abs( 22 - (int)usHeight ) / 2 ) - pTrav->sOffsetY; // shadow if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sCenX-2, sCenY+2); @@ -3724,6 +3930,8 @@ void DisplayLowestStatValuesForCurrentTeam( void ) { if (fCurrentTeamMode) { iId = GetIdOfMercWithLowestStat( iCounter ); + if( iId == -1 ) + continue; } else { iDepartedId = GetIdOfDepartedMercWithLowestStat( iCounter ); if( iDepartedId == -1 ) @@ -3739,9 +3947,9 @@ void DisplayLowestStatValuesForCurrentTeam( void ) if (fCurrentTeamMode) { // get name - if( iId == -1 ) + /*if( iId == -1 ) swprintf( sString, L"%s", pPOWStrings[1] ); - else + else*/ swprintf( sString, L"%s", MercPtrs[ iId ]->name ); } else { // get name @@ -3754,9 +3962,9 @@ void DisplayLowestStatValuesForCurrentTeam( void ) case 0: // health if (fCurrentTeamMode) { - if( iId == -1 ) + /*if( iId == -1 ) iStat = -1; - else + else*/ iStat = MercPtrs[ iId ]->stats.bLifeMax; } else { iStat = gMercProfiles[ iDepartedId ] . bLife; @@ -3844,9 +4052,9 @@ void DisplayLowestStatValuesForCurrentTeam( void ) break; } - if( iStat == -1 ) + /*if( iStat == -1 ) swprintf( sString, L"%s", pPOWStrings[1] ); - else + else*/ swprintf( sString, L"%d", iStat ); // right justify @@ -3895,6 +4103,9 @@ void DisplayHighestStatValuesForCurrentTeam( void ) else iId = GetIdOfDepartedMercWithHighestStat( iCounter ); + if( iId == -1 ) + continue; + // even or odd?..color black or yellow? if( iCounter % 2 == 0 ) { @@ -3905,13 +4116,14 @@ void DisplayHighestStatValuesForCurrentTeam( void ) SetFontForeground( PERS_TEXT_FONT_COLOR ); } - if (fCurrentTeamMode) { // get name - if( iId == -1 ) + /*if( iId == -1 ) + { swprintf( sString, L"%s", pPOWStrings[1] ); - else + } + else*/ swprintf( sString, L"%s", MercPtrs[ iId ]->name ); } else @@ -3926,9 +4138,9 @@ void DisplayHighestStatValuesForCurrentTeam( void ) case 0: // health if (fCurrentTeamMode) { - if( iId == -1 ) + /*if( iId == -1 ) iStat = -1; - else + else*/ iStat = MercPtrs[ iId ]->stats.bLifeMax; } else { iStat = gMercProfiles[ iId ] . bLife; @@ -4016,9 +4228,9 @@ void DisplayHighestStatValuesForCurrentTeam( void ) break; } - if( iStat == -1 ) + /*if( iStat == -1 ) swprintf( sString, L"%s", pPOWStrings[1] ); - else + else*/ swprintf( sString, L"%d", iStat ); // right justify @@ -4502,32 +4714,19 @@ void DisplayPortraitOfPastMerc( INT32 iId , INT32 iCounter, BOOLEAN fDead, BOOLE HVOBJECT hFaceHandle; VOBJECT_DESC VObjectDesc; - if( ( 50 < iId )&&( 57 > iId ) ) { + if( ( 50 < iId )&&( 57 > iId ) ) + { sprintf( sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex ); - } else { + } + else + { if( iId < 100 ) { - if (gGameExternalOptions.fReadProfileDataFromXML) - { - // HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value. - sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex ); - } - else - { - sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, iId ); - } + sprintf(sTemp, "%s%02d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex ); } else - { - if (gGameExternalOptions.fReadProfileDataFromXML) - { - // HEADROCK PROFEX: Do not read direct profile number, instead, look inside the profile for a ubFaceIndex value. - sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex ); - } - else - { - sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, iId ); - } + { + sprintf(sTemp, "%s%03d.sti", SMALL_FACES_DIR, gMercProfiles[ iId ].ubFaceIndex ); } } @@ -4558,12 +4757,23 @@ void DisplayDepartedCharStats(INT32 iId, INT32 iSlot, INT32 iState) CHAR16 sString[50]; INT16 sX, sY; UINT32 uiHits = 0; + HVOBJECT hHandle; // font stuff SetFont( FONT10ARIAL ); SetFontBackground( FONT_BLACK ); SetFontForeground( PERS_TEXT_FONT_COLOR ); + // SANDRO - remove the regions + for( INT8 i = 0; i < 13; i++ ) + { + if( fAddedTraitRegion[i] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[i] ); + fAddedTraitRegion[i] = FALSE; + } + } + // display the stats for a char for(iCounter=0;iCounter 0 ) + if( (gMercProfiles[iId].records.usShotsFired + gMercProfiles[iId].records.usMissilesLaunched + gMercProfiles[iId].records.usGrenadesThrown + gMercProfiles[iId].records.usKnivesThrown + gMercProfiles[iId].records.usBladeAttacks + gMercProfiles[iId].records.usHtHAttacks) > 0 ) { - uiHits /= ( UINT32 )gMercProfiles[iId].usShotsFired; + uiHits /= ( UINT32 )(gMercProfiles[iId].records.usShotsFired + gMercProfiles[iId].records.usMissilesLaunched + gMercProfiles[iId].records.usGrenadesThrown + gMercProfiles[iId].records.usKnivesThrown + gMercProfiles[iId].records.usBladeAttacks + gMercProfiles[iId].records.usHtHAttacks); + if ( uiHits > 100 ) + uiHits = 100; } else { @@ -4692,24 +4938,101 @@ void DisplayDepartedCharStats(INT32 iId, INT32 iSlot, INT32 iState) uiHits = 0; } + swprintf(sString, L"%d %%%%",uiHits); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - sX += StringPixLength( L"%", PERS_FONT ); - mprintf(sX,pPersonnelScreenPoints[23].y,sString); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[22].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + sX += StringPixLength( L"%", PERS_FONT ); + mprintf(sX,(pPersonnelScreenPoints[22].y - 8),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[22].x + 148), ( pPersonnelScreenPoints[22].y - 9 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[9] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[9] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[9], (UINT16)( pPersonnelScreenPoints[22].x + 147 ), (UINT16)( pPersonnelScreenPoints[22].y - 10 ), + (UINT16)( pPersonnelScreenPoints[22].x + 166 ), (UINT16)(pPersonnelScreenPoints[22].y + 1), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[9] ); + fAddedTraitRegion[9] = TRUE; + // Assign the text + AssignPersonnelHitPercentageHelpText( iId ); + break; case 17: - // battles - mprintf((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[24].y,pPersonnelScreenStrings[PRSNL_TXT_BATTLES]); - swprintf(sString, L"%d",gMercProfiles[iId].usBattlesFought); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[24].y,sString); + // Achievements + mprintf((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[23].y - 6),pPersonnelScreenStrings[PRSNL_TXT_ACHIEVEMNTS]); + swprintf(sString, L"%d %%%%",CalculateMercsAchievemntPercentage( iId )); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + sX += StringPixLength( L"%", PERS_FONT ); + mprintf(sX,(pPersonnelScreenPoints[23].y - 6),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[23].x + 148), ( pPersonnelScreenPoints[23].y - 7 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[10] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[10] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[10], (UINT16)( pPersonnelScreenPoints[23].x + 147 ), (UINT16)( pPersonnelScreenPoints[23].y - 8 ), + (UINT16)( pPersonnelScreenPoints[23].x + 166 ), (UINT16)(pPersonnelScreenPoints[23].y + 3), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[10] ); + fAddedTraitRegion[10] = TRUE; + // Assign the text + AssignPersonnelAchievementsHelpText( iId ); + break; case 18: + // battles + mprintf((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[24].y - 4),pPersonnelScreenStrings[PRSNL_TXT_BATTLES]); + swprintf(sString, L"%d",(gMercProfiles[iId].records.usBattlesTactical + gMercProfiles[iId].records.usBattlesAutoresolve)); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[24].y - 4),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[24].x + 148), ( pPersonnelScreenPoints[24].y - 5 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[11] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[11] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[11], (UINT16)( pPersonnelScreenPoints[24].x + 147 ), (UINT16)( pPersonnelScreenPoints[24].y - 6 ), + (UINT16)( pPersonnelScreenPoints[24].x + 166 ), (UINT16)(pPersonnelScreenPoints[24].y + 5), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[11] ); + fAddedTraitRegion[11] = TRUE; + // Assign the text + AssignPersonnelBattlesHelpText( iId ); + + break; + case 19: // wounds - mprintf((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),pPersonnelScreenPoints[25].y,pPersonnelScreenStrings[PRSNL_TXT_TIMES_WOUNDED]); - swprintf(sString, L"%d",gMercProfiles[iId].usTimesWounded); - FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); - mprintf(sX,pPersonnelScreenPoints[25].y,sString); + mprintf((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[25].y - 2),pPersonnelScreenStrings[PRSNL_TXT_TIMES_WOUNDED]); + swprintf(sString, L"%d",(gMercProfiles[iId].records.usTimesWoundedShot + gMercProfiles[iId].records.usTimesWoundedStabbed + (gMercProfiles[iId].records.usTimesWoundedPunched/2) + gMercProfiles[iId].records.usTimesWoundedBlasted)); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[25].y - 2),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[25].x + 148), ( pPersonnelScreenPoints[25].y - 3 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[12] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[12] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[12], (UINT16)( pPersonnelScreenPoints[25].x + 147 ), (UINT16)( pPersonnelScreenPoints[25].y - 4 ), + (UINT16)( pPersonnelScreenPoints[25].x + 166 ), (UINT16)(pPersonnelScreenPoints[25].y + 7), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[12] ); + fAddedTraitRegion[12] = TRUE; + // Assign the text + AssignPersonnelWoundsHelpText( iId ); + break; } } @@ -4781,7 +5104,8 @@ void DisplayDepartedCharName( INT32 iId, INT32 iSlot, INT32 iState ) } //if the merc is an AIM merc - else if( iId < BIFF ) + //else if( iId < BIFF ) + else if ( gProfilesAIM[ iId ].ProfilId == iId ) { //if dismissed if( iState == DEPARTED_FIRED ) @@ -4791,7 +5115,8 @@ void DisplayDepartedCharName( INT32 iId, INT32 iSlot, INT32 iState ) } //else if its a MERC merc - else if( iId >= BIFF && iId <= BUBBA ) + //else if( iId >= BIFF && iId <= BUBBA ) + else if ( gProfilesMERC[ iId ].ProfilId == iId ) { if( iState == DEPARTED_FIRED ) swprintf( sString, L"%s", pPersonnelDepartedStateStrings[ DEPARTED_FIRED ] ); @@ -4799,7 +5124,8 @@ void DisplayDepartedCharName( INT32 iId, INT32 iSlot, INT32 iState ) swprintf( sString, L"%s", pPersonnelDepartedStateStrings[ DEPARTED_QUIT ] ); } //must be a RPC - else + //else + else if ( gProfilesRPC[ iId ].ProfilId == iId ) { if( iState == DEPARTED_FIRED ) swprintf( sString, L"%s", pPersonnelDepartedStateStrings[ DEPARTED_FIRED ] ); @@ -6153,7 +6479,18 @@ void DisplayEmploymentinformation( INT32 iId, INT32 iSlot ) CHAR16 sString[50]; CHAR16 sStringA[ 50 ]; INT16 sX, sY; + UINT32 uiHits = 0; + HVOBJECT hHandle; + // SANDRO - remove the regions + for( INT8 i = 0; i < 13; i++ ) + { + if( fAddedTraitRegion[i] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[i] ); + fAddedTraitRegion[i] = FALSE; + } + } if( Menptr[iId].flags.uiStatusFlags & SOLDIER_VEHICLE ) { @@ -6392,6 +6729,174 @@ DEF:3/19/99: break; + ///////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - show num kills, hit percentage, times wounded etc. in here instead of stats table + + case 14: + // kills + mprintf((INT16)(pPersonnelScreenPoints[20].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[20].y - 12),pPersonnelScreenStrings[PRSNL_TXT_KILLS]); + swprintf(sString, L"%d",(gMercProfiles[Menptr[iId].ubProfile].records.usKillsElites + gMercProfiles[Menptr[iId].ubProfile].records.usKillsRegulars + gMercProfiles[Menptr[iId].ubProfile].records.usKillsAdmins + gMercProfiles[Menptr[iId].ubProfile].records.usKillsHostiles + gMercProfiles[Menptr[iId].ubProfile].records.usKillsCreatures + gMercProfiles[Menptr[iId].ubProfile].records.usKillsTanks + gMercProfiles[Menptr[iId].ubProfile].records.usKillsOthers)); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[20].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[20].y - 12),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[20].x + 148), ( pPersonnelScreenPoints[20].y - 13 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[7] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[7] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[7], (UINT16)( pPersonnelScreenPoints[20].x + 147 ), (UINT16)( pPersonnelScreenPoints[20].y - 14 ), + (UINT16)( pPersonnelScreenPoints[20].x + 166 ), (UINT16)(pPersonnelScreenPoints[20].y - 3), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[7] ); + fAddedTraitRegion[7] = TRUE; + // Assign the text + AssignPersonnelKillsHelpText( iId ); + + break; + case 15: + // assists + mprintf((INT16)(pPersonnelScreenPoints[21].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[21].y - 10),pPersonnelScreenStrings[PRSNL_TXT_ASSISTS]); + swprintf(sString, L"%d",(gMercProfiles[Menptr[iId].ubProfile].records.usAssistsMercs + gMercProfiles[Menptr[iId].ubProfile].records.usAssistsMilitia + gMercProfiles[Menptr[iId].ubProfile].records.usAssistsOthers)); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[21].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[21].y - 10),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[21].x + 148), ( pPersonnelScreenPoints[21].y - 11 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[8] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[8] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[8], (UINT16)( pPersonnelScreenPoints[21].x + 147 ), (UINT16)( pPersonnelScreenPoints[21].y - 12 ), + (UINT16)( pPersonnelScreenPoints[21].x + 166 ), (UINT16)(pPersonnelScreenPoints[21].y - 1), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[8] ); + fAddedTraitRegion[8] = TRUE; + // Assign the text + AssignPersonnelAssistsHelpText( iId ); + + break; + case 16: + // shots/hits + mprintf((INT16)(pPersonnelScreenPoints[22].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[22].y - 8),pPersonnelScreenStrings[PRSNL_TXT_HIT_PERCENTAGE]); + uiHits = ( UINT32 )gMercProfiles[Menptr[iId].ubProfile].records.usShotsHit; + uiHits *= 100; + + // check we have shot at least once + if( (gMercProfiles[Menptr[iId].ubProfile].records.usShotsFired + gMercProfiles[Menptr[iId].ubProfile].records.usMissilesLaunched + gMercProfiles[Menptr[iId].ubProfile].records.usGrenadesThrown + gMercProfiles[Menptr[iId].ubProfile].records.usKnivesThrown + gMercProfiles[Menptr[iId].ubProfile].records.usBladeAttacks + gMercProfiles[Menptr[iId].ubProfile].records.usHtHAttacks) > 0 ) + { + uiHits /= ( UINT32 )(gMercProfiles[Menptr[iId].ubProfile].records.usShotsFired + gMercProfiles[Menptr[iId].ubProfile].records.usMissilesLaunched + gMercProfiles[Menptr[iId].ubProfile].records.usGrenadesThrown + gMercProfiles[Menptr[iId].ubProfile].records.usKnivesThrown + gMercProfiles[Menptr[iId].ubProfile].records.usBladeAttacks + gMercProfiles[Menptr[iId].ubProfile].records.usHtHAttacks); + if ( uiHits > 100 ) + uiHits = 100; + } + else + { + // no, set hit % to 0 + uiHits = 0; + } + + + swprintf(sString, L"%d %%%%",uiHits); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[22].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + sX += StringPixLength( L"%", PERS_FONT ); + mprintf(sX,(pPersonnelScreenPoints[22].y - 8),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[22].x + 148), ( pPersonnelScreenPoints[22].y - 9 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[9] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[9] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[9], (UINT16)( pPersonnelScreenPoints[22].x + 147 ), (UINT16)( pPersonnelScreenPoints[22].y - 10 ), + (UINT16)( pPersonnelScreenPoints[22].x + 166 ), (UINT16)(pPersonnelScreenPoints[22].y + 1), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[9] ); + fAddedTraitRegion[9] = TRUE; + // Assign the text + AssignPersonnelHitPercentageHelpText( iId ); + + break; + case 17: + // Achievements + mprintf((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[23].y - 6),pPersonnelScreenStrings[PRSNL_TXT_ACHIEVEMNTS]); + swprintf(sString, L"%d %%%%", CalculateMercsAchievemntPercentage( Menptr[iId].ubProfile )); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[23].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + sX += StringPixLength( L"%", PERS_FONT ); + mprintf(sX,(pPersonnelScreenPoints[23].y - 6),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[23].x + 148), ( pPersonnelScreenPoints[23].y - 7 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[10] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[10] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[10], (UINT16)( pPersonnelScreenPoints[23].x + 147 ), (UINT16)( pPersonnelScreenPoints[23].y - 8 ), + (UINT16)( pPersonnelScreenPoints[23].x + 166 ), (UINT16)(pPersonnelScreenPoints[23].y + 3), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[10] ); + fAddedTraitRegion[10] = TRUE; + // Assign the text + AssignPersonnelAchievementsHelpText( iId ); + + break; + case 18: + // battles + mprintf((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[24].y - 4),pPersonnelScreenStrings[PRSNL_TXT_BATTLES]); + swprintf(sString, L"%d",(gMercProfiles[Menptr[iId].ubProfile].records.usBattlesTactical + gMercProfiles[Menptr[iId].ubProfile].records.usBattlesAutoresolve)); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[24].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[24].y - 4),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[24].x + 148), ( pPersonnelScreenPoints[24].y - 5 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[11] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[11] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[11], (UINT16)( pPersonnelScreenPoints[24].x + 147 ), (UINT16)( pPersonnelScreenPoints[24].y - 6 ), + (UINT16)( pPersonnelScreenPoints[24].x + 166 ), (UINT16)(pPersonnelScreenPoints[24].y + 5), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[11] ); + fAddedTraitRegion[11] = TRUE; + // Assign the text + AssignPersonnelBattlesHelpText( iId ); + + break; + case 19: + // wounds + mprintf((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),(pPersonnelScreenPoints[25].y - 2),pPersonnelScreenStrings[PRSNL_TXT_TIMES_WOUNDED]); + swprintf(sString, L"%d",(gMercProfiles[Menptr[iId].ubProfile].records.usTimesWoundedShot + gMercProfiles[Menptr[iId].ubProfile].records.usTimesWoundedStabbed + (gMercProfiles[Menptr[iId].ubProfile].records.usTimesWoundedPunched/2) + gMercProfiles[Menptr[iId].ubProfile].records.usTimesWoundedBlasted)); + FindFontRightCoordinates((INT16)(pPersonnelScreenPoints[25].x+(iSlot*TEXT_BOX_WIDTH)),0,TEXT_BOX_WIDTH-20,0,sString, PERS_FONT, &sX, &sY); + mprintf(sX,(pPersonnelScreenPoints[25].y - 2),sString); + + GetVideoObject(&hHandle, guiQMark); + BltVideoObject( FRAME_BUFFER, hHandle, 0,(pPersonnelScreenPoints[25].x + 148), ( pPersonnelScreenPoints[25].y - 3 ), VO_BLT_SRCTRANSPARENCY,NULL ); + + // Add specific region for fast help window + if( fAddedTraitRegion[12] ) + { + MSYS_RemoveRegion( &gSkillTraitHelpTextRegion[12] ); + } + MSYS_DefineRegion( &gSkillTraitHelpTextRegion[12], (UINT16)( pPersonnelScreenPoints[25].x + 147 ), (UINT16)( pPersonnelScreenPoints[25].y - 4 ), + (UINT16)( pPersonnelScreenPoints[25].x + 166 ), (UINT16)(pPersonnelScreenPoints[25].y + 7), MSYS_PRIORITY_HIGH, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, NULL ); + MSYS_AddRegion( &gSkillTraitHelpTextRegion[12] ); + fAddedTraitRegion[12] = TRUE; + // Assign the text + AssignPersonnelWoundsHelpText( iId ); + + break; + + ///////////////////////////////////////////////////////////////////////////////////////////////// } } } @@ -6429,10 +6934,1583 @@ INT32 CalcTimeLeftOnMercContract( SOLDIERTYPE *pSoldier ) return( iTimeLeftOnContract ); } +// SANDRO - Popup text windows for traits +void AssignPersonnelSkillTraitHelpText( UINT8 ubTraitNumber, BOOLEAN fExpertLevel, INT32 IMercId, INT8 bRegionNumber ) +{ + CHAR16 apStr[ 5000 ]; + CHAR16 atStr[ 1500 ]; + if( gGameOptions.fNewTraitSystem ) + { + switch( ubTraitNumber ) + { + case AUTO_WEAPONS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubAWBonusCtHAssaultRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[0], ( gSkillTraitValues.ubAWBonusCtHAssaultRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWBonusCtHSMGs != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[1], ( gSkillTraitValues.ubAWBonusCtHSMGs * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWBonusCtHLMGs != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[2], ( gSkillTraitValues.ubAWBonusCtHLMGs * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWFiringSpeedBonusLMGs != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[3], ( gSkillTraitValues.ubAWFiringSpeedBonusLMGs * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWPercentReadyLMGReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[4], ( gSkillTraitValues.ubAWPercentReadyLMGReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWAutoFirePenaltyReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[5], ( gSkillTraitValues.ubAWAutoFirePenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAWUnwantedBulletsReduction > 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsAutoWeapons[6]); + wcscat( apStr, atStr ); + } + break; + } + case HEAVY_WEAPONS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[0], ( gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWRocketLaunchersAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[1], ( gSkillTraitValues.ubHWRocketLaunchersAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWBonusCtHGrenadeLaunchers != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[2], ( gSkillTraitValues.ubHWBonusCtHGrenadeLaunchers * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWBonusCtHRocketLaunchers != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[3], ( gSkillTraitValues.ubHWBonusCtHRocketLaunchers * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWMortarAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[4], ( gSkillTraitValues.ubHWMortarAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWMortarCtHPenaltyReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[5], ( gSkillTraitValues.ubHWMortarCtHPenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWDamageTanksBonusPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[6], ( gSkillTraitValues.ubHWDamageTanksBonusPercent * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubHWDamageBonusPercentForHW != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsHeavyWeapons[7], ( gSkillTraitValues.ubHWDamageBonusPercentForHW * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case SNIPER_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSNBonusCtHRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[0], ( gSkillTraitValues.ubSNBonusCtHRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNBonusCtHSniperRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[1], ( gSkillTraitValues.ubSNBonusCtHSniperRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNEffRangeToTargetReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[2], ( gSkillTraitValues.ubSNEffRangeToTargetReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNAimingBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[3], ( gSkillTraitValues.ubSNAimingBonusPerClick * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNDamageBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[4], ( gSkillTraitValues.ubSNDamageBonusPerClick * (fExpertLevel ? 2 : 1)), L"%"); + if( gSkillTraitValues.ubSNDamageBonusFromNumClicks == 0) + { + wcscat( apStr, gzIMPMajorTraitsHelpTextsSniper[5] ); + wcscat( apStr, gzIMPMajorTraitsHelpTextsSniper[6] ); + } + else if( gSkillTraitValues.ubSNDamageBonusFromNumClicks == 1 ) + { + wcscat( atStr, gzIMPMajorTraitsHelpTextsSniper[6] ); + } + else + { + wcscat( atStr, gzIMPMajorTraitsHelpTextsSniper[6] ); + wcscat( atStr, gzIMPMajorTraitsHelpTextsSniper[gSkillTraitValues.ubSNDamageBonusFromNumClicks + 4] ); + } + wcscat( atStr, L"\n" ); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNChamberRoundAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[14], ( gSkillTraitValues.ubSNChamberRoundAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSNAimClicksAdded != 0 ) + { + if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[15]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[16], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + break; + } + case RANGER_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubRABonusCtHRifles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[0], ( gSkillTraitValues.ubRABonusCtHRifles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRABonusCtHShotguns != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[1], ( gSkillTraitValues.ubRABonusCtHShotguns * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAPumpShotgunsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[2], ( gSkillTraitValues.ubRAPumpShotgunsAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAGroupTimeSpentForTravellingFoot != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[3], ( gSkillTraitValues.ubRAGroupTimeSpentForTravellingFoot * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAGroupTimeSpentForTravellingVehicle != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[4], ( gSkillTraitValues.ubRAGroupTimeSpentForTravellingVehicle * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRABreathForTravellingReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[5], ( gSkillTraitValues.ubRABreathForTravellingReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubRAWeatherPenaltiesReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[6], ( gSkillTraitValues.ubRAWeatherPenaltiesReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + //if( gSkillTraitValues.ubRACamoEffectivenessBonus != 0 ) + //{ + // swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[7], ( gSkillTraitValues.ubRACamoEffectivenessBonus * (fExpertLevel ? 2 : 1)), L"%"); + // wcscat( apStr, atStr ); + //} + if( gSkillTraitValues.ubRACamoWornountSpeedReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsRanger[8], ( gSkillTraitValues.ubRACamoWornountSpeedReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case GUNSLINGER_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubGSFiringSpeedBonusPistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[0], ( gSkillTraitValues.ubGSFiringSpeedBonusPistols * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSEffectiveRangeBonusPistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[1], ( gSkillTraitValues.ubGSEffectiveRangeBonusPistols * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSBonusCtHPistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[2], ( gSkillTraitValues.ubGSBonusCtHPistols * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSBonusCtHMachinePistols != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[3], ( gSkillTraitValues.ubGSBonusCtHMachinePistols * (fExpertLevel ? 2 : 1)), L"%"); + if( gSkillTraitValues.ubGSCtHMPExcludeAuto ) + wcscat( atStr, gzIMPMajorTraitsHelpTextsGunslinger[4] ); + wcscat( atStr, L"\n"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSAimingBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[5], ( gSkillTraitValues.ubGSAimingBonusPerClick * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSPercentReadyPistolsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[6], ( gSkillTraitValues.ubGSPercentReadyPistolsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSRealoadSpeedHandgunsBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[7], ( gSkillTraitValues.ubGSRealoadSpeedHandgunsBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubGSAimClicksAdded != 0 ) + { + if( gSkillTraitValues.ubGSAimClicksAdded == 1 && !fExpertLevel ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[8], ( gSkillTraitValues.ubGSAimClicksAdded * (fExpertLevel ? 2 : 1))); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsGunslinger[9], ( gSkillTraitValues.ubGSAimClicksAdded * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + break; + } + case MARTIAL_ARTS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubMAPunchAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[0], ( gSkillTraitValues.ubMAPunchAPsReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusCtHBareHands != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[1], ( gSkillTraitValues.ubMABonusCtHBareHands * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusCtHBrassKnuckles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[2], ( gSkillTraitValues.ubMABonusCtHBrassKnuckles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusDamageHandToHand != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[3], ( gSkillTraitValues.ubMABonusDamageHandToHand * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMABonusBreathDamageHandToHand != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[4], ( gSkillTraitValues.ubMABonusBreathDamageHandToHand * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usMALostBreathRegainPenalty != 0 ) + { + if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 25) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[5]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 50) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[6]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 100) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[7]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 200) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[8]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 400) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[9]); + else if( (gSkillTraitValues.usMALostBreathRegainPenalty * (fExpertLevel ? 2 : 1)) <= 700) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[10]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[11]); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usMAAimedPunchDamageBonus != 0 ) + { + if (gMercProfiles[ IMercId ].ubBodyType != REGMALE || (gSkillTraitValues.fPermitExtraAnimationsOnlyToMA && !fExpertLevel)) + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[12], ( gSkillTraitValues.usMAAimedPunchDamageBonus * (fExpertLevel ? 2 : 1)), L"%"); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[13], ( gSkillTraitValues.usMAAimedPunchDamageBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAChanceToDodgeHtH != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[14], ( gSkillTraitValues.ubMAChanceToDodgeHtH * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAOnTopCTDHtHBareHanded != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[15], ( gSkillTraitValues.ubMAOnTopCTDHtHBareHanded * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + if( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles == gSkillTraitValues.ubMAOnTopCTDHtHBareHanded ) + wcscat( apStr, gzIMPMajorTraitsHelpTextsMartialArts[16] ); + else if( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles > 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[17], ( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + wcscat( apStr, L"\n" ); + } + else if( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[18], ( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAChanceToDodgeMelee != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[19], ( gSkillTraitValues.ubMAChanceToDodgeMelee * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAReducedAPsToSteal != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[20], ( gSkillTraitValues.ubMAReducedAPsToSteal * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAAPsChangeStanceReduction != 0 && ( gSkillTraitValues.ubMAAPsChangeStanceReduction == gSkillTraitValues.ubMAApsTurnAroundReduction == gSkillTraitValues.ubMAAPsClimbOrJumpReduction )) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[21], ( gSkillTraitValues.ubMAAPsChangeStanceReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + else + { + if( gSkillTraitValues.ubMAAPsChangeStanceReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[22], ( gSkillTraitValues.ubMAAPsChangeStanceReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAApsTurnAroundReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[23], ( gSkillTraitValues.ubMAApsTurnAroundReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMAAPsClimbOrJumpReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[24], ( gSkillTraitValues.ubMAAPsClimbOrJumpReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + } + if( gSkillTraitValues.ubMAChanceToCkickDoors != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[25], ( gSkillTraitValues.ubMAChanceToCkickDoors * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + //if (gMercProfiles[ IMercId ].ubBodyType == REGMALE && + if (gMercProfiles[ IMercId ].ubBodyType == REGMALE && + ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA && fExpertLevel) || + !gSkillTraitValues.fPermitExtraAnimationsOnlyToMA )) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsMartialArts[26]); + wcscat( apStr, atStr ); + } + break; + } + case SQUADLEADER_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSLBonusAPsPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[0], ( gSkillTraitValues.ubSLBonusAPsPercent * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLEffectiveLevelInRadius != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[1], ( gSkillTraitValues.ubSLEffectiveLevelInRadius * (fExpertLevel ? 2 : 1)), (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLEffectiveLevelAsStandby != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[2], ( gSkillTraitValues.ubSLEffectiveLevelAsStandby * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLOverallSuppresionBonusPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[3], ( gSkillTraitValues.ubSLOverallSuppresionBonusPercent * (fExpertLevel ? 2 : 1)), L"%", (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLMoraleGainBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[4], ( gSkillTraitValues.ubSLMoraleGainBonus * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLMoraleLossReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[5], ( gSkillTraitValues.ubSLMoraleLossReduction * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[6], gSkillTraitValues.usSLRadiusNormal); + wcscat( apStr, atStr ); + if( gSkillTraitValues.usSLRadiusExtendedEar > gSkillTraitValues.usSLRadiusNormal ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[7], gSkillTraitValues.usSLRadiusExtendedEar); + + wcscat( apStr, atStr ); + wcscat( apStr, L"\n" ); + + if( gSkillTraitValues.ubSLMaxBonuses > 1 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[8], gSkillTraitValues.ubSLMaxBonuses ) ; + wcscat( apStr, atStr ); + } + + if( gSkillTraitValues.ubSLFearResistance != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[9], ( gSkillTraitValues.ubSLFearResistance * (fExpertLevel ? 2 : 1)), L"%", (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSLDeathMoralelossMultiplier != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsSquadleader[10], (1 + ( gSkillTraitValues.ubSLDeathMoralelossMultiplier * (fExpertLevel ? 2 : 1))), (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + } + break; + } + case TECHNICIAN_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.usTERepairSpeedBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[0], ( gSkillTraitValues.usTERepairSpeedBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usTELockpickingBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[1], ( gSkillTraitValues.usTELockpickingBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usTEDisarmElTrapBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[2], ( gSkillTraitValues.usTEDisarmElTrapBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usTEAttachingItemsBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[3], ( gSkillTraitValues.usTEAttachingItemsBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTEUnjamGunBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[4], ( gSkillTraitValues.ubTEUnjamGunBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTERepairElectronicsPenaltyReduction != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[5], ( gSkillTraitValues.ubTERepairElectronicsPenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTEChanceToDetectTrapsBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[6], ( gSkillTraitValues.ubTEChanceToDetectTrapsBonus * (fExpertLevel ? 2 : 1))); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTECtHControlledRobotBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[7], ( gSkillTraitValues.ubTECtHControlledRobotBonus * (fExpertLevel ? 2 : 1)), L"%", (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTETraitsNumToRepairRobot == 2 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[8], (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + } + else if( gSkillTraitValues.ubTETraitsNumToRepairRobot == 1 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[8], (fExpertLevel ? gzMercSkillTextNew[ubTraitNumber + 19] : gzMercSkillTextNew[ubTraitNumber])); + wcscat( apStr, atStr ); + + if( gSkillTraitValues.ubTERepairRobotPenaltyReduction != 0 && fExpertLevel) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsTechnician[9], ( gSkillTraitValues.ubTERepairRobotPenaltyReduction * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + } + break; + } + case DOCTOR_NT: + { + BOOLEAN fCanSurgery = FALSE; + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubDONumberTraitsNeededForSurgery != 0 && ((gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop) > 0)) + { + if( gSkillTraitValues.ubDONumberTraitsNeededForSurgery <= (fExpertLevel ? 2 : 1)) + { + fCanSurgery = TRUE; + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[0]); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[1], (gSkillTraitValues.ubDOSurgeryHealPercentBase + ( gSkillTraitValues.ubDOSurgeryHealPercentOnTop * (fExpertLevel ? 2 : 1))), L"%"); + wcscat( apStr, atStr ); + if( gSkillTraitValues.usDOSurgeryMedBagConsumption >= 60 ) + wcscat( apStr, gzIMPMajorTraitsHelpTextsDoctor[2] ); + + wcscat( apStr, L"\n" ); + } + } + if( (gSkillTraitValues.usDORepairStatsRateBasic + gSkillTraitValues.usDORepairStatsRateOnTop) > 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[3]); + wcscat( apStr, atStr ); + if( fCanSurgery ) + wcscat( apStr, gzIMPMajorTraitsHelpTextsDoctor[4] ); + + wcscat( apStr, gzIMPMajorTraitsHelpTextsDoctor[5] ); + } + if( gSkillTraitValues.usDODoctorAssignmentBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[6], ( gSkillTraitValues.usDODoctorAssignmentBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDOBandagingSpeedPercent != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[7], ( gSkillTraitValues.ubDOBandagingSpeedPercent * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDONaturalRegenBonus != 0 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[8], ( gSkillTraitValues.ubDONaturalRegenBonus * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + if( gSkillTraitValues.ubDOMaxRegenBonuses > 1 ) + { + swprintf( atStr, gzIMPMajorTraitsHelpTextsDoctor[9], gSkillTraitValues.ubDOMaxRegenBonuses ) ; + wcscat( apStr, atStr ); + } + wcscat( apStr, L"\n" ); + } + break; + } + case AMBIDEXTROUS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubAMPenaltyDoubleReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[0], gSkillTraitValues.ubAMPenaltyDoubleReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMReloadSpeedMagazines != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[1], gSkillTraitValues.ubAMReloadSpeedMagazines, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMReloadSpeedLoose != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[2], gSkillTraitValues.ubAMReloadSpeedLoose, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMPickItemsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[3], gSkillTraitValues.ubAMPickItemsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMWorkBackpackAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[4], gSkillTraitValues.ubAMWorkBackpackAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMHandleDoorsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[5], gSkillTraitValues.ubAMHandleDoorsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMHandleBombsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[6], gSkillTraitValues.ubAMHandleBombsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubAMAttachingItemsAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAmbidextrous[7], gSkillTraitValues.ubAMAttachingItemsAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case MELEE_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubMEBladesAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[0], gSkillTraitValues.ubMEBladesAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtHBladesBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[1], gSkillTraitValues.ubMECtHBladesBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtHBluntBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[2], gSkillTraitValues.ubMECtHBluntBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDamageBonusBlades != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[3], gSkillTraitValues.ubMEDamageBonusBlades, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDamageBonusBlunt != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[4], gSkillTraitValues.ubMEDamageBonusBlunt, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usMEAimedMeleeAttackDamageBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[5], gSkillTraitValues.usMEAimedMeleeAttackDamageBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDodgeBladesBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[6], gSkillTraitValues.ubMEDodgeBladesBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtDBladesOnTopWithBladeInHands != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[7], gSkillTraitValues.ubMECtDBladesOnTopWithBladeInHands, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMEDodgeBluntBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[8], gSkillTraitValues.ubMEDodgeBluntBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubMECtDBluntOnTopWithBladeInHands != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsMelee[9], gSkillTraitValues.ubMECtDBluntOnTopWithBladeInHands, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case THROWING_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubTHBladesAPsReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[0], gSkillTraitValues.ubTHBladesAPsReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesMaxRange != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[1], gSkillTraitValues.ubTHBladesMaxRange, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesCtHBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[2], gSkillTraitValues.ubTHBladesCtHBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesCtHBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[3], gSkillTraitValues.ubTHBladesCtHBonusPerClick, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesDamageBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[4], gSkillTraitValues.ubTHBladesDamageBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesDamageBonusPerClick != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[5], gSkillTraitValues.ubTHBladesDamageBonusPerClick, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesSilentCriticalHitChance != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[6], gSkillTraitValues.ubTHBladesSilentCriticalHitChance, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesCriticalHitMultiplierBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[7], gSkillTraitValues.ubTHBladesCriticalHitMultiplierBonus); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTHBladesAimClicksAdded != 0 ) + { + if( gSkillTraitValues.ubTHBladesAimClicksAdded == 1 ) + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[8], gSkillTraitValues.ubTHBladesAimClicksAdded ); + else + swprintf( atStr, gzIMPMinorTraitsHelpTextsThrowing[9], gSkillTraitValues.ubTHBladesAimClicksAdded ); + + wcscat( apStr, atStr ); + } + break; + } + case NIGHT_OPS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubNOeSightRangeBonusInDark != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[0], gSkillTraitValues.ubNOeSightRangeBonusInDark, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNOHearingRangeBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[1], gSkillTraitValues.ubNOHearingRangeBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNOHearingRangeBonusInDark != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[2], gSkillTraitValues.ubNOHearingRangeBonusInDark, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNOIterruptsBonusInDark != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[3], gSkillTraitValues.ubNOIterruptsBonusInDark, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubNONeedForSleepReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsNightOps[4], gSkillTraitValues.ubNONeedForSleepReduction); + wcscat( apStr, atStr ); + } + break; + } + case STEALTHY_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSTStealthModeSpeedBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[0], gSkillTraitValues.ubSTStealthModeSpeedBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSTBonusToMoveQuietly != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[1], gSkillTraitValues.ubSTBonusToMoveQuietly, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSTStealthBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[2], gSkillTraitValues.ubSTStealthBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSTStealthPenaltyForMovingReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsStealthy[3], gSkillTraitValues.ubSTStealthPenaltyForMovingReduction, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case ATHLETICS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubATAPsMovementReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAthletics[0], gSkillTraitValues.ubATAPsMovementReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubATBPsMovementReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsAthletics[1], gSkillTraitValues.ubATBPsMovementReduction, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case BODYBUILDING_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubBBDamageResistance != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[0], gSkillTraitValues.ubBBDamageResistance, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubBBCarryWeightBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[1], gSkillTraitValues.ubBBCarryWeightBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubBBBreathLossForHtHImpactReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[2], gSkillTraitValues.ubBBBreathLossForHtHImpactReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usBBIncreasedNeededDamageToFallDown != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsBodybuilding[3], gSkillTraitValues.usBBIncreasedNeededDamageToFallDown, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case DEMOLITIONS_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[0], gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEMaxRangeToThrowGrenades != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[1], gSkillTraitValues.ubDEMaxRangeToThrowGrenades, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDECtHWhenThrowingGrenades != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[2], gSkillTraitValues.ubDECtHWhenThrowingGrenades, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEDamageOfBombsAndMines != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[3], gSkillTraitValues.ubDEDamageOfBombsAndMines, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEAttachDetonatorCheckBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[4], gSkillTraitValues.ubDEAttachDetonatorCheckBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[5], gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEPlacedBombLevelBonus != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[6], gSkillTraitValues.ubDEPlacedBombLevelBonus); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubDEShapedChargeDamageMultiplier != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsDemolitions[7], gSkillTraitValues.ubDEShapedChargeDamageMultiplier); + wcscat( apStr, atStr ); + } + break; + } + case TEACHING_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubTGBonusToTrainMilitia != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[0], gSkillTraitValues.ubTGBonusToTrainMilitia, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[1], gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGBonusToTeachOtherMercs != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[2], gSkillTraitValues.ubTGBonusToTeachOtherMercs, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGEffectiveSkillValueForTeaching != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[3], gSkillTraitValues.ubTGEffectiveSkillValueForTeaching); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubTGBonusOnPractising != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsTeaching[4], gSkillTraitValues.ubTGBonusOnPractising, L"%"); + wcscat( apStr, atStr ); + } + break; + } + case SCOUTING_NT: + { + swprintf( apStr, L"" ); + if( gSkillTraitValues.ubSCSightRangebonusWithScopes != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[0], gSkillTraitValues.ubSCSightRangebonusWithScopes, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.usSCSightRangebonusWithBinoculars != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[1], gSkillTraitValues.usSCSightRangebonusWithBinoculars, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.ubSCTunnelVisionReducedWithBinoculars != 0 ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[2], gSkillTraitValues.ubSCTunnelVisionReducedWithBinoculars, L"%"); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.fSCCanDetectEnemyPresenseAround ) + { + if( gSkillTraitValues.fSCCanDetermineEnemyNumbersAround ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[3]); + wcscat( apStr, atStr ); + } + else + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[4]); + wcscat( apStr, atStr ); + } + } + if( gSkillTraitValues.fSCPreventsTheEnemyToAmbushMercs ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[5]); + wcscat( apStr, atStr ); + } + if( gSkillTraitValues.fSCPreventsBloodcatsAmbushes ) + { + swprintf( atStr, gzIMPMinorTraitsHelpTextsScouting[6]); + wcscat( apStr, atStr ); + } + break; + } + case NO_SKILLTRAIT_NT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPMajorTraitsHelpTextsNone[0] ); + wcscat( apStr, atStr ); + break; + } + } + } + else + { + switch( ubTraitNumber ) + { + case LOCKPICKING_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[LOCKPICKING_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[0], ( gbSkillTraitBonus[LOCKPICKING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case HANDTOHAND_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[HANDTOHAND_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[1], ( gbSkillTraitBonus[HANDTOHAND_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[2], ( 3 * gbSkillTraitBonus[HANDTOHAND_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[3], ( gbSkillTraitBonus[HANDTOHAND_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case ELECTRONICS_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[4] ); + wcscat( apStr, atStr ); + break; + } + case NIGHTOPS_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[5], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[6], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[7], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[8], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[9], (fExpertLevel ? 2 : 1)); + wcscat( apStr, atStr ); + break; + } + case THROWING_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[THROWING_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[10], ( gbSkillTraitBonus[THROWING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[11], ( gbSkillTraitBonus[THROWING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[12], ( 10 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case TEACHING_OT: + { + swprintf( apStr, L"" ); + if( gGameExternalOptions.ubTeachBonusToTrain != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[13], ( gGameExternalOptions.ubTeachBonusToTrain * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + if( (gGameExternalOptions.usTeacherTraitEffectOnLeadership - 100) > 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[14], ( (gGameExternalOptions.usTeacherTraitEffectOnLeadership - 100) * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case HEAVY_WEAPS_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[HEAVY_WEAPS_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[15], ( gbSkillTraitBonus[HEAVY_WEAPS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case AUTO_WEAPS_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[16], ( 2 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[17] ); + wcscat( apStr, atStr ); + break; + } + case STEALTHY_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[18], ( 25 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + if( gGameExternalOptions.ubStealthTraitCoverValue != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[19], ( gGameExternalOptions.ubStealthTraitCoverValue * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case AMBIDEXT_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[20] ); + wcscat( apStr, atStr ); + break; + } + case MARTIALARTS_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[MARTIALARTS_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[28], ( gbSkillTraitBonus[MARTIALARTS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[29], ( gbSkillTraitBonus[MARTIALARTS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[30], ( gbSkillTraitBonus[MARTIALARTS_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[31], ( gbSkillTraitBonus[MARTIALARTS_OT] * 2 / 3 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[32], ( gbSkillTraitBonus[MARTIALARTS_OT] / 2 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[33]); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[34]); + wcscat( apStr, atStr ); + break; + } + case KNIFING_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[KNIFING_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[21], ( gbSkillTraitBonus[KNIFING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[22], ( gbSkillTraitBonus[KNIFING_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[23], ( gbSkillTraitBonus[KNIFING_OT] / 3 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[24], ( gbSkillTraitBonus[KNIFING_OT] / 2 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + break; + } + case PROF_SNIPER_OT: + { + swprintf( apStr, L"" ); + if( gbSkillTraitBonus[PROF_SNIPER_OT] != 0 ) + { + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[25], ( gbSkillTraitBonus[PROF_SNIPER_OT] * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + } + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[26], ( 10 * (fExpertLevel ? 2 : 1)), L"%"); + wcscat( apStr, atStr ); + break; + } + case CAMOUFLAGED_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPOldSkillTraitsHelpTexts[27] ); + wcscat( apStr, atStr ); + break; + } + case NO_SKILLTRAIT_OT: + { + swprintf( apStr, L"" ); + swprintf( atStr, gzIMPMajorTraitsHelpTextsNone[0] ); + wcscat( apStr, atStr ); + break; + } + } + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[bRegionNumber]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[bRegionNumber], MSYS_NO_CALLBACK ); + + return; +} +// SANDRO - Popup text windows for character +void AssignPersonnelCharacterTraitHelpText( UINT8 ubCharacterNumber ) +{ + CHAR16 apStr[ 1000 ]; + + swprintf( apStr, L"" ); + swprintf( apStr, gzIMPNewCharacterTraitsHelpTexts[ubCharacterNumber] ); + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[5]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[5], MSYS_NO_CALLBACK ); + + return; +} +// SANDRO - Popup text windows for disability +void AssignPersonnelDisabilityHelpText( UINT8 ubDisabilityNumber ) +{ + CHAR16 apStr[ 500 ]; + + swprintf( apStr, L"" ); + swprintf( apStr, gzIMPDisabilitiesHelpTexts[ubDisabilityNumber] ); + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[6]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[6], MSYS_NO_CALLBACK ); + + return; +} + +void AssignPersonnelKillsHelpText( INT32 IMercId ) +{ + CHAR16 apStr[ 1000 ]; + CHAR16 atStr[ 150 ]; + + swprintf( apStr, L"" ); + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsElites > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 0 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsElites ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsRegulars > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 1 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsRegulars ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsAdmins > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 2 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsAdmins ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsHostiles > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 3 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsHostiles ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsCreatures > 0 || fShowRecordsIfZero) + { + // WANNE: Only display the monster info, when we play with monsters! + if (gGameExternalOptions.fEnableCrepitus) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 4 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsCreatures ); + wcscat( apStr, atStr ); + } + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsTanks > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 5 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsTanks ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsOthers > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 6 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKillsOthers ); + wcscat( apStr, atStr ); + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[7]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[7], MSYS_NO_CALLBACK ); + + return; +} + +void AssignPersonnelAssistsHelpText( INT32 IMercId ) +{ + CHAR16 apStr[ 350 ]; + CHAR16 atStr[ 80 ]; + + swprintf( apStr, L"" ); + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usAssistsMercs > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 7 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usAssistsMercs ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usAssistsMilitia > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 8 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usAssistsMilitia ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usAssistsOthers > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 9 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usAssistsOthers ); + wcscat( apStr, atStr ); + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[8]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[8], MSYS_NO_CALLBACK ); + + return; +} + +void AssignPersonnelHitPercentageHelpText( INT32 IMercId ) +{ + CHAR16 apStr[ 1000 ]; + CHAR16 atStr[ 150 ]; + + swprintf( apStr, L"" ); + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usShotsFired > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 10 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usShotsFired ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usMissilesLaunched > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 11 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usMissilesLaunched ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usGrenadesThrown > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 12 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usGrenadesThrown ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usKnivesThrown > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 13 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usKnivesThrown ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usBladeAttacks > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 14 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usBladeAttacks ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usHtHAttacks > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 15 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usHtHAttacks ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usShotsHit > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 16 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usShotsHit ); + wcscat( apStr, atStr ); + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[9]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[9], MSYS_NO_CALLBACK ); + + return; +} + +void AssignPersonnelAchievementsHelpText( INT32 IMercId ) +{ + CHAR16 apStr[ 1000 ]; + CHAR16 atStr[ 80 ]; + + swprintf( apStr, L"" ); + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usLocksPicked > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 17 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usLocksPicked ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usLocksBreached > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 18 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usLocksBreached ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTrapsRemoved > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 19 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTrapsRemoved ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usExpDetonated > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 20 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usExpDetonated ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usItemsRepaired > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 21 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usItemsRepaired ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usItemsCombined > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 22 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usItemsCombined ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usItemsStolen > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 23 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usItemsStolen ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usMilitiaTrained > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 24 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usMilitiaTrained ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usMercsBandaged > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 25 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usMercsBandaged ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usSurgeriesMade > 0 || fShowRecordsIfZero) + { + if ( gGameOptions.fNewTraitSystem ) + { + switch( gSkillTraitValues.ubDONumberTraitsNeededForSurgery ) + { + case 0: + swprintf(atStr, pPersonnelRecordsHelpTexts[ 26 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usSurgeriesMade ); + wcscat( apStr, atStr ); + break; + case 1: + if ( ProfileHasSkillTrait( Menptr[IMercId].ubProfile, DOCTOR_NT ) > 0 ) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 26 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usSurgeriesMade ); + wcscat( apStr, atStr ); + } + break; + case 2: + if ( ProfileHasSkillTrait( Menptr[IMercId].ubProfile, DOCTOR_NT ) > 1 ) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 26 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usSurgeriesMade ); + wcscat( apStr, atStr ); + } + break; + default: + break; + } + } + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usNPCsDiscovered > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 27 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usNPCsDiscovered ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usSectorsDiscovered > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 28 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usSectorsDiscovered ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usAmbushesExperienced > 0 || fShowRecordsIfZero) + { + if ( gGameOptions.fNewTraitSystem && ( ProfileHasSkillTrait( Menptr[IMercId].ubProfile, SCOUTING_NT ) > 0 ) ) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 29 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usAmbushesExperienced ); + wcscat( apStr, atStr ); + } + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.ubQuestsHandled > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 30 ], gMercProfiles[Menptr[IMercId].ubProfile].records.ubQuestsHandled ); + wcscat( apStr, atStr ); + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[10]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[10], MSYS_NO_CALLBACK ); + + return; +} + +void AssignPersonnelBattlesHelpText( INT32 IMercId ) +{ + CHAR16 apStr[ 400 ]; + CHAR16 atStr[ 80 ]; + + swprintf( apStr, L"" ); + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usBattlesTactical > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 31 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usBattlesTactical ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usBattlesAutoresolve > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 32 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usBattlesAutoresolve ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usBattlesRetreated > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 33 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usBattlesRetreated ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usAmbushesExperienced > 0 || fShowRecordsIfZero) + { + if (!( gGameOptions.fNewTraitSystem && ( ProfileHasSkillTrait( Menptr[IMercId].ubProfile, SCOUTING_NT ) > 0 ) )) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 34 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usAmbushesExperienced ); + wcscat( apStr, atStr ); + } + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usLargestBattleFought > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 35 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usLargestBattleFought ); + wcscat( apStr, atStr ); + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[11]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[11], MSYS_NO_CALLBACK ); + + return; +} + +void AssignPersonnelWoundsHelpText( INT32 IMercId ) +{ + CHAR16 apStr[ 500 ]; + CHAR16 atStr[ 80 ]; + + swprintf( apStr, L"" ); + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedShot > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 36 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedShot ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedStabbed > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 37 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedStabbed ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedPunched > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 38 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedPunched ); + wcscat( apStr, atStr ); + } + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedBlasted > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 39 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesWoundedBlasted ); + wcscat( apStr, atStr ); + } + + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesSurgeryUndergoed > 0 || fShowRecordsIfZero) + { + if ( gGameOptions.fNewTraitSystem ) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 41 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesSurgeryUndergoed ); + wcscat( apStr, atStr ); + } + } + + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usFacilityAccidents > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 42 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usFacilityAccidents ); + wcscat( apStr, atStr ); + } + + // WANNE: Moved to the end + if (gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesStatDamaged > 0 || fShowRecordsIfZero) + { + swprintf(atStr, pPersonnelRecordsHelpTexts[ 40 ], gMercProfiles[Menptr[IMercId].ubProfile].records.usTimesStatDamaged ); + wcscat( apStr, atStr ); + } + + // Set region help text + SetRegionFastHelpText( &(gSkillTraitHelpTextRegion[12]), apStr ); + SetRegionHelpEndCallback( &gSkillTraitHelpTextRegion[12], MSYS_NO_CALLBACK ); + + return; +} + +INT8 CalculateMercsAchievemntPercentage( INT32 IMercId ) +{ + SOLDIERTYPE *pTeamSoldier; + INT32 cnt=0; + UINT32 uiMercPoints, uiMercPercentage; + unsigned long ulTotalMercPoints = 0; + + // run through active soldiers + for ( cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++) + { + pTeamSoldier = MercPtrs[cnt]; + // Only count stats of merc (not vehicles) + if ( !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !AM_A_ROBOT( pTeamSoldier ) ) + { + if( pTeamSoldier->bActive && pTeamSoldier->stats.bLife > 0 && pTeamSoldier->ubProfile != 0 ) + { + // get total value of all mercs, adjust by importance + ulTotalMercPoints += + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usLocksPicked ) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usLocksBreached ) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usTrapsRemoved *3/2) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usExpDetonated *3/2) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usItemsRepaired /2) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usItemsCombined *2) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usItemsStolen ) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usMercsBandaged *3/4) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usSurgeriesMade *3/2) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usNPCsDiscovered *4/3) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usSectorsDiscovered ) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.usMilitiaTrained /4) + + + ( gMercProfiles[ pTeamSoldier->ubProfile ].records.ubQuestsHandled *2); + + } + } + } + + // Now get points of our mercs + uiMercPoints = + ( gMercProfiles[ IMercId ].records.usLocksPicked ) + + + ( gMercProfiles[ IMercId ].records.usLocksBreached ) + + + ( gMercProfiles[ IMercId ].records.usTrapsRemoved *3/2) + + + ( gMercProfiles[ IMercId ].records.usExpDetonated *3/2) + + + ( gMercProfiles[ IMercId ].records.usItemsRepaired /2) + + + ( gMercProfiles[ IMercId ].records.usItemsCombined *2) + + + ( gMercProfiles[ IMercId ].records.usItemsStolen ) + + + ( gMercProfiles[ IMercId ].records.usMercsBandaged *3/4) + + + ( gMercProfiles[ IMercId ].records.usSurgeriesMade *3/2) + + + ( gMercProfiles[ IMercId ].records.usNPCsDiscovered *4/3) + + + ( gMercProfiles[ IMercId ].records.usSectorsDiscovered ) + + + ( gMercProfiles[ IMercId ].records.usMilitiaTrained /4) + + + ( gMercProfiles[ IMercId ].records.ubQuestsHandled *2); + + // Calculate percentage + if( ulTotalMercPoints != 0 ) + { + uiMercPercentage = (UINT32)(((100 * uiMercPoints)/ulTotalMercPoints)+ 0.5); + + uiMercPercentage = min( 100, uiMercPercentage ); + + return( (UINT8)(uiMercPercentage) ); + } + else + return( 0 ); +} diff --git a/Laptop/personnel.h b/Laptop/personnel.h index 2ae61512..bfce1079 100644 --- a/Laptop/personnel.h +++ b/Laptop/personnel.h @@ -9,6 +9,49 @@ // delay for change in ATM mode #define DELAY_PER_MODE_CHANGE_IN_ATM 2000 +//enums for the pPersonnelScreenStrings[] +enum +{ + PRSNL_TXT_HEALTH, // 0 HEALTH OF MERC + PRSNL_TXT_AGILITY, + PRSNL_TXT_DEXTERITY, + PRSNL_TXT_STRENGTH, + PRSNL_TXT_LEADERSHIP, + PRSNL_TXT_WISDOM, // 5 + PRSNL_TXT_EXP_LVL, // EXPERIENCE LEVEL + PRSNL_TXT_MARKSMANSHIP, + PRSNL_TXT_MECHANICAL, + PRSNL_TXT_EXPLOSIVES, + PRSNL_TXT_MEDICAL, // 10 + PRSNL_TXT_MED_DEPOSIT, // AMOUNT OF MEDICAL DEPOSIT PUT DOWN ON THE MERC + PRSNL_TXT_CURRENT_CONTRACT, // COST OF CURRENT CONTRACT + PRSNL_TXT_KILLS, // NUMBER OF KILLS BY MERC + PRSNL_TXT_ASSISTS, // NUMBER OF ASSISTS ON KILLS BY MERC + PRSNL_TXT_DAILY_COST, // 15 DAILY COST OF MERC + PRSNL_TXT_TOTAL_COST, // TOTAL COST OF MERC + PRSNL_TXT_CONTRACT, // COST OF CURRENT CONTRACT + PRSNL_TXT_TOTAL_SERVICE, // TOTAL SERVICE RENDERED BY MERC + PRSNL_TXT_UNPAID_AMOUNT, // AMOUNT LEFT ON MERC MERC TO BE PAID + PRSNL_TXT_HIT_PERCENTAGE, // 20 PERCENTAGE OF SHOTS THAT HIT TARGET + PRSNL_TXT_BATTLES, // NUMBER OF BATTLES FOUGHT + PRSNL_TXT_TIMES_WOUNDED, // NUMBER OF TIMES MERC HAS BEEN WOUNDED + PRSNL_TXT_SKILLS, + PRSNL_TXT_NOSKILLS, + PRSNL_TXT_ACHIEVEMNTS, + TEXT_NUM_PRSNL, +}; + +// departed states +enum +{ + DEPARTED_DEAD = 0, + DEPARTED_FIRED, + DEPARTED_OTHER, + DEPARTED_MARRIED, + DEPARTED_CONTRACT_EXPIRED, + DEPARTED_QUIT, + TEXT_NUM_DEPARTED +}; void GameInitPersonnel(); void EnterPersonnel(); diff --git a/Loading Screen.cpp b/Loading Screen.cpp index 1a9dba07..300b01e3 100644 --- a/Loading Screen.cpp +++ b/Loading Screen.cpp @@ -16,11 +16,22 @@ #include "font.h" #include "render dirty.h" #endif +#include "Strategic Movement.h" +#include "UndergroundInit.h" +#include extern HVSURFACE ghFrameBuffer; +extern BOOLEAN gfSchedulesHosed; -STR8 szSectorMap[MAP_WORLD_Y][MAP_WORLD_X] = { - {"N", "N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N"}, + +UINT8 gubLastLoadingScreenID = LOADINGSCREEN_NOTHING; +BOOLEAN bShowSmallImage = FALSE; +SECTOR_LOADSCREENS gSectorLoadscreens[MAX_SECTOR_LOADSCREENS]; + +static INT16 requestedX, requestedY, requestedZ; +static STR8 szSector; +static STR8 szSectorMap[MAP_WORLD_Y][MAP_WORLD_X] = { + {"N", "N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" , "N" , "N" , "N" , "N" , "N" , "N" , "N" ,"N"}, {"N", "A1","A2","A3","A4","A5","A6","A7","A8","A9","A10","A11","A12","A13","A14","A15","A16" ,"N"}, {"N", "B1","B2","B3","B4","B5","B6","B7","B8","B9","B10","B11","B12","B13","B14","B15","B16" ,"N"}, @@ -39,470 +50,166 @@ STR8 szSectorMap[MAP_WORLD_Y][MAP_WORLD_X] = { {"N", "O1","O2","O3","O4","O5","O6","O7","O8","O9","O10","O11","O12","O13","O14","O15","O16" ,"N"}, {"N", "P1","P2","P3","P4","P5","P6","P7","P8","P9","P10","P11","P12","P13","P14","P15","P16" ,"N"}, - {"N","N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N"} - }; + {"N", "N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" ,"N" , "N" , "N" , "N" , "N" , "N" , "N" , "N" ,"N"}, +}; -UINT8 gubLastLoadingScreenID = LOADINGSCREEN_NOTHING; -STR8 szSector; -BOOLEAN bShowSmallImage = FALSE; - -SECTOR_LOADSCREENS gSectorLoadscreens[MAX_SECTOR_LOADSCREENS]; +// Map LOADINGSCREEN_NOTHING, ..., LOADINGSCREEN_NIGHTBALIME (see enum in header file) +// to some strings which will be used to create the actual filename +// (by appending e.g. "_800x600.sti" or something). +// This is only used when NOT loading them from SectorLoadscreens.xml. +static STR8 LoadScreenNames[LOADINGSCREEN_NIGHTBALIME+1] = +{ + "LS_Heli", + "LS_DayGeneric", + "LS_DayTown1", + "LS_DayTown2", + "LS_DayWild", + "LS_DayTropical", + "LS_DayForest", + "LS_DayDesert", + "LS_DayPalace", + "LS_NightGeneric", + "LS_NightWild", + "LS_NightTown1", + "LS_NightTown2", + "LS_NightForest", + "LS_NightTropical", + "LS_NightDesert", + "LS_NightPalace", + "LS_Heli", + "LS_Basement", + "LS_Mine", + "LS_Cave", + "LS_DayPine", + "LS_NightPine", + "LS_DayMilitary", + "LS_NightMilitary", + "LS_DaySAM", + "LS_NightSAM", + "LS_DayPrison", + "LS_NightPrison", + "LS_DayHospital", + "LS_NightHospital", + "LS_DayAirport", + "LS_NightAirport", + "LS_DayLab", + "LS_NightLab", + "LS_DayOmerta", + "LS_NightOmerta", + "LS_DayChitzena", + "LS_NightChitzena", + "LS_DayMine", + "LS_NightMine", + "LS_DayBalime", + "LS_NightBalime", +}; //returns the UINT8 ID for the specified sector. -UINT8 GetLoadScreenID( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) +// Which for sectors above ground is one of { HELI, DAY, NIGHT } +// if gGameExternalOptions.gfUseExternalLoadscreens. +// Otherwise and for underground sectors this is the actual loadsceen ID. +UINT8 GetLoadScreenID(INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ) { - SECTORINFO *pSector; - UINT8 ubSectorID; - BOOLEAN fNight = FALSE; + const UINT8 ubSectorID = SECTOR( sSectorX, sSectorY ); + const BOOLEAN fNight = NightTime(); //before 5AM or after 9PM - ubSectorID = SECTOR( sSectorX, sSectorY ); - if( NightTime() ) //before 5AM or after 9PM + requestedX = sSectorX; requestedY = sSectorY; requestedZ = bSectorZ; + + /* User made system - BEGIN */ + if (gGameExternalOptions.gfUseExternalLoadscreens) { - fNight = TRUE; - } + if (bSectorZ != 0) + { + szSector = szSectorMap [sSectorY][sSectorX]; // not really necessary, I guess + return UNDERGROUND; + } - // Which map layer? (ground, basement 1-3)? - switch( bSectorZ ) + switch( ubSectorID ) + { + case SEC_A9: + szSector = "A9"; + return DidGameJustStart() ? HELI : (fNight ? NIGHT : DAY); + default: + szSector = szSectorMap [sSectorY][sSectorX]; + return fNight ? NIGHT : DAY; + } + } /* WANNE: User made System - END */ + + /* WANNE: Sir-Tech System - BEGIN */ + else { - // Ground - case 0: - - /* User made system - BEGIN */ - if (gGameExternalOptions.gfUseExternalLoadscreens) - { - switch( ubSectorID ) - { - case SEC_A1: - case SEC_A2: - case SEC_A3: - case SEC_A4: - case SEC_A5: - case SEC_A6: - case SEC_A7: - case SEC_A8: - // case SEC_A9: // Start sector - case SEC_A10: - case SEC_A11: - case SEC_A12: - case SEC_A13: - case SEC_A14: - case SEC_A15: - case SEC_A16: - case SEC_B1: - case SEC_B2: - case SEC_B3: - case SEC_B4: - case SEC_B5: - case SEC_B6: - case SEC_B7: - case SEC_B8: - case SEC_B9: - case SEC_B10: - case SEC_B11: - case SEC_B12: - case SEC_B13: - case SEC_B14: - case SEC_B15: - case SEC_B16: - case SEC_C1: - case SEC_C2: - case SEC_C3: - case SEC_C4: - case SEC_C5: - case SEC_C6: - case SEC_C7: - case SEC_C8: - case SEC_C9: - case SEC_C10: - case SEC_C11: - case SEC_C12: - case SEC_C13: - case SEC_C14: - case SEC_C15: - case SEC_C16: - case SEC_D1: - case SEC_D2: - case SEC_D3: - case SEC_D4: - case SEC_D5: - case SEC_D6: - case SEC_D7: - case SEC_D8: - case SEC_D9: - case SEC_D10: - case SEC_D11: - case SEC_D12: - case SEC_D13: - case SEC_D14: - case SEC_D15: - case SEC_D16: - case SEC_E1: - case SEC_E2: - case SEC_E3: - case SEC_E4: - case SEC_E5: - case SEC_E6: - case SEC_E7: - case SEC_E8: - case SEC_E9: - case SEC_E10: - case SEC_E11: - case SEC_E12: - case SEC_E13: - case SEC_E14: - case SEC_E15: - case SEC_E16: - case SEC_F1: - case SEC_F2: - case SEC_F3: - case SEC_F4: - case SEC_F5: - case SEC_F6: - case SEC_F7: - case SEC_F8: - case SEC_F9: - case SEC_F10: - case SEC_F11: - case SEC_F12: - case SEC_F13: - case SEC_F14: - case SEC_F15: - case SEC_F16: - case SEC_G1: - case SEC_G2: - case SEC_G3: - case SEC_G4: - case SEC_G5: - case SEC_G6: - case SEC_G7: - case SEC_G8: - case SEC_G9: - case SEC_G10: - case SEC_G11: - case SEC_G12: - case SEC_G13: - case SEC_G14: - case SEC_G15: - case SEC_G16: - case SEC_H1: - case SEC_H2: - case SEC_H3: - case SEC_H4: - case SEC_H5: - case SEC_H6: - case SEC_H7: - case SEC_H8: - case SEC_H9: - case SEC_H10: - case SEC_H11: - case SEC_H12: - case SEC_H13: - case SEC_H14: - case SEC_H15: - case SEC_H16: - case SEC_I1: - case SEC_I2: - case SEC_I3: - case SEC_I4: - case SEC_I5: - case SEC_I6: - case SEC_I7: - case SEC_I8: - case SEC_I9: - case SEC_I10: - case SEC_I11: - case SEC_I12: - case SEC_I13: - case SEC_I14: - case SEC_I15: - case SEC_I16: - case SEC_J1: - case SEC_J2: - case SEC_J3: - case SEC_J4: - case SEC_J5: - case SEC_J6: - case SEC_J7: - case SEC_J8: - case SEC_J9: - case SEC_J10: - case SEC_J11: - case SEC_J12: - case SEC_J13: - case SEC_J14: - case SEC_J15: - case SEC_J16: - case SEC_K1: - case SEC_K2: - case SEC_K3: - case SEC_K4: - case SEC_K5: - case SEC_K6: - case SEC_K7: - case SEC_K8: - case SEC_K9: - case SEC_K10: - case SEC_K11: - case SEC_K12: - case SEC_K13: - case SEC_K14: - case SEC_K15: - case SEC_K16: - case SEC_L1: - case SEC_L2: - case SEC_L3: - case SEC_L4: - case SEC_L5: - case SEC_L6: - case SEC_L7: - case SEC_L8: - case SEC_L9: - case SEC_L10: - case SEC_L11: - case SEC_L12: - case SEC_L13: - case SEC_L14: - case SEC_L15: - case SEC_L16: - case SEC_M1: - case SEC_M2: - case SEC_M3: - case SEC_M4: - case SEC_M5: - case SEC_M6: - case SEC_M7: - case SEC_M8: - case SEC_M9: - case SEC_M10: - case SEC_M11: - case SEC_M12: - case SEC_M13: - case SEC_M14: - case SEC_M15: - case SEC_M16: - case SEC_N1: - case SEC_N2: - case SEC_N3: - case SEC_N4: - case SEC_N5: - case SEC_N6: - case SEC_N7: - case SEC_N8: - case SEC_N9: - case SEC_N10: - case SEC_N11: - case SEC_N12: - case SEC_N13: - case SEC_N14: - case SEC_N15: - case SEC_N16: - case SEC_O1: - case SEC_O2: - case SEC_O3: - case SEC_O4: - case SEC_O5: - case SEC_O6: - case SEC_O7: - case SEC_O8: - case SEC_O9: - case SEC_O10: - case SEC_O11: - case SEC_O12: - case SEC_O13: - case SEC_O14: - case SEC_O15: - case SEC_O16: - case SEC_P1: - case SEC_P2: - case SEC_P3: - case SEC_P4: - case SEC_P5: - case SEC_P6: - case SEC_P7: - case SEC_P8: - case SEC_P9: - case SEC_P10: - case SEC_P11: - case SEC_P12: - case SEC_P13: - case SEC_P14: - case SEC_P15: - case SEC_P16: - szSector = szSectorMap [sSectorY][sSectorX]; - - if( fNight ) - { - return NIGHT; - } - else - { - return DAY; - } - - case SEC_A9: - szSector = "A9"; - - if( !DidGameJustStart() ) - { - if( fNight ) - { - return NIGHT; - } - else - { - return DAY; - } - } - else - { - return HELI; - } - } - } /* WANNE: User made System - END */ - - /* WANNE: Sir-Tech System - BEGIN */ - else + // Which map layer? (ground, basement 1-3)? + switch( bSectorZ ) + { + // Ground + case 0: { switch( ubSectorID ) { case SEC_A2: case SEC_B2: - if( fNight ) - return LOADINGSCREEN_NIGHTCHITZENA; - return LOADINGSCREEN_DAYCHITZENA; + return fNight ? LOADINGSCREEN_NIGHTCHITZENA : LOADINGSCREEN_DAYCHITZENA; case SEC_A9: - if( !DidGameJustStart() ) - { - if( fNight ) - return LOADINGSCREEN_NIGHTOMERTA; - return LOADINGSCREEN_DAYOMERTA; - } - return LOADINGSCREEN_HELI; + return DidGameJustStart() ? LOADINGSCREEN_HELI : + (fNight ? LOADINGSCREEN_NIGHTOMERTA : LOADINGSCREEN_DAYOMERTA); case SEC_A10: - if( fNight ) - return LOADINGSCREEN_NIGHTOMERTA; - return LOADINGSCREEN_DAYOMERTA; + return fNight ? LOADINGSCREEN_NIGHTOMERTA : LOADINGSCREEN_DAYOMERTA; case SEC_P3: - if( fNight ) - return LOADINGSCREEN_NIGHTPALACE; - return LOADINGSCREEN_DAYPALACE; + return fNight ? LOADINGSCREEN_NIGHTPALACE : LOADINGSCREEN_DAYPALACE; case SEC_H13: case SEC_H14: //military installations case SEC_I13: case SEC_N7: - if( fNight ) - return LOADINGSCREEN_NIGHTMILITARY; - return LOADINGSCREEN_DAYMILITARY; + return fNight ? LOADINGSCREEN_NIGHTMILITARY : LOADINGSCREEN_DAYMILITARY; case SEC_K4: - if( fNight ) - return LOADINGSCREEN_NIGHTLAB; - return LOADINGSCREEN_DAYLAB; + return fNight ? LOADINGSCREEN_NIGHTLAB : LOADINGSCREEN_DAYLAB; case SEC_J9: - if( fNight ) - return LOADINGSCREEN_NIGHTPRISON; - return LOADINGSCREEN_DAYPRISON; + return fNight ? LOADINGSCREEN_NIGHTPRISON : LOADINGSCREEN_DAYPRISON; case SEC_D2: case SEC_D15: case SEC_I8: case SEC_N4: - if( fNight ) - return LOADINGSCREEN_NIGHTSAM; - return LOADINGSCREEN_DAYSAM; + return fNight ? LOADINGSCREEN_NIGHTSAM : LOADINGSCREEN_DAYSAM; case SEC_F8: - if( fNight ) - return LOADINGSCREEN_NIGHTHOSPITAL; - return LOADINGSCREEN_DAYHOSPITAL; + return fNight ? LOADINGSCREEN_NIGHTHOSPITAL : LOADINGSCREEN_DAYHOSPITAL; case SEC_B13: case SEC_N3: - if( fNight ) - return LOADINGSCREEN_NIGHTAIRPORT; - return LOADINGSCREEN_DAYAIRPORT; + return fNight ? LOADINGSCREEN_NIGHTAIRPORT : LOADINGSCREEN_DAYAIRPORT; case SEC_L11: case SEC_L12: - if( fNight ) - return LOADINGSCREEN_NIGHTBALIME; - return LOADINGSCREEN_DAYBALIME; + return fNight ? LOADINGSCREEN_NIGHTBALIME : LOADINGSCREEN_DAYBALIME; case SEC_H3: case SEC_H8: case SEC_D4: - if( fNight ) - return LOADINGSCREEN_NIGHTMINE; - return LOADINGSCREEN_DAYMINE; + return fNight ? LOADINGSCREEN_NIGHTMINE : LOADINGSCREEN_DAYMINE; } - pSector = &SectorInfo[ ubSectorID ]; - switch( pSector->ubTraversability[ 4 ] ) + SECTORINFO *pSector = &SectorInfo[ ubSectorID ]; + switch( pSector->ubTraversability[ THROUGH_STRATEGIC_MOVE ] ) { case TOWN: - if( fNight ) - { - if( Random( 2 ) ) - { - return LOADINGSCREEN_NIGHTTOWN2; - } - else - { - return LOADINGSCREEN_NIGHTTOWN1; - } - } - else - { - if( Random( 2 ) ) - { - return LOADINGSCREEN_DAYTOWN2; - } - else - { - return LOADINGSCREEN_DAYTOWN1; - } - } + return Random(2) > 0 ? + (fNight ? LOADINGSCREEN_NIGHTTOWN2 : LOADINGSCREEN_DAYTOWN2) : + (fNight ? LOADINGSCREEN_NIGHTTOWN1 : LOADINGSCREEN_DAYTOWN1); case SAND: case SAND_ROAD: - if( fNight ) - { - return LOADINGSCREEN_NIGHTDESERT; - } - else - { - return LOADINGSCREEN_DAYDESERT; - } + return fNight ? LOADINGSCREEN_NIGHTDESERT : LOADINGSCREEN_DAYDESERT; case FARMLAND: case FARMLAND_ROAD: case ROAD: - if( fNight ) - { - return LOADINGSCREEN_NIGHTGENERIC; - } - else - { - return LOADINGSCREEN_DAYGENERIC; - } + return fNight ? LOADINGSCREEN_NIGHTGENERIC : LOADINGSCREEN_DAYGENERIC; case PLAINS: case SPARSE: case HILLS: case PLAINS_ROAD: case SPARSE_ROAD: case HILLS_ROAD: - if( fNight ) - { - return LOADINGSCREEN_NIGHTWILD; - } - else - { - return LOADINGSCREEN_DAYWILD; - } + return fNight ? LOADINGSCREEN_NIGHTWILD : LOADINGSCREEN_DAYWILD; case DENSE: case SWAMP: case SWAMP_ROAD: case DENSE_ROAD: - if( fNight ) - { - return LOADINGSCREEN_NIGHTFOREST; - } - else - { - return LOADINGSCREEN_DAYFOREST; - } + return fNight ? LOADINGSCREEN_NIGHTFOREST : LOADINGSCREEN_DAYFOREST; case TROPICS: case TROPICS_ROAD: case WATER: @@ -510,124 +217,98 @@ UINT8 GetLoadScreenID( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) case EW_RIVER: case COASTAL: case COASTAL_ROAD: - if( fNight ) - { - return LOADINGSCREEN_NIGHTTROPICAL; - } - else - { - return LOADINGSCREEN_DAYTROPICAL; - } + return fNight ? LOADINGSCREEN_NIGHTTROPICAL : LOADINGSCREEN_DAYTROPICAL; default: Assert( 0 ); - if( fNight ) - { - return LOADINGSCREEN_NIGHTGENERIC; - } - else - { - return LOADINGSCREEN_DAYGENERIC; - } + return fNight ? LOADINGSCREEN_NIGHTGENERIC : LOADINGSCREEN_DAYGENERIC; } - break; - /* WANNE: Sir-Tech System */ + } + // Basement Level 1 + case 1: + switch( ubSectorID ) + { + case SEC_A10: //Miguel's basement + case SEC_I13: //Alma prison dungeon + case SEC_J9: //Tixa prison dungeon + case SEC_K4: //Orta weapons plant + case SEC_O3: //Meduna + case SEC_P3: //Meduna + return LOADINGSCREEN_BASEMENT; + default: //rest are mines + return LOADINGSCREEN_MINE; + } + // Basement Level 2 and 3 + case 2: + case 3: + //all level 2 and 3 maps are caves! + return LOADINGSCREEN_CAVE; + default: + // shouldn't ever happen + Assert( FALSE ); + return fNight ? LOADINGSCREEN_NIGHTGENERIC : LOADINGSCREEN_DAYGENERIC; } - - // Basement Level 1 - case 1: - switch( ubSectorID ) - { - case SEC_A10: //Miguel's basement - case SEC_I13: //Alma prison dungeon - case SEC_J9: //Tixa prison dungeon - case SEC_K4: //Orta weapons plant - case SEC_O3: //Meduna - case SEC_P3: //Meduna - return LOADINGSCREEN_BASEMENT; - default: //rest are mines - return LOADINGSCREEN_MINE; - } - break; - // Basement Level 2 and 3 - case 2: - case 3: - //all level 2 and 3 maps are caves! - return LOADINGSCREEN_CAVE; - default: - // shouldn't ever happen - Assert( FALSE ); - - if( fNight ) - { - return LOADINGSCREEN_NIGHTGENERIC; - } - else - { - return LOADINGSCREEN_DAYGENERIC; - } - } + + } /* WANNE: Sir-Tech System - END */ } -extern BOOLEAN gfSchedulesHosed; +static void BuildLoadscreenFilename(std::string& dst, const char* path, int resolution, const char* ext) +{ + if (path) + dst.append(path); + + switch (resolution) + { + case 1: + dst.append("_800x600"); + break; + case 2: + dst.append("_1024x768"); + break; + default: + break; + } + + if (ext) + { + dst.append("."); + dst.append(ext); + } + else + // This might suck later on. If it does, remove it. + dst.append(".sti"); +} //sets up the loadscreen with specified ID, and draws it to the FRAME_BUFFER, //and refreshing the screen with it. void DisplayLoadScreenWithID( UINT8 ubLoadScreenID ) { - VSURFACE_DESC vs_desc; + VSURFACE_DESC vs_desc = {}; HVSURFACE hVSurface; UINT32 uiLoadScreen; - STRING512 smallImage; - BOOLEAN fExternalLS = FALSE; + STRING512 smallImage = {0}; bShowSmallImage = FALSE; - vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE; + vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE | VSURFACE_CREATE_FROMPNG_FALLBACK; - if (gGameExternalOptions.gfUseExternalLoadscreens) - { - if ((ubLoadScreenID == HELI || ubLoadScreenID == DAY || ubLoadScreenID == DAY_ALT || - ubLoadScreenID == NIGHT || ubLoadScreenID == NIGHT_ALT) && szSector != NULL) - { - fExternalLS = TRUE; - } - else - { - fExternalLS = FALSE; - } - } - else - { - if ((ubLoadScreenID == HELI || ubLoadScreenID == DAY || ubLoadScreenID == DAY_ALT || - ubLoadScreenID == NIGHT || ubLoadScreenID == NIGHT_ALT) && szSector != NULL) - { - fExternalLS = TRUE; - } - else - { - fExternalLS = FALSE; - } - } + const BOOLEAN fExternalLS = (szSector != NULL) && ((DAY <= ubLoadScreenID && ubLoadScreenID <= NIGHT_ALT) || (ubLoadScreenID == UNDERGROUND)); + if (fExternalLS) { // Get the image path - char szImagePath[80]; - char szImageFormat[5]; - char szFullImagePath[80]; - - // WDS - Fix: Init strings 7/16/2007 - szImagePath[0] = 0; - szImageFormat[0] = 0; - szFullImagePath[0] = 0; + std::string imagePath; + std::string imageFormat; // Start screen if (ubLoadScreenID == HELI) { - strncpy(szImagePath, gSectorLoadscreens[0].szDay, 80); - - strncpy(szImageFormat, ".", MAX_IMAGE_FORMAT_CHARS); - strcat(szImageFormat, gSectorLoadscreens[0].szImageFormat); + imagePath = gSectorLoadscreens[0].szDay; + imageFormat = gSectorLoadscreens[0].szImageFormat; + } + else if (ubLoadScreenID == UNDERGROUND) + { + g_luaUnderground.GetLoadscreen(requestedX, requestedY, requestedZ, imagePath, imageFormat); } else { @@ -636,53 +317,38 @@ void DisplayLoadScreenWithID( UINT8 ubLoadScreenID ) // We found the sector if (strcmp(gSectorLoadscreens[i].szLocation, szSector) == 0) { - strncpy(szImageFormat, ".", MAX_IMAGE_FORMAT_CHARS); - - strcat(szImageFormat, gSectorLoadscreens[i].szImageFormat); + imageFormat = gSectorLoadscreens[i].szImageFormat; BOOLEAN fAlternate = gSectorLoadscreens[i].RandomAltSector; - if (fAlternate) + if (fAlternate && (Random(2) > 0)) { - // Day - if (ubLoadScreenID == DAY) + switch (ubLoadScreenID) { - if( Random( 2 ) ) - { - ubLoadScreenID = DAY; - } - else - { + case DAY: ubLoadScreenID = DAY_ALT; - } - } - // Night - else - { - if( Random( 2 ) ) - { - ubLoadScreenID = NIGHT; - } - else - { + break; + case NIGHT: ubLoadScreenID = NIGHT_ALT; - } + break; + default: + break; } } switch (ubLoadScreenID) { case DAY: - strncpy(szImagePath, gSectorLoadscreens[i].szDay, MAX_IMAGE_PATH_CHARS); + imagePath = gSectorLoadscreens[i].szDay; break; case DAY_ALT: - strncpy(szImagePath, gSectorLoadscreens[i].szDayAlt, MAX_IMAGE_PATH_CHARS); + imagePath = gSectorLoadscreens[i].szDayAlt; break; case NIGHT: - strncpy(szImagePath, gSectorLoadscreens[i].szNight, MAX_IMAGE_PATH_CHARS); + imagePath = gSectorLoadscreens[i].szNight; break; case NIGHT_ALT: - strncpy(szImagePath, gSectorLoadscreens[i].szNightAlt, MAX_IMAGE_PATH_CHARS); + imagePath = gSectorLoadscreens[i].szNight; break; } break; @@ -691,738 +357,36 @@ void DisplayLoadScreenWithID( UINT8 ubLoadScreenID ) } // Small image: 640x480 - strncpy(szFullImagePath, szImagePath, 80); - strcat(szFullImagePath, szImageFormat); - strcpy(smallImage,szFullImagePath); + std::string strSmallImage; + BuildLoadscreenFilename(strSmallImage, imagePath.c_str(), 0, imageFormat.c_str()); + strSmallImage.copy(smallImage, sizeof(smallImage)-1); // Actual image, depending on the resolution - if (iResolution == 1) - { - strncpy(szFullImagePath, szImagePath, 80); - strcat(szFullImagePath, "_800x600"); - strcat(szFullImagePath, szImageFormat); - } - else if (iResolution == 2) - { - strncpy(szFullImagePath, szImagePath, 80); - strcat(szFullImagePath, "_1024x768"); - strcat(szFullImagePath, szImageFormat); - } - - strcpy(vs_desc.ImageFile,szFullImagePath); + std::string strBigImage; + BuildLoadscreenFilename(strBigImage, imagePath.c_str(), iResolution, imageFormat.c_str()); + strBigImage.copy(vs_desc.ImageFile, sizeof(vs_desc.ImageFile)-1); } else { - switch( ubLoadScreenID ) - { - case LOADINGSCREEN_NOTHING: - strcpy(smallImage, "LOADSCREENS\\LS_Heli.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli_1024x768.sti"); - } - break; - case LOADINGSCREEN_DAYGENERIC: - strcpy(smallImage, "LOADSCREENS\\LS_DayGeneric.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayGeneric.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayGeneric_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayGeneric_1024x768.sti"); - } - break; - case LOADINGSCREEN_DAYTOWN1: - strcpy(smallImage, "LOADSCREENS\\LS_DayTown1.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTown1.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTown1_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTown1_1024x768.sti"); - } - break; - case LOADINGSCREEN_DAYTOWN2: - strcpy(smallImage, "LOADSCREENS\\LS_DayTown2.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTown2.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTown2_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTown2_1024x768.sti"); - } + std::string strSmallImage("LOADSCREENS\\"); + std::string strBigImage("LOADSCREENS\\"); - break; - case LOADINGSCREEN_DAYWILD: - strcpy(smallImage, "LOADSCREENS\\LS_DayWild.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayWild.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayWild_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayWild_1024x768.sti"); - } + if (LOADINGSCREEN_NOTHING <= ubLoadScreenID && ubLoadScreenID <= LOADINGSCREEN_NIGHTBALIME) + { + BuildLoadscreenFilename(strSmallImage, LoadScreenNames[ubLoadScreenID], 0, "sti"); + BuildLoadscreenFilename(strBigImage, LoadScreenNames[ubLoadScreenID], iResolution, "sti"); + } + else + { + // for some reason the heli screen is the default + BuildLoadscreenFilename(strSmallImage, LoadScreenNames[0], 0, "sti"); + BuildLoadscreenFilename(strBigImage, LoadScreenNames[0], iResolution, "sti"); + } - break; - case LOADINGSCREEN_DAYTROPICAL: - strcpy(smallImage, "LOADSCREENS\\LS_DayTropical.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTropical.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTropical_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayTropical_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYFOREST: - strcpy(smallImage, "LOADSCREENS\\LS_DayForest.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayForest.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayForest_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayForest_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYDESERT: - strcpy(smallImage, "LOADSCREENS\\LS_DayDesert.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayDesert.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayDesert_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayDesert_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYPALACE: - strcpy(smallImage, "LOADSCREENS\\LS_DayPalace.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPalace.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPalace_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPalace_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTGENERIC: - strcpy(smallImage, "LOADSCREENS\\LS_NightGeneric.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightGeneric.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightGeneric_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightGeneric_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTWILD: - strcpy(smallImage, "LOADSCREENS\\LS_NightWild.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightWild.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightWild_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightWild_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTTOWN1: - strcpy(smallImage, "LOADSCREENS\\LS_NightTown1.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTown1.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTown1_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTown1_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTTOWN2: - strcpy(smallImage, "LOADSCREENS\\LS_NightTown2.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTown2.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTown2_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTown2_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTFOREST: - strcpy(smallImage, "LOADSCREENS\\LS_NightForest.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightForest.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightForest_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightForest_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTTROPICAL: - strcpy(smallImage, "LOADSCREENS\\LS_NightTropical.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTropical.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTropical_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightTropical_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTDESERT: - strcpy(smallImage, "LOADSCREENS\\LS_NightDesert.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightDesert.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightDesert_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightDesert_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTPALACE: - strcpy(smallImage, "LOADSCREENS\\LS_NightPalace.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPalace.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPalace_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPalace_1024x768.sti"); - } - - break; - case LOADINGSCREEN_HELI: - strcpy(smallImage, "LOADSCREENS\\LS_Heli.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli_1024x768.sti"); - } - - break; - case LOADINGSCREEN_BASEMENT: - strcpy(smallImage, "LOADSCREENS\\LS_Basement.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Basement.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Basement_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Basement_1024x768.sti"); - } - - break; - case LOADINGSCREEN_MINE: - strcpy(smallImage, "LOADSCREENS\\LS_Mine.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Mine.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Mine_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Mine_1024x768.sti"); - } - - break; - case LOADINGSCREEN_CAVE: - strcpy(smallImage, "LOADSCREENS\\LS_Cave.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Cave.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Cave_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Cave_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYPINE: - strcpy(smallImage, "LOADSCREENS\\LS_DayPine.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPine.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPine_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPine_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTPINE: - strcpy(smallImage, "LOADSCREENS\\LS_NightPine.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPine.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPine_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPine_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYMILITARY: - strcpy(smallImage, "LOADSCREENS\\LS_DayMilitary.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayMilitary.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayMilitary_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayMilitary_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTMILITARY: - strcpy(smallImage, "LOADSCREENS\\LS_NightMilitary.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightMilitary.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightMilitary_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightMilitary_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYSAM: - strcpy(smallImage, "LOADSCREENS\\LS_DaySAM.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DaySAM.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DaySAM_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DaySAM_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTSAM: - strcpy(smallImage, "LOADSCREENS\\LS_NightSAM.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightSAM.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightSAM_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightSAM_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYPRISON: - strcpy(smallImage, "LOADSCREENS\\LS_DayPrison.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPrison.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPrison_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayPrison_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTPRISON: - strcpy(smallImage, "LOADSCREENS\\LS_NightPrison.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPrison.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPrison_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightPrison_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYHOSPITAL: - strcpy(smallImage, "LOADSCREENS\\LS_DayHospital.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayHospital.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayHospital_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayHospital_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTHOSPITAL: - strcpy(smallImage, "LOADSCREENS\\LS_NightHospital.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightHospital.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightHospital_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightHospital_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYAIRPORT: - strcpy(smallImage, "LOADSCREENS\\LS_DayAirport.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayAirport.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayAirport_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayAirport_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTAIRPORT: - strcpy(smallImage, "LOADSCREENS\\LS_NightAirport.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightAirport.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightAirport_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightAirport_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYLAB: - strcpy(smallImage, "LOADSCREENS\\LS_DayLab.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayLab.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayLab_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayLab_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTLAB: - strcpy(smallImage, "LOADSCREENS\\LS_NightLab.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightLab.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightLab_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightLab_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYOMERTA: - strcpy(smallImage, "LOADSCREENS\\LS_DayOmerta.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayOmerta.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayOmerta_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayOmerta_1024x768.sti"); - } - break; - case LOADINGSCREEN_NIGHTOMERTA: - strcpy(smallImage, "LOADSCREENS\\LS_NightOmerta.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightOmerta.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightOmerta_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightOmerta_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYCHITZENA: - strcpy(smallImage, "LOADSCREENS\\LS_DayChitzena.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayChitzena.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayChitzena_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayChitzena_1024x768.sti"); - } - - break; - case LOADINGSCREEN_NIGHTCHITZENA: - strcpy(smallImage, "LOADSCREENS\\LS_NightChitzena.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightChitzena.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightChitzena_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightChitzena_1024x768.sti"); - } - - break; - case LOADINGSCREEN_DAYMINE: - strcpy(smallImage, "LOADSCREENS\\LS_DayMine.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayMine.sti" ); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayMine_800x600.sti" ); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayMine_1024x768.sti" ); - } - - break; - case LOADINGSCREEN_NIGHTMINE: - strcpy(smallImage, "LOADSCREENS\\LS_NightMine.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightMine.sti" ); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightMine_800x600.sti" ); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightMine_1024x768.sti" ); - } - - break; - case LOADINGSCREEN_DAYBALIME: - strcpy(smallImage, "LOADSCREENS\\LS_DayBalime.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayBalime.sti" ); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayBalime_800x600.sti" ); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_DayBalime_1024x768.sti" ); - } - - break; - case LOADINGSCREEN_NIGHTBALIME: - strcpy(smallImage, "LOADSCREENS\\LS_NightBalime.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightBalime.sti" ); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightBalime_800x600.sti" ); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_NightBalime_1024x768.sti" ); - } - - break; - default: - strcpy(smallImage, "LOADSCREENS\\LS_Heli.sti"); - if (iResolution == 0) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli.sti"); - } - else if (iResolution == 1) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli_800x600.sti"); - } - else if (iResolution == 2) - { - strcpy(vs_desc.ImageFile, "LOADSCREENS\\LS_Heli_1024x768.sti"); - } - break; - } // Switch - END + strSmallImage.copy(smallImage, sizeof(smallImage)-1); + strBigImage.copy(vs_desc.ImageFile, sizeof(vs_desc.ImageFile)-1); } - // Sti loadscreen (big image) is not available - if ( AddVideoSurface( &vs_desc, &uiLoadScreen ) == FALSE && iResolution > 0) - { - bShowSmallImage = TRUE; - strcpy(vs_desc.ImageFile, smallImage); - } if( gfSchedulesHosed ) { @@ -1432,29 +396,45 @@ void DisplayLoadScreenWithID( UINT8 ubLoadScreenID ) ColorFillVideoSurfaceArea( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 ); mprintf( 5, 5, L"Error loading save, attempting to patch save to version 1.02...", vs_desc.ImageFile ); } - else if( AddVideoSurface( &vs_desc, &uiLoadScreen ) ) - { //Blit the background image - GetVideoSurface( &hVSurface, uiLoadScreen ); + else + { + BOOLEAN fOk = FALSE; - // Special case->show the small image centered - if (iResolution > 0 && bShowSmallImage == TRUE) + if(FileExists(vs_desc.ImageFile) && AddVideoSurface(&vs_desc, &uiLoadScreen)) + fOk = TRUE; + else { - BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, iScreenWidthOffset, iScreenHeightOffset, 0, NULL ); + // Sti loadscreen is not available + // we may have tried the big image, so let's check out the small one + bShowSmallImage = TRUE; + strncpy(vs_desc.ImageFile, smallImage, sizeof(vs_desc.ImageFile)-1); + + if (FileExists(vs_desc.ImageFile) && AddVideoSurface(&vs_desc, &uiLoadScreen)) + fOk = TRUE; + } + + if (fOk) + { + //Blit the background image + GetVideoSurface(&hVSurface, uiLoadScreen); + + // Special case->show the small image centered + if (iResolution > 0 && bShowSmallImage) + BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, iScreenWidthOffset, iScreenHeightOffset, 0, NULL ); + else + BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, 0, 0, 0, NULL ); + + DeleteVideoSurfaceFromIndex( uiLoadScreen ); } else { - BltVideoSurfaceToVideoSurface( ghFrameBuffer, hVSurface, 0, 0, 0, 0, NULL ); + //Failed to load the file, so use a black screen and print out message. + SetFont( FONT10ARIAL ); + SetFontForeground( FONT_YELLOW ); + SetFontShadow( FONT_NEARBLACK ); + ColorFillVideoSurfaceArea( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 ); + mprintf( 5, 5, L"%S loadscreen data file not found...", vs_desc.ImageFile ); } - - DeleteVideoSurfaceFromIndex( uiLoadScreen ); - } - else - { //Failed to load the file, so use a black screen and print out message. - SetFont( FONT10ARIAL ); - SetFontForeground( FONT_YELLOW ); - SetFontShadow( FONT_NEARBLACK ); - ColorFillVideoSurfaceArea( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 ); - mprintf( 5, 5, L"%S loadscreen data file not found...", vs_desc.ImageFile ); } gubLastLoadingScreenID = ubLoadScreenID; @@ -1463,5 +443,3 @@ void DisplayLoadScreenWithID( UINT8 ubLoadScreenID ) EndFrameBufferRender(); RefreshScreen( NULL ); } - - diff --git a/Loading Screen.h b/Loading Screen.h index c37121fb..69f0b6c9 100644 --- a/Loading Screen.h +++ b/Loading Screen.h @@ -52,7 +52,8 @@ enum NIGHT, HELI, DAY_ALT, - NIGHT_ALT + NIGHT_ALT, + UNDERGROUND, }; diff --git a/MPChatScreen.cpp b/MPChatScreen.cpp index 105cdf90..0f24449a 100644 --- a/MPChatScreen.cpp +++ b/MPChatScreen.cpp @@ -896,7 +896,7 @@ void BtnChatTogglesCallback( GUI_BUTTON *btn, INT32 reason ) { UINT8 ubButton = (UINT8)MSYS_GetBtnUserData( btn, 0 ); - if (ubButton == 1 && PLAYER_BSIDE != 1) + if (ubButton == 1 && cGameType != MP_TYPE_TEAMDEATMATCH) return; if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) @@ -1160,7 +1160,7 @@ void EnableDisableChatLogScrollButtonsAndRegions( void ) MSYS_EnableRegion( &gChatLogScrollBarRegion ); } - if (PLAYER_BSIDE==1) + if (cGameType==MP_TYPE_TEAMDEATMATCH) { // Only enable Allies toggle for team deathmatch EnableButton( guiChatToggles[1] ); diff --git a/MPConnectScreen.cpp b/MPConnectScreen.cpp index f344ba71..77447c2f 100644 --- a/MPConnectScreen.cpp +++ b/MPConnectScreen.cpp @@ -525,3 +525,39 @@ void CheckForContinue() } } } + +#include +#include +#include +#include + +void ja2::mp::InitializeMultiplayerProfile(vfs::Path const& profileRoot) +{ + // does the profile root directory actually exist + if(!vfs::OS::checkRealDirectory(profileRoot)) + { + // OK, directory did not exist, probably a new profile + SGP_THROW_IFFALSE( vfs::OS::createRealDirectory(profileRoot), + _BS(L"Could not create directory : ") << profileRoot << _BS::wget ); + } + + // create and initialize a new Multiplayer profile + std::auto_ptr pProf( new vfs::CVirtualProfile("_MULTIPLAYER",profileRoot,true) ); + + if(!vfs_init::initWriteProfile(*pProf)) + { + SGP_THROW(_BS(L"Could not initialize client profile") << profileRoot << _BS::wget); + } + + vfs::CProfileStack *PS = getVFS()->getProfileStack(); + + // remove old Multiplayer profile (if it exists) + vfs::CVirtualProfile *pOldProf = PS->getProfile("_MULTIPLAYER"); + if( pOldProf && (pOldProf == PS->topProfile()) ) + { + SGP_THROW_IFFALSE(PS->popProfile(), L"Could not remove old \"_MULTIPLAYER\" profile"); + } + + // add new profile + PS->pushProfile(pProf.release()); +} diff --git a/MPHostScreen.cpp b/MPHostScreen.cpp index 19b4d8d1..c9434693 100644 --- a/MPHostScreen.cpp +++ b/MPHostScreen.cpp @@ -27,13 +27,13 @@ #include "gameloop.h" #include "connect.h" -#include "network.h" // for client name +#include "network.h" #include "saveloadscreen.h" -#include "VFS/vfs.h" -#include "VFS/vfs_init.h" -#include "VFS/PropertyContainer.h" -#include "VFS/os_functions.h" +#include +#include +#include +#include #include "MPJoinScreen.h" #include "MainMenuScreen.h" #include "Init.h" @@ -45,155 +45,146 @@ // /////////////////////////////////////////// -#define MPH_TITLE_FONT FONT14ARIAL//FONT16ARIAL -#define MPH_TITLE_COLOR FONT_MCOLOR_WHITE +INT32 giMPHMessageBox = -1; // message box handle -#define MPH_LABEL_TEXT_FONT FONT12ARIAL//FONT16ARIAL -#define MPH_LABEL_TEXT_COLOR FONT_MCOLOR_WHITE -#define MPH_TOGGLE_TEXT_FONT FONT12ARIAL//FONT16ARIAL -#define MPH_TOGGLE_TEXT_COLOR FONT_MCOLOR_WHITE +#define MPH_TITLE_FONT FONT14ARIAL +#define MPH_TITLE_COLOR FONT_MCOLOR_WHITE + +#define MPH_LABEL_TEXT_FONT FONT10ARIAL +#define MPH_LABEL_TEXT_COLOR FONT_MCOLOR_WHITE + +#define MPH_TOGGLE_TEXT_FONT FONT10ARIAL +#define MPH_TOGGLE_TEXT_COLOR FONT_MCOLOR_WHITE //buttons -#define MPH_BTN_START_X iScreenWidthOffset + 320 + 143 -#define MPH_BTN_START_Y iScreenHeightOffset + 435 #define MPH_CANCEL_X iScreenWidthOffset + ((320 - 115) / 2) -//textboxes -#define MPH_TXT_SVRNAME_X iScreenWidthOffset + 100 -#define MPH_TXT_SVRNAME_Y iScreenHeightOffset + 167 -#define MPH_TXT_SVRNAME_WIDTH 120 -#define MPH_TXT_SVRNAME_HEIGHT 17 -#define MPH_TXT_MAXPLAYERS_X iScreenWidthOffset + 100 -#define MPH_TXT_MAXPLAYERS_Y MPH_TXT_SVRNAME_Y + MPH_TXT_SVRNAME_HEIGHT + 13 -#define MPH_TXT_MAXPLAYERS_WIDTH 40 -#define MPH_TXT_MAXPLAYERS_HEIGHT 17 -#define MPH_TXT_SQUAD_X iScreenWidthOffset + 100 -#define MPH_TXT_SQUAD_Y MPH_TXT_MAXPLAYERS_Y + MPH_TXT_MAXPLAYERS_HEIGHT + 13 -#define MPH_TXT_SQUAD_WIDTH 40 -#define MPH_TXT_SQUAD_HEIGHT 17 -#define MPH_TXT_TIME_X iScreenWidthOffset + 100 -#define MPH_TXT_TIME_Y MPH_TXT_SQUAD_Y + MPH_TXT_SQUAD_HEIGHT + 13 -#define MPH_TXT_TIME_WIDTH 60 -#define MPH_TXT_TIME_HEIGHT 17 -#define MPH_TXT_CASH_X iScreenWidthOffset + 100 -#define MPH_TXT_CASH_Y MPH_TXT_TIME_Y + MPH_TXT_TIME_HEIGHT + 13 -#define MPH_TXT_CASH_WIDTH 60 -#define MPH_TXT_CASH_HEIGHT 17 -#define MPH_TXT_DMG_X iScreenWidthOffset + 100 -#define MPH_TXT_DMG_Y MPH_TXT_CASH_Y + MPH_TXT_CASH_HEIGHT + 13 -#define MPH_TXT_DMG_WIDTH 60 -#define MPH_TXT_DMG_HEIGHT 17 -#define MPH_TXT_TIMER_X iScreenWidthOffset + 100 -#define MPH_TXT_TIMER_Y MPH_TXT_DMG_Y + MPH_TXT_DMG_HEIGHT + 13 -#define MPH_TXT_TIMER_WIDTH 60 -#define MPH_TXT_TIMER_HEIGHT 17 -#define MPH_TXT_FILE_TRANSFER_DIR_X iScreenWidthOffset + 100 -#define MPH_TXT_FILE_TRANSFER_DIR_Y MPH_TXT_TIMER_Y + MPH_TXT_TIMER_HEIGHT + 13 -#define MPH_TXT_FILE_TRANSFER_DIR_WIDTH 200 -#define MPH_TXT_FILE_TRANSFER_DIR_HEIGHT 17 - - +#define MPH_BTN_START_X iScreenWidthOffset + 320 + 105 +#define MPH_BTN_START_Y iScreenHeightOffset + 435 //main title -#define MPH_MAIN_TITLE_X 0 +#define MPH_MAIN_TITLE_X 0 #define MPH_MAIN_TITLE_Y iScreenHeightOffset + 10 #define MPH_MAIN_TITLE_WIDTH SCREEN_WIDTH -//labels -#define MPH_LABEL_SVRNAME_X MPH_TXT_SVRNAME_X - 80 -#define MPH_LABEL_SVRNAME_Y MPH_TXT_SVRNAME_Y + 3 -#define MPH_LABEL_SVRNAME_WIDTH 80 -#define MPH_LABEL_SVRNAME_HEIGHT 17 -#define MPH_LABEL_MAXPLAYERS_X MPH_TXT_MAXPLAYERS_X - 80 -#define MPH_LABEL_MAXPLAYERS_Y MPH_TXT_MAXPLAYERS_Y + 3 -#define MPH_LABEL_MAXPLAYERS_WIDTH 80 -#define MPH_LABEL_MAXPLAYERS_HEIGHT 17 -#define MPH_LABEL_SQUAD_X MPH_TXT_SQUAD_X - 80 -#define MPH_LABEL_SQUAD_Y MPH_TXT_SQUAD_Y + 3 -#define MPH_LABEL_SQUAD_WIDTH 80 -#define MPH_LABEL_SQUAD_HEIGHT 17 -#define MPH_LABEL_TIME_X MPH_TXT_TIME_X - 80 -#define MPH_LABEL_TIME_Y MPH_TXT_TIME_Y + 3 -#define MPH_LABEL_TIME_WIDTH 80 -#define MPH_LABEL_TIME_HEIGHT 17 -#define MPH_LABEL_CASH_X MPH_TXT_CASH_X - 80 -#define MPH_LABEL_CASH_Y MPH_TXT_CASH_Y + 3 -#define MPH_LABEL_CASH_WIDTH 80 -#define MPH_LABEL_CASH_HEIGHT 17 -#define MPH_LABEL_DMG_X MPH_TXT_DMG_X - 80 -#define MPH_LABEL_DMG_Y MPH_TXT_DMG_Y + 3 -#define MPH_LABEL_DMG_WIDTH 80 -#define MPH_LABEL_DMG_HEIGHT 17 -#define MPH_LABEL_TIMER_X MPH_TXT_TIMER_X - 80 -#define MPH_LABEL_TIMER_Y MPH_TXT_TIMER_Y + 3 -#define MPH_LABEL_TIMER_WIDTH 80 -#define MPH_LABEL_TIMER_HEIGHT 17 -#define MPH_LABEL_FILE_TRANSFER_DIR_X MPH_TXT_FILE_TRANSFER_DIR_X - 80 -#define MPH_LABEL_FILE_TRANSFER_DIR_Y MPH_TXT_FILE_TRANSFER_DIR_Y + 3 -#define MPH_LABEL_FILE_TRANSFER_DIR_WIDTH 80 -#define MPH_LABEL_FILE_TRANSFER_DIR_HEIGHT 17 +#define MPH_TITLE_DISTANCE 30 // higher means closer -//radio box locations -#define MPH_GAP_BN_SETTINGS 35 -#define MPH_OFFSET_TO_TEXT 30 -#define MPH_OFFSET_TO_TOGGLE_BOX 170 -#define MPH_OFFSET_TO_TOGGLE_BOX_Y 9 +#define MPH_GAP_BN_SETTINGS 35 +#define MPH_OFFSET_TO_TEXT 36 +#define MPH_OFFSET_TO_TOGGLE_BOX 180 +#define MPH_OFFSET_TO_TOGGLE_BOX_Y 9 -#define MPH_DIF_SETTINGS_X iScreenWidthOffset + 320 -#define MPH_DIF_SETTINGS_Y iScreenHeightOffset + 75 -#define MPH_DIF_SETTINGS_WIDTH MPH_OFFSET_TO_TOGGLE_BOX - MPH_OFFSET_TO_TEXT +// --------------------------------- +// Y-Offset for Combo-Controls +#define COMBO_Y_OFFSET 63 +// Y-Offset for Check-Controls +#define CHECK_Y_OFFSET 50 -#define MPH_GAMETYPE_SETTINGS_X iScreenWidthOffset + 20 -#define MPH_GAMETYPE_SETTINGS_Y iScreenHeightOffset + 75 -#define MPH_GAMETYPE_SETTINGS_WIDTH MPH_OFFSET_TO_TOGGLE_BOX - MPH_OFFSET_TO_TEXT +#define CORRECTION_Y_OFFSET (COMBO_Y_OFFSET - CHECK_Y_OFFSET) -#define MPH_OVERRIDEMAXAI_X MPH_DIF_SETTINGS_X -#define MPH_OVERRIDEMAXAI_Y MPH_TXT_SVRNAME_Y -#define MPH_OVERRIDEMAXAI_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +// X-Offset for Checkbox-Controls +#define CHECK_X_OFFSET 36 +#define COMBO_X_OFFSET 0 -#define MPH_RNDMERC_X MPH_DIF_SETTINGS_X -#define MPH_RNDMERC_Y MPH_OVERRIDEMAXAI_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_RNDMERC_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define CHECK_WIDTH (MPH_OFFSET_TO_TOGGLE_BOX - MPH_OFFSET_TO_TEXT) +#define COMBO_WIDTH (MPH_OFFSET_TO_TOGGLE_BOX - MPH_OFFSET_TO_TEXT) +// --------------------------------- -#define MPH_SAMEMERC_X MPH_DIF_SETTINGS_X -#define MPH_SAMEMERC_Y MPH_RNDMERC_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_SAMEMERC_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +/********************************* + FIRST COLUMN +**********************************/ -#define MPH_REPORTMERC_X MPH_DIF_SETTINGS_X -#define MPH_REPORTMERC_Y MPH_SAMEMERC_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_REPORTMERC_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define FIRST_COLUMN_X iScreenWidthOffset + 10 +#define FIRST_COLUMN_Y iScreenHeightOffset + 75 -#define MPH_BOBBYRAY_X MPH_DIF_SETTINGS_X -#define MPH_BOBBYRAY_Y MPH_REPORTMERC_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_BOBBYRAY_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define MPH_SYNC_SETTING_X FIRST_COLUMN_X + CHECK_X_OFFSET +#define MPH_SYNC_SETTING_Y FIRST_COLUMN_Y - CORRECTION_Y_OFFSET +#define MPH_SYNC_SETTING_WIDTH CHECK_WIDTH -#define MPH_RNDSPAWN_X MPH_DIF_SETTINGS_X -#define MPH_RNDSPAWN_Y MPH_BOBBYRAY_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_RNDSPAWN_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define MPH_SQUADSIZE_SETTING_X FIRST_COLUMN_X + COMBO_X_OFFSET +#define MPH_SQUADSIZE_SETTING_Y MPH_SYNC_SETTING_Y + COMBO_Y_OFFSET + CORRECTION_Y_OFFSET +#define MPH_SQUADSIZE_SETTING_WIDTH COMBO_WIDTH -#define MPH_CIVS_X MPH_DIF_SETTINGS_X -#define MPH_CIVS_Y MPH_RNDSPAWN_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_CIVS_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define MPH_TIMETURNS_SETTING_X FIRST_COLUMN_X + COMBO_X_OFFSET +#define MPH_TIMETURNS_SETTING_Y MPH_SQUADSIZE_SETTING_Y + COMBO_Y_OFFSET +#define MPH_TIMETURNS_SETTING_WIDTH COMBO_WIDTH -#define MPH_USENIV_X MPH_DIF_SETTINGS_X -#define MPH_USENIV_Y MPH_CIVS_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_USENIV_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define MPH_INVENTORY_SETTING_X FIRST_COLUMN_X + COMBO_X_OFFSET +#define MPH_INVENTORY_SETTING_Y MPH_TIMETURNS_SETTING_Y + COMBO_Y_OFFSET +#define MPH_INVENTORY_SETTING_WIDTH COMBO_WIDTH -#define MPH_SEND_FILES_X MPH_DIF_SETTINGS_X -#define MPH_SEND_FILES_Y MPH_USENIV_Y + MPH_GAP_BN_SETTINGS - 5 -#define MPH_SEND_FILES_WIDTH MPH_OFFSET_TO_TOGGLE_BOX +#define MPH_BOBBYRAY_SETTING_X FIRST_COLUMN_X + CHECK_X_OFFSET +#define MPH_BOBBYRAY_SETTING_Y MPH_INVENTORY_SETTING_Y + CHECK_Y_OFFSET +#define MPH_BOBBYRAY_SETTING_WIDTH CHECK_WIDTH -//Difficulty settings -enum -{ - MPH_DIFF_HARD, - MPH_DIFF_INSANE, - MPH_NUM_DIFF_SETTINGS, -}; +#define MPH_REPORTMERC_SETTING_X FIRST_COLUMN_X + CHECK_X_OFFSET +#define MPH_REPORTMERC_SETTING_Y MPH_BOBBYRAY_SETTING_Y + CHECK_Y_OFFSET + CORRECTION_Y_OFFSET +#define MPH_REPORTMERC_SETTING_WIDTH CHECK_WIDTH +/********************************* + SECOND COLUMN +**********************************/ -//////////////////////////////////////////// +#define SECOND_COLUMN_X iScreenWidthOffset + 210 +#define SECOND_COLUMN_Y FIRST_COLUMN_Y + +#define MPH_MAXPLAYERS_SETTING_X SECOND_COLUMN_X + COMBO_X_OFFSET +#define MPH_MAXPLAYERS_SETTING_Y SECOND_COLUMN_Y +#define MPH_MAXPLAYERS_SETTING_WIDTH COMBO_WIDTH + +#define MPH_STARTINGTIME_SETTING_X SECOND_COLUMN_X + COMBO_X_OFFSET +#define MPH_STARTINGTIME_SETTING_Y MPH_MAXPLAYERS_SETTING_Y + COMBO_Y_OFFSET +#define MPH_STARTINGTIME_SETTING_WIDTH COMBO_WIDTH + +#define MPH_WEAPONDAMAGE_SETTING_X SECOND_COLUMN_X + COMBO_X_OFFSET +#define MPH_WEAPONDAMAGE_SETTING_Y MPH_STARTINGTIME_SETTING_Y + COMBO_Y_OFFSET +#define MPH_WEAPONDAMAGE_SETTING_WIDTH COMBO_WIDTH + +#define MPH_TRAITS_SETTING_X SECOND_COLUMN_X + CHECK_X_OFFSET +#define MPH_TRAITS_SETTING_Y MPH_WEAPONDAMAGE_SETTING_Y + CHECK_Y_OFFSET +#define MPH_TRAITS_SETTING_WIDTH CHECK_WIDTH + +#define MPH_HIREMERC_SETTING_X SECOND_COLUMN_X + CHECK_X_OFFSET +#define MPH_HIREMERC_SETTING_Y MPH_TRAITS_SETTING_Y + CHECK_Y_OFFSET + CORRECTION_Y_OFFSET +#define MPH_HIREMERC_SETTING_WIDTH CHECK_WIDTH + +#define MPH_CIVS_SETTING_X SECOND_COLUMN_X + CHECK_X_OFFSET +#define MPH_CIVS_SETTING_Y MPH_HIREMERC_SETTING_Y + CHECK_Y_OFFSET + CORRECTION_Y_OFFSET +#define MPH_CIVS_SETTING_WIDTH CHECK_WIDTH + +/********************************* + THIRD COLUMN +**********************************/ + +#define THIRD_COLUMN_X iScreenWidthOffset + 413 +#define THIRD_COLUMN_Y FIRST_COLUMN_Y + +#define MPH_GAMETYPE_SETTING_X THIRD_COLUMN_X + COMBO_X_OFFSET +#define MPH_GAMETYPE_SETTING_Y THIRD_COLUMN_Y +#define MPH_GAMETYPE_SETTING_WIDTH COMBO_WIDTH + +#define MPH_STARTINGCASH_SETTING_X THIRD_COLUMN_X + COMBO_X_OFFSET +#define MPH_STARTINGCASH_SETTING_Y MPH_GAMETYPE_SETTING_Y + COMBO_Y_OFFSET +#define MPH_STARTINGCASH_SETTING_WIDTH COMBO_WIDTH + +#define MPH_SECTOREDGE_SETTING_X THIRD_COLUMN_X + CHECK_X_OFFSET +#define MPH_SECTOREDGE_SETTING_Y MPH_STARTINGCASH_SETTING_Y + CHECK_Y_OFFSET +#define MPH_SECTOREDGE_SETTING_WIDTH CHECK_WIDTH + +#define MPH_DIFFICULTY_SETTING_X THIRD_COLUMN_X + COMBO_X_OFFSET +#define MPH_DIFFICULTY_SETTING_Y MPH_SECTOREDGE_SETTING_Y + COMBO_Y_OFFSET + CORRECTION_Y_OFFSET +#define MPH_DIFFICULTY_SETTING_WIDTH COMBO_WIDTH + +#define MPH_MAXENEMIES_SETTING_X THIRD_COLUMN_X + CHECK_X_OFFSET +#define MPH_MAXENEMIES_SETTING_Y MPH_DIFFICULTY_SETTING_Y + CHECK_Y_OFFSET +#define MPH_MAXENEMIES_SETTING_WIDTH CHECK_WIDTH + +#define MPH_SAMEMERC_SETTING_X THIRD_COLUMN_X + CHECK_X_OFFSET +#define MPH_SAMEMERC_SETTING_Y MPH_MAXENEMIES_SETTING_Y + CHECK_Y_OFFSET + CORRECTION_Y_OFFSET +#define MPH_SAMEMERC_SETTING_WIDTH CHECK_WIDTH + +/////////////////////////////////////////// // // Global Variables // @@ -204,6 +195,1292 @@ BOOLEAN gfMPHScreenExit = FALSE; BOOLEAN gfReRenderMPHScreen=TRUE; BOOLEAN gfMPHButtonsAllocated = FALSE; +// RW: +UINT32 guiMPHSMALLFRAME; + +void RenderMPHSmallSelectionFrame(INT16 sX, INT16 sY); + +// ---------------- +// Traits +enum +{ + MPH_TRAITS_OLD = 0, + MPH_TRAITS_NEW = 1, + + MPH_NUM_TRAITS_OPTIONS, +}; + +UINT32 guiMPHTraitsOptionTogglesImage[ MPH_NUM_TRAITS_OPTIONS ]; +UINT32 guiMPHTraitsOptionToggles[ MPH_NUM_TRAITS_OPTIONS ]; +void BtnMPHOldTraitsCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHNewTraitsCallback(GUI_BUTTON *btn,INT32 reason); +void MTHNewTraitsNotPossibleMessageBoxCallBack( UINT8 bExitValue ); + +void BtnMPHOldTraitsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_TRAITS_SETTING_X), (MPH_TRAITS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHTraitsOptionToggles[ MPH_TRAITS_OLD ], BUTTON_SOUND_CLICKED_ON ); + } +} + +BOOLEAN DoMPHMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ) +{ + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; + + // do message box and return + giMPHMessageBox = DoMessageBox( ubStyle, zString, uiExitScreen, ( UINT16 ) ( usFlags| MSG_BOX_FLAG_USE_CENTERING_RECT ), ReturnCallback, &CenteringRect ); + + // send back return state + return( ( giMPHMessageBox != -1 ) ); +} + +UINT8 GetMPHCurrentTraitsOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +void BtnMPHNewTraitsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + if (!gGameExternalOptions.fReadProfileDataFromXML) + { + PlayButtonSound( guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ], BUTTON_SOUND_DISABLED_CLICK ); + + DoMPHMessageBox( MSG_BOX_BASIC_STYLE, zGioNewTraitsImpossibleText[0], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, MTHNewTraitsNotPossibleMessageBoxCallBack ); + } + else + { + RestoreExternBackgroundRect( (MPH_TRAITS_SETTING_X), (MPH_TRAITS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHTraitsOptionToggles[ MPH_TRAITS_OLD ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ], BUTTON_SOUND_CLICKED_ON ); + } + } +} + +void MTHNewTraitsNotPossibleMessageBoxCallBack( UINT8 bExitValue ) +{ +} + +// ---------------- + +// ------------- +// Sync +enum +{ + MPH_SYNC_NO = 0, + MPH_SYNC_YES = 1, + + MPH_NUM_SYNC_OPTIONS, +}; + +UINT32 guiMPHSyncOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHSyncOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHNoSyncCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHYesSyncCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHNoSyncCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_SYNC_SETTING_X), (MPH_SYNC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHSyncOptionToggles[ MPH_SYNC_YES ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHSyncOptionToggles[ MPH_SYNC_NO ], BUTTON_SOUND_CLICKED_ON ); + } +} +void BtnMPHYesSyncCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_SYNC_SETTING_X), (MPH_SYNC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHSyncOptionToggles[ MPH_SYNC_NO ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHSyncOptionToggles[ MPH_SYNC_YES ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentSyncOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// MaxEnemies +enum +{ + MPH_MAXENEMIES_NO = 0, + MPH_MAXENEMIES_YES = 1, + + MPH_NUM_MAXENEMIES_OPTIONS, +}; + +UINT32 guiMPHMaxEnemiesOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHMaxEnemiesOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHNoMaxEnemiesCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHYesMaxEnemiesCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHNoMaxEnemiesCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_MAXENEMIES_SETTING_X), (MPH_MAXENEMIES_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_YES ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_NO ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHYesMaxEnemiesCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_MAXENEMIES_SETTING_X), (MPH_MAXENEMIES_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_NO ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_YES ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentMaxEnemiesOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// Civs +enum +{ + MPH_CIVS_NO = 0, + MPH_CIVS_YES = 1, + + MPH_NUM_CIVS_OPTIONS, +}; + +UINT32 guiMPHCivsOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHCivsOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHNoCivsCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHYesCivsCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHNoCivsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_CIVS_SETTING_X), (MPH_CIVS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHCivsOptionToggles[ MPH_CIVS_YES ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHCivsOptionToggles[ MPH_CIVS_NO ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHYesCivsCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_CIVS_SETTING_X), (MPH_CIVS_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHCivsOptionToggles[ MPH_CIVS_NO ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHCivsOptionToggles[ MPH_CIVS_YES ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentCivsOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// ReportMerc +enum +{ + MPH_REPORTMERC_NO = 0, + MPH_REPORTMERC_YES = 1, + + MPH_NUM_REPORTMERC_OPTIONS, +}; + +UINT32 guiMPHReportMercOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHReportMercOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHNoReportMercCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHYesReportMercCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHNoReportMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_REPORTMERC_SETTING_X), (MPH_REPORTMERC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHReportMercOptionToggles[ MPH_REPORTMERC_YES ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHReportMercOptionToggles[ MPH_REPORTMERC_NO ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHYesReportMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_REPORTMERC_SETTING_X), (MPH_REPORTMERC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHReportMercOptionToggles[ MPH_REPORTMERC_NO ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHReportMercOptionToggles[ MPH_REPORTMERC_YES ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentReportMercOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// HireMerc +enum +{ + MPH_HIREMERC_NORMAL = 0, + MPH_HIREMERC_RANDOM = 1, + + MPH_NUM_HIREMERC_OPTIONS, +}; + +UINT32 guiMPHHireMercOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHHireMercOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHRandomHireMercCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHNormalHireMercCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHRandomHireMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_HIREMERC_SETTING_X), (MPH_HIREMERC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHHireMercOptionToggles[ MPH_HIREMERC_NORMAL ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHHireMercOptionToggles[ MPH_HIREMERC_RANDOM ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHNormalHireMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_HIREMERC_SETTING_X), (MPH_HIREMERC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHHireMercOptionToggles[ MPH_HIREMERC_RANDOM ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHHireMercOptionToggles[ MPH_HIREMERC_NORMAL ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentHireMercOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// SectorEdge +enum +{ + MPH_SECTOREDGE_SELECTABLE = 0, + MPH_SECTOREDGE_RANDOM = 1, + + MPH_NUM_SECTOREDGE_OPTIONS, +}; + +UINT32 guiMPHSectorEdgeOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHSectorEdgeOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHRandomSectorEdgeCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHSelectableSectorEdgeCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHRandomSectorEdgeCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_SECTOREDGE_SETTING_X), (MPH_SECTOREDGE_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_SELECTABLE ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_RANDOM ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHSelectableSectorEdgeCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_SECTOREDGE_SETTING_X), (MPH_SECTOREDGE_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_RANDOM ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_SELECTABLE ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentSectorEdgeOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// BobbyRay +enum +{ + MPH_BOBBYRAY_ALLOW = 0, + MPH_BOBBYRAY_DISABLE = 1, + + MPH_NUM_BOBBYRAY_OPTIONS, +}; + +UINT32 guiMPHBobbyRayOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHBobbyRayOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHDisableBobbyRayCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHAllowBobbyRayCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHDisableBobbyRayCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_BOBBYRAY_SETTING_X), (MPH_BOBBYRAY_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_ALLOW ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_DISABLE ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHAllowBobbyRayCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_BOBBYRAY_SETTING_X), (MPH_BOBBYRAY_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_DISABLE ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_ALLOW ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentBobbyRayOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// SameMerc +enum +{ + MPH_SAMEMERC_DISABLE = 0, + MPH_SAMEMERC_ALLOW = 1, + + MPH_NUM_SAMEMERC_OPTIONS, +}; + +UINT32 guiMPHSameMercOptionTogglesImage[ MPH_NUM_SYNC_OPTIONS ]; +UINT32 guiMPHSameMercOptionToggles[ MPH_NUM_SYNC_OPTIONS ]; +void BtnMPHDisableSameMercCallback(GUI_BUTTON *btn,INT32 reason); +void BtnMPHAllowSameMercCallback(GUI_BUTTON *btn,INT32 reason); + +void BtnMPHDisableSameMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_SAMEMERC_SETTING_X), (MPH_SAMEMERC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHSameMercOptionToggles[ MPH_SAMEMERC_ALLOW ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHSameMercOptionToggles[ MPH_SAMEMERC_DISABLE ], BUTTON_SOUND_CLICKED_ON ); + } +} + +void BtnMPHAllowSameMercCallback(GUI_BUTTON *btn,INT32 reason) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + RestoreExternBackgroundRect( (MPH_SAMEMERC_SETTING_X), (MPH_SAMEMERC_SETTING_Y + 10), 230, 40 ); + + ButtonList[ guiMPHSameMercOptionToggles[ MPH_SAMEMERC_DISABLE ] ]->uiFlags &= ~BUTTON_CLICKED_ON; + btn->uiFlags|=(BUTTON_CLICKED_ON); + + PlayButtonSound( guiMPHSameMercOptionToggles[ MPH_SAMEMERC_ALLOW ], BUTTON_SOUND_CLICKED_ON ); + } +} + +UINT8 GetCurrentSameMercOptionButtonSetting() +{ + UINT8 cnt; + + for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) + { + return( cnt ); + } + } + return( 0 ); +} + +// ------------- + +// ------------- +// Difficulty +enum +{ + MPH_DIFF_EASY = 0, + MPH_DIFF_MED = 1, + MPH_DIFF_HARD = 2, + MPH_DIFF_INSANE = 3, + + MPH_NUM_DIFF_SETTINGS, +}; + +INT8 iMPHDifficulty; + +UINT32 giMPHDifficultyButton[ 2 ]; +INT32 giMPHDifficultyButtonImage[ 2 ]; +void BtnMPHDifficultySelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHDifficultySelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHDifficultySelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHDifficulty > 0 ) + { + PlayButtonSound( giMPHDifficultyButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHDifficulty--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHDifficultyButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHDifficultySelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + if ( iMPHDifficulty < 3 ) + { + PlayButtonSound( giMPHDifficultyButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHDifficulty++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHDifficultyButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// GameType +enum +{ + MPH_GT_DEATHMATCH = 0, + MPH_GT_TEAM_DEATHMATCH = 1, + MPH_GT_COOP = 2, + + MPH_NUM_GAMETYPE_SETTINGS, +}; + +INT8 iMPHGameType; + +UINT32 giMPHGameTypeButton[ 2 ]; +INT32 giMPHGameTypeButtonImage[ 2 ]; +void BtnMPHGameTypeSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHGameTypeSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHGameTypeSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHGameType > MPH_GT_DEATHMATCH ) + { + PlayButtonSound( giMPHGameTypeButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHGameType--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHGameTypeButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHGameTypeSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHGameType < MPH_GT_COOP ) + { + PlayButtonSound( giMPHGameTypeButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHGameType++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHGameTypeButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// MaxPlayers +enum +{ + MPH_MAXPLAYERS_2 = 2, + MPH_MAXPLAYERS_3 = 3, + MPH_MAXPLAYERS_4 = 4, + + MPH_NUM_MAXPLAYERS_SETTINGS, +}; + +INT8 iMPHMaxPlayers; + +UINT32 giMPHMaxPlayersButton[ 2 ]; +INT32 giMPHMaxPlayersButtonImage[ 2 ]; +void BtnMPHMaxPlayersSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHMaxPlayersSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHMaxPlayersSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHMaxPlayers > MPH_MAXPLAYERS_2 ) + { + PlayButtonSound( giMPHMaxPlayersButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHMaxPlayers--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHMaxPlayersButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHMaxPlayersSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHMaxPlayers < MPH_MAXPLAYERS_4 ) + { + PlayButtonSound( giMPHMaxPlayersButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHMaxPlayers++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHMaxPlayersButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// Inventory +enum +{ + MPH_INV_OLD = 0, + MPH_INV_NEW = 1, + MPH_INV_NEW_NAS = 2, + + MPH_NUM_INV_OPTIONS, +}; + +INT8 iMPHInventory; + +UINT32 giMPHInventoryButton[ 2 ]; +INT32 giMPHInventoryButtonImage[ 2 ]; +void BtnMPHInventorySelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHInventorySelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHInventorySelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHInventory > MPH_INV_OLD ) + { + PlayButtonSound( giMPHInventoryButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHInventory--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHInventoryButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHInventorySelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHInventory < MPH_INV_NEW_NAS ) + { + PlayButtonSound( giMPHInventoryButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHInventory++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHInventoryButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// StartingTime +enum +{ + MPH_STARTINGTIME_MORNING = 0, + MPH_STARTINGTIME_AFTERNOON = 1, + MPH_STARTINGTIME_NIGHT = 2, + + MPH_NUM_STARTINGTIME_SETTINGS, +}; + +INT8 iMPHStartingTime; + +UINT32 giMPHStartingTimeButton[ 2 ]; +INT32 giMPHStartingTimeButtonImage[ 2 ]; +void BtnMPHStartingTimeSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHStartingTimeSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHStartingTimeSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHStartingTime > MPH_STARTINGTIME_MORNING ) + { + PlayButtonSound( giMPHStartingTimeButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHStartingTime--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHStartingTimeButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHStartingTimeSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHStartingTime < MPH_STARTINGTIME_NIGHT ) + { + PlayButtonSound( giMPHStartingTimeButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHStartingTime++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHStartingTimeButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// StartingCash +enum +{ + MPH_STARTINGCASH_LOW = 0, + MPH_STARTINGCASH_MEDIUM = 1, + MPH_STARTINGCASH_HIGH = 2, + MPH_STARTINGCASH_UNLIMITED = 3, + + MPH_NUM_STARTINGCASH_SETTINGS, +}; + +INT8 iMPHStartingCash; + +UINT32 giMPHStartingCashButton[ 2 ]; +INT32 giMPHStartingCashButtonImage[ 2 ]; +void BtnMPHStartingCashSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHStartingCashSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHStartingCashSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHStartingCash > MPH_STARTINGCASH_LOW ) + { + PlayButtonSound( giMPHStartingCashButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHStartingCash--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHStartingCashButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHStartingCashSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHStartingCash < MPH_STARTINGCASH_UNLIMITED ) + { + PlayButtonSound( giMPHStartingCashButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHStartingCash++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHStartingCashButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// WeaponDamage +enum +{ + MPH_WEAPONDAMAGE_VERYLOW = 0, + MPH_WEAPONDAMAGE_LOW = 1, + MPH_WEAPONDAMAGE_NORMAL = 2, + + MPH_NUM_WEAPONDAMAGE_SETTINGS, +}; + +INT8 iMPHWeaponDamage; + +UINT32 giMPHWeaponDamageButton[ 2 ]; +INT32 giMPHWeaponDamageButtonImage[ 2 ]; +void BtnMPHWeaponDamageSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHWeaponDamageSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHWeaponDamageSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHWeaponDamage > MPH_WEAPONDAMAGE_VERYLOW ) + { + PlayButtonSound( giMPHWeaponDamageButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHWeaponDamage--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHWeaponDamageButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHWeaponDamageSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHWeaponDamage < MPH_WEAPONDAMAGE_NORMAL ) + { + PlayButtonSound( giMPHWeaponDamageButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHWeaponDamage++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHWeaponDamageButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// TimeTurns +enum +{ + MPH_TIMETURNS_NEVER = 0, + MPH_TIMETURNS_SLOW = 1, + MPH_TIMETURNS_MEDIUM = 2, + MPH_TIMETURNS_FAST = 3, + + MPH_NUM_TIMETURNS_SETTINGS, +}; + +INT8 iMPHTimeTurns; + +UINT32 giMPHTimeTurnsButton[ 2 ]; +INT32 giMPHTimeTurnsButtonImage[ 2 ]; +void BtnMPHTimeTurnsSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHTimeTurnsSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHTimeTurnsSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHTimeTurns > MPH_TIMETURNS_NEVER ) + { + PlayButtonSound( giMPHTimeTurnsButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHTimeTurns--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHTimeTurnsButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHTimeTurnsSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHTimeTurns < MPH_TIMETURNS_FAST ) + { + PlayButtonSound( giMPHTimeTurnsButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHTimeTurns++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHTimeTurnsButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + +// ------------- +// SquadSize +enum +{ + MPH_SQUADSIZE_1 = 1, + MPH_SQUADSIZE_2 = 2, + MPH_SQUADSIZE_3 = 3, + MPH_SQUADSIZE_4 = 4, + MPH_SQUADSIZE_5 = 5, + MPH_SQUADSIZE_6 = 6, + + MPH_NUM_SQUADSIZE_SETTINGS, +}; + +INT8 iMPHSquadSize; + +UINT32 giMPHSquadSizeButton[ 2 ]; +INT32 giMPHSquadSizeButtonImage[ 2 ]; +void BtnMPHSquadSizeSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ); +void BtnMPHSquadSizeSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ); + +void BtnMPHSquadSizeSelectionLeftCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHSquadSize > MPH_SQUADSIZE_1 ) + { + PlayButtonSound( giMPHSquadSizeButton[0], BUTTON_SOUND_CLICKED_ON ); + + iMPHSquadSize--; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHSquadSizeButton[0], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +void BtnMPHSquadSizeSelectionRightCallback( GUI_BUTTON *btn,INT32 reason ) +{ + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if( reason & MSYS_CALLBACK_REASON_LBUTTON_REPEAT || reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) + { + if ( iMPHSquadSize < MPH_SQUADSIZE_6 ) + { + PlayButtonSound( giMPHSquadSizeButton[1], BUTTON_SOUND_CLICKED_ON ); + + iMPHSquadSize++; + gfReRenderMPHScreen =TRUE; + } + else + { + PlayButtonSound( giMPHSquadSizeButton[1], BUTTON_SOUND_DISABLED_CLICK ); + } + } + else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + if (btn->uiFlags & BUTTON_CLICKED_ON) + { + btn->uiFlags&=~(BUTTON_CLICKED_ON); + } + } +} + +// ------------- + //enum for different states of screen enum { @@ -218,34 +1495,38 @@ UINT32 gubMPHExitScreen = MP_HOST_SCREEN; // The screen that is in control next UINT32 guiMPHMainBackGroundImage; +// ------------ +// String fields // Wide-char strings that will hold the variables until they are transferred to the CHAR ascii fields CHAR16 gzServerNameField[ 30 ] = {0} ; -CHAR16 gzMaxPlayersField[ 2 ] = {0} ; -CHAR16 gzSquadSizeField[ 2 ] = {0} ; -CHAR16 gzTimeOfDayField[ 6 ] = {0}; -CHAR16 gzStartingBalanceField[ 10 ] = {0}; -INT16 giMPHTimeHours = 0; -INT16 giMPHTimeMins = 0; -CHAR16 gzDmgMultiplierField[ 5 ] = {0}; -CHAR16 gzTimerField[ 6 ] = {0}; CHAR16 gzFileTransferDirectory[ 100 ] = {0} ; CHAR16 gzKitBag[ 100 ] = {0}; -UINT8 guiMPHGameType = MP_TYPE_DEATHMATCH; // default value -UINT8 guiMPHDifficultLevel = DIF_LEVEL_HARD; // Expert - -INT32 giMPHMessageBox = -1; // message box handle - -INT giMPHOverrideMaxAI = 0; -INT giMPHRandomMercs = 0; -INT giMPHSameMercs = 0; -INT giMPHReportMercs = 0; -INT giMPHBobbyRays = 0; -INT giMPHRandomSpawn = 0; -INT giMPHEnableCivilians = 0; -INT giMPHUseNIV = 0; -INT giMPHSendFiles = 0; +// ------------ +// Controls with Multi Selection! +UINT8 guiMPHGameType; +UINT8 guiMPHDifficultLevel; +UINT8 guiMPHMaxPlayers; +UINT8 guiMPHSquadSize; +UINT8 guiMPHStartingTime; +UINT8 guiMPHStartingCash; +UINT8 guiMPHTimeTurns; +UINT8 guiMPHWeaponDamage; +UINT8 guiMPHInventory; +// ------------ +// ------------ +// Controls with YES/NO +UINT8 guiMPHMaxEnemies; +UINT8 guiMPHSendFiles; +UINT8 guiMPHHireMerc; +UINT8 guiMPHSectorEdge; +UINT8 guiMPHBobbyRay; +UINT8 guiMPHSameMerc; +UINT8 guiMPHReportMerc; +UINT8 guiMPHCivs; +UINT8 guiMPHNewTraits; +// ------------ //////////////////////////////////////////// // @@ -263,51 +1544,6 @@ void BtnMPHCancelCallback(GUI_BUTTON *btn,INT32 reason); UINT32 guiMPHCancelButton; INT32 giMPHCancelBtnImage; -//checkbox to toggle the Diff level -UINT32 guiMPHDifficultySettingsToggles[ MPH_NUM_DIFF_SETTINGS ]; -void BtnMPHDifficultyTogglesCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox to toggle Game Type -UINT32 guiMPHGameTypeToggles[ NUM_MP_GAMETYPE ]; -void BtnMPHGameTypeTogglesCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for override max ai -UINT32 guiMPHOverrideMaxAIToggle; -void BtnMPHOverrideMaxAICallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for merc options -UINT32 guiMPHRandomMercsToggle; -void BtnMPHRandomMercCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for same merc -UINT32 guiMPHSameMercToggle; -void BtnMPHSameMercCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for report purchase -UINT32 guiMPHReportMercToggle; -void BtnMPHReportMercCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for bobby rays -UINT32 guiMPHBobbyRayToggle; -void BtnMPHBobbyRayCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for random spawn pos -UINT32 guiMPHRandomSpawnToggle; -void BtnMPHRandomSpawnCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for enable civilians in CO-OP -UINT32 guiMPHCivsToggle; -void BtnMPHCivsCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for use NIV -UINT32 guiMPHUseNIVToggle; -void BtnMPHUseNIVCallback(GUI_BUTTON *btn,INT32 reason); - -//checkbox for send files -UINT32 guiMPHSendFiles; -void BtnMPHSendFilesCallback(GUI_BUTTON *btn,INT32 reason); - - //////////////////////////////////////////// // // Local Function Prototypes @@ -321,14 +1557,12 @@ BOOLEAN ExitMPHScreen(); void HandleMPHScreen(); BOOLEAN RenderMPHScreen(); void GetMPHScreenUserInput(); -void RestoreMPHButtonBackGrounds(); bool ValidateMPSettings(); void SaveMPSettings(); -UINT8 GetMPHCurrentDifficultyButtonSetting(); UINT8 GetMPHGameTypeButtonSetting(); -BOOLEAN DoMPHMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); -void DoneFadeOutForExitMPHScreen( void ); -void DoneFadeInForExitMPHScreen( void ); +BOOLEAN DoMPHMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ); +void DoneFadeOutForExitMPHScreen( void ); +void DoneFadeInForExitMPHScreen( void ); //////////////////////////////////////////// // @@ -337,423 +1571,149 @@ void DoneFadeInForExitMPHScreen( void ); /////////////////////////////////////////// void SaveMPSettings() -{ - Get16BitStringFromField( 0, gzServerNameField, 30 ); // these indexes are based on the order created - Get16BitStringFromField( 1, gzMaxPlayersField, 2 ); - Get16BitStringFromField( 2, gzSquadSizeField, 2 ); - Get16BitStringFromField( 7, gzFileTransferDirectory, 100 ); -#ifndef USE_VFS - // save settings to JA2_mp.ini - WritePrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_NAME", gzServerNameField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"MAX_CLIENTS", gzMaxPlayersField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"MAX_MERCS", gzSquadSizeField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"STARTING_BALANCE", gzStartingBalanceField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"DAMAGE_MULTIPLIER", gzDmgMultiplierField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"TIMED_TURN_SECS_PER_TICK", gzTimerField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"FILE_TRANSFER_DIRECTORY", gzFileTransferDirectory , L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"KIT_BAG", gzKitBag , L"..\\Ja2_mp.ini" ); - - - - guiMPHGameType = GetMPHGameTypeButtonSetting(); - CHAR16 tmpGTStr[2]; - _itow(guiMPHGameType,tmpGTStr,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"GAME_MODE", tmpGTStr, L"..\\Ja2_mp.ini" ); - - CHAR16 tmpTimeStr[6]; - swprintf(tmpTimeStr,L"%i.%i",giMPHTimeHours,giMPHTimeMins); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"TIME", tmpTimeStr, L"..\\Ja2_mp.ini" ); - - CHAR16 tmpVal[2]; - - giMPHOverrideMaxAI = ( ButtonList[ guiMPHOverrideMaxAIToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHOverrideMaxAI,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"OVERRIDE_MAX_AI", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHRandomMercs = ( ButtonList[ guiMPHRandomMercsToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHRandomMercs,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"RANDOM_MERCS", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHSameMercs = ( ButtonList[ guiMPHSameMercToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHSameMercs,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"SAME_MERC", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHBobbyRays = ( ButtonList[ guiMPHBobbyRayToggle ]->uiFlags & BUTTON_CLICKED_ON ? 0 : 1 ); // This setting is reversed - _itow(giMPHBobbyRays,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"DISABLE_BOBBY_RAYS", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHReportMercs = ( ButtonList[ guiMPHReportMercToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHReportMercs,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"REPORT_NAME", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHRandomSpawn = ( ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHRandomSpawn,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"RANDOM_EDGES", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHEnableCivilians = ( ButtonList[ guiMPHCivsToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHEnableCivilians,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"CIV_ENABLED", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHUseNIV = ( ButtonList[ guiMPHUseNIVToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHUseNIV,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"ALLOW_CUSTOM_NIV", tmpVal, L"..\\Ja2_mp.ini" ); - - giMPHSendFiles = ( ButtonList[ guiMPHSendFiles ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHSendFiles,tmpVal,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"SYNC_CLIENTS_MP_DIR", tmpVal, L"..\\Ja2_mp.ini" ); - guiMPHDifficultLevel = GetMPHCurrentDifficultyButtonSetting(); - CHAR16 tmpDiffStr[2]; - _itow(guiMPHDifficultLevel,tmpDiffStr,10); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"DIFFICULT_LEVEL", tmpDiffStr, L"..\\Ja2_mp.ini" ); -#else - CPropertyContainer props; - props.initFromIniFile("Ja2_mp.ini"); - - props.setStringProperty(L"Ja2_mp Settings",L"SERVER_NAME", gzServerNameField); - props.setStringProperty(L"Ja2_mp Settings",L"MAX_CLIENTS", gzMaxPlayersField); - props.setStringProperty(L"Ja2_mp Settings",L"MAX_MERCS", gzSquadSizeField); - props.setStringProperty(L"Ja2_mp Settings",L"STARTING_BALANCE", gzStartingBalanceField); - props.setStringProperty(L"Ja2_mp Settings",L"DAMAGE_MULTIPLIER", gzDmgMultiplierField); - props.setStringProperty(L"Ja2_mp Settings",L"TIMED_TURN_SECS_PER_TICK", gzTimerField); - props.setStringProperty(L"Ja2_mp Settings",L"FILE_TRANSFER_DIRECTORY", gzFileTransferDirectory); - props.setStringProperty(L"Ja2_mp Settings",L"KIT_BAG", gzKitBag); - - - guiMPHGameType = GetMPHGameTypeButtonSetting(); - CHAR16 tmpGTStr[2]; - _itow(guiMPHGameType,tmpGTStr,10); - props.setStringProperty(L"Ja2_mp Settings",L"GAME_MODE", tmpGTStr); - - CHAR16 tmpTimeStr[6]; - swprintf(tmpTimeStr,L"%i.%i",giMPHTimeHours,giMPHTimeMins); - props.setStringProperty(L"Ja2_mp Settings",L"TIME", tmpTimeStr); - - CHAR16 tmpVal[2]; - - giMPHOverrideMaxAI = ( ButtonList[ guiMPHOverrideMaxAIToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHOverrideMaxAI,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"OVERRIDE_MAX_AI", tmpVal); - - giMPHRandomMercs = ( ButtonList[ guiMPHRandomMercsToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHRandomMercs,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"RANDOM_MERCS", tmpVal); - - giMPHSameMercs = ( ButtonList[ guiMPHSameMercToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHSameMercs,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"SAME_MERC", tmpVal); - - giMPHBobbyRays = ( ButtonList[ guiMPHBobbyRayToggle ]->uiFlags & BUTTON_CLICKED_ON ? 0 : 1 ); // This setting is reversed - _itow(giMPHBobbyRays,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"DISABLE_BOBBY_RAYS", tmpVal); - - giMPHReportMercs = ( ButtonList[ guiMPHReportMercToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHReportMercs,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"REPORT_NAME", tmpVal); - - giMPHRandomSpawn = ( ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHRandomSpawn,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"RANDOM_EDGES", tmpVal); - - giMPHEnableCivilians = ( ButtonList[ guiMPHCivsToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHEnableCivilians,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"CIV_ENABLED", tmpVal); - - giMPHUseNIV = ( ButtonList[ guiMPHUseNIVToggle ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHUseNIV,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"ALLOW_CUSTOM_NIV", tmpVal); - - giMPHSendFiles = ( ButtonList[ guiMPHSendFiles ]->uiFlags & BUTTON_CLICKED_ON ? 1 : 0 ); - _itow(giMPHSendFiles,tmpVal,10); - props.setStringProperty(L"Ja2_mp Settings",L"SYNC_CLIENTS_MP_DIR", tmpVal); - - guiMPHDifficultLevel = GetMPHCurrentDifficultyButtonSetting(); - CHAR16 tmpDiffStr[2]; - _itow(guiMPHDifficultLevel,tmpDiffStr,10); - props.setStringProperty(L"Ja2_mp Settings",L"DIFFICULT_LEVEL", tmpDiffStr); - props.writeToIniFile(L"Ja2_mp.ini",true); // This writes to the Profiles/UserProfile/ja2_mp.ini -#endif +{ + MpIniExists(); + vfs::PropertyContainer props; + props.initFromIniFile(JA2MP_INI_FILENAME); + + guiMPHMaxPlayers = iMPHMaxPlayers; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_MAX_CLIENTS, guiMPHMaxPlayers); + + guiMPHSquadSize = iMPHSquadSize; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_MAX_MERCS, guiMPHSquadSize); + + guiMPHStartingCash = iMPHStartingCash; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_STARTING_BALANCE, guiMPHStartingCash); + + guiMPHWeaponDamage = iMPHWeaponDamage; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_DAMAGE_MULTIPLIER, guiMPHWeaponDamage); + + guiMPHTimeTurns = iMPHTimeTurns; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_TIMED_TURN_SECS_PER_TICK, guiMPHTimeTurns); + + guiMPHGameType = iMPHGameType; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_GAME_MODE, guiMPHGameType); + + guiMPHStartingTime = iMPHStartingTime; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_TIME, guiMPHStartingTime); + + guiMPHMaxEnemies = GetCurrentMaxEnemiesOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_OVERRIDE_MAX_AI, guiMPHMaxEnemies); + + guiMPHHireMerc = GetCurrentHireMercOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_RANDOM_MERCS, guiMPHHireMerc); + + guiMPHSameMerc = GetCurrentSameMercOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_SAME_MERC, guiMPHSameMerc); + + guiMPHBobbyRay = GetCurrentBobbyRayOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_DISABLE_BOBBY_RAYS, guiMPHBobbyRay); + + guiMPHReportMerc = GetCurrentReportMercOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_REPORT_NAME, guiMPHReportMerc); + + guiMPHSectorEdge = GetCurrentSectorEdgeOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_RANDOM_EDGES, guiMPHSectorEdge); + + guiMPHCivs = GetCurrentCivsOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_CIV_ENABLED, guiMPHCivs); + + guiMPHInventory = iMPHInventory; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_ALLOW_CUSTOM_NIV, guiMPHInventory); + + guiMPHSendFiles = GetCurrentSyncOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_SYNC_CLIENTS_MP_DIR, guiMPHSendFiles); + guiMPHNewTraits = GetMPHCurrentTraitsOptionButtonSetting(); + props.setIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_NEW_TRAITS, guiMPHNewTraits); + guiMPHDifficultLevel = iMPHDifficulty + 1; + props.setIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_DIFFICULT_LEVEL, guiMPHDifficultLevel - 1); + // This writes the data back (from the GUI) to the Profiles/UserProfile/ja2_mp.ini + props.writeToIniFile(JA2MP_INI_FILENAME, false); } bool ValidateMPSettings() -{ - // Check a Server name is entered - Get16BitStringFromField( 0, gzServerNameField, 30 ); // these indexes are based on the order created - if (wcscmp(gzServerNameField,L"")<=0) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_SERVERNAME_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - // Verify the Max Players - Get16BitStringFromField( 1, gzMaxPlayersField, 2 ); - UINT8 numPlayers = _wtoi(gzMaxPlayersField); - if (numPlayers < 2 || numPlayers > 4) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_MAXPLAYERS_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - // Verify the Squad Size - Get16BitStringFromField( 2, gzSquadSizeField, 2 ); - UINT8 squadSize = _wtoi(gzSquadSizeField); - if (squadSize < 1 || squadSize > 6) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_SQUADSIZE_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - // verify the Time of Day - Get16BitStringFromField( 3, gzTimeOfDayField, 6 ); - wchar_t* tok; - bool bTimeOK = true; - int hours = 0; - int mins = 0; - - // strtok is destructive, make a copy to work on - CHAR16 tmpTODStr[6]; - memcpy(tmpTODStr,gzTimeOfDayField,sizeof(CHAR16)*5); - - tok = wcstok(tmpTODStr,L":"); - if (tok != NULL) - { - // Special case, because _wtoi() returns 0 if invalid number! - if (wcscmp(tok, L"00") == 0) - { - hours = 0; - } - else - { - hours = _wtoi(tok); - // check for invalid conversion, ie alpha chars - // wtoi returns 0 if it cant convert, but we need this value - // therefore if tok <> 0 then it was a bad convert. - if (hours == 0 && wcscmp(tok,L"0") != 0) - { - // force error - bTimeOK = false; - } - } - - tok = wcstok(NULL,L"."); - if (tok != NULL) - { - if (wcsnlen(tok, 50) >= 2 && tok[0] == '0' && tok[1] == '0') - { - mins = 0; - } - else - { - mins = _wtoi(tok); - if (mins == 0 && wcscmp(tok,L"0") != 0) - { - // force error - bTimeOK = false; - } - } - - // fix for single digits - if (wcslen(tok) == 1) - mins = mins * 10; - } - else - { - bTimeOK = false; - } - } - else - { - bTimeOK = false; - } - - - if (bTimeOK) - { - giMPHTimeHours = hours; - float ratio = (float)mins / 60.0f; - giMPHTimeMins = (INT16)(ratio * 100); - - } - else - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_TIME_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - - // verify the Starting Balance - Get16BitStringFromField( 4, gzStartingBalanceField, 10 ); - UINT32 sBalance = _wtoi(gzStartingBalanceField); - if (sBalance < 1) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_CASH_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - Get16BitStringFromField( 5, gzDmgMultiplierField, 5 ); - double fDmg = _wtof(gzDmgMultiplierField); - if (fDmg <= 0.0f || fDmg >= 5.0f) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_DMG_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - Get16BitStringFromField( 6, gzTimerField, 6 ); - UINT32 iTimer = _wtoi(gzTimerField); - if (iTimer < 0 || iTimer > 200) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_TIMER_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - - // Verify the File Transfer Directory - Get16BitStringFromField( 7, gzFileTransferDirectory, 100 ); - if (wcscmp(gzFileTransferDirectory,L"")<=0) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_FILE_TRANSFER_DIR_INVALID], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } - -#ifdef USE_VFS +{ vfs::Path sUserDir(gzFileTransferDirectory); - if(!os::createRealDirectory(sUserDir,true)) + if(!vfs::OS::checkRealDirectory(sUserDir)) { DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_FILE_TRANSFER_DIR_NOT_EXIST], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); return false; } -#endif - - //if (!bSkipSyncDir) - //{ -#ifndef USE_VFS - // Check if sync folder exists - STRING512 syncDir; - STRING512 executableDir; - - GetExecutableDirectory(executableDir); - sprintf(syncDir, "%s\\%S", executableDir, gzFileTransferDirectory); - - if (!DirectoryExists(syncDir)) - { - DoMPHMessageBox( MSG_BOX_BASIC_STYLE, gzMPHScreenText[MPH_FILE_TRANSFER_DIR_NOT_EXIST], MP_HOST_SCREEN, MSG_BOX_FLAG_OK, NULL ); - return false; - } -#endif - //} - + return true; } UINT32 MPHostScreenInit( void ) { + memset( &gGameOptions, 0, sizeof( GAME_OPTIONS ) ); + // this is wrong as ScreenInit is called at game start, but the settigs can change anytime // has be called in ScreenEnter for example std::vector szTime(6,0); -#ifndef USE_VFS - // read settings from JA2_mp.ini - GetPrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_NAME", L"Server Name", gzServerNameField, 30, L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"MAX_CLIENTS", L"4", gzMaxPlayersField, 4, L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"MAX_MERCS", L"5", gzSquadSizeField, 5 , L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"STARTING_BALANCE", L"25000", gzStartingBalanceField, 10 , L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"DAMAGE_MULTIPLIER", L"0.7", gzDmgMultiplierField, 5 , L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"TIMED_TURN_SECS_PER_TICK", L"25", gzTimerField, 5 , L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"FILE_TRANSFER_DIRECTORY", L"MULTIPLAYER/Servers/My Server", gzFileTransferDirectory, 100, L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"KIT_BAG", L"[201,214,243]", gzKitBag, 100, L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"TIME", L"13.50", &szTime[0], 5 , L"..\\Ja2_mp.ini" ); - giMPHOverrideMaxAI = GetPrivateProfileIntW( L"Ja2_mp Settings",L"OVERRIDE_MAX_AI", 0, L"..\\Ja2_mp.ini" ); - giMPHRandomMercs = GetPrivateProfileIntW( L"Ja2_mp Settings",L"RANDOM_MERCS", 0, L"..\\Ja2_mp.ini" ); - giMPHSameMercs = GetPrivateProfileIntW( L"Ja2_mp Settings",L"SAME_MERC", 1, L"..\\Ja2_mp.ini" ); - giMPHReportMercs = GetPrivateProfileIntW( L"Ja2_mp Settings",L"REPORT_NAME", 1, L"..\\Ja2_mp.ini" ); - giMPHBobbyRays = GetPrivateProfileIntW( L"Ja2_mp Settings",L"DISABLE_BOBBY_RAYS", 0, L"..\\Ja2_mp.ini" ); - giMPHRandomSpawn = GetPrivateProfileIntW( L"Ja2_mp Settings",L"RANDOM_EDGES", 0, L"..\\Ja2_mp.ini" ); - giMPHEnableCivilians = GetPrivateProfileIntW( L"Ja2_mp Settings",L"CIV_ENABLED", 0, L"..\\Ja2_mp.ini" ); - giMPHUseNIV = GetPrivateProfileIntW( L"Ja2_mp Settings",L"ALLOW_CUSTOM_NIV", 0, L"..\\Ja2_mp.ini" ); - giMPHSendFiles = GetPrivateProfileIntW( L"Ja2_mp Settings",L"SYNC_CLIENTS_MP_DIR", 1, L"..\\Ja2_mp.ini" ); - guiMPHGameType = GetPrivateProfileIntW( L"Ja2_mp Settings",L"GAME_MODE", MP_TYPE_DEATHMATCH, L"..\\Ja2_mp.ini" ); - guiMPHDifficultLevel = GetPrivateProfileIntW( L"Ja2_mp Settings",L"DIFFICULT_LEVEL", 2, L"..\\Ja2_mp.ini" ); -#else // read settings from JA2_mp.ini - CPropertyContainer props; - props.initFromIniFile("Ja2_mp.ini"); - props.getStringProperty( L"Ja2_mp Settings", L"SERVER_NAME", gzServerNameField, 30, L"Server Name"); - props.getStringProperty( L"Ja2_mp Settings", L"MAX_CLIENTS", gzMaxPlayersField, 4, L"4"); - props.getStringProperty( L"Ja2_mp Settings", L"MAX_MERCS", gzSquadSizeField, 5, L"5"); - props.getStringProperty( L"Ja2_mp Settings", L"STARTING_BALANCE", gzStartingBalanceField, 10, L"25000"); - props.getStringProperty( L"Ja2_mp Settings", L"DAMAGE_MULTIPLIER", gzDmgMultiplierField, 5, L"0.7"); - props.getStringProperty( L"Ja2_mp Settings", L"TIMED_TURN_SECS_PER_TICK", gzTimerField, 5, L"25"); - props.getStringProperty( L"Ja2_mp Settings", L"FILE_TRANSFER_DIRECTORY", gzFileTransferDirectory, 100, L"MULTIPLAYER/Servers/My Server"); - props.getStringProperty( L"Ja2_mp Settings", L"KIT_BAG", gzKitBag, 100, L"[201,214,243]"); - props.getStringProperty(L"Ja2_mp Settings", L"TIME", &szTime[0], 6, L"13.50"); + MpIniExists(); + vfs::PropertyContainer props; + props.initFromIniFile(JA2MP_INI_FILENAME); + + // ------------ + // Get the data from ja2_mp.ini + // ------------ - giMPHOverrideMaxAI = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"OVERRIDE_MAX_AI", 0); - giMPHRandomMercs = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"RANDOM_MERCS", 0); - giMPHSameMercs = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"SAME_MERC", 1); - giMPHReportMercs = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"REPORT_NAME", 1); - giMPHBobbyRays = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"DISABLE_BOBBY_RAYS", 0); - giMPHRandomSpawn = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"RANDOM_EDGES", 0); - giMPHEnableCivilians = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"CIV_ENABLED", 0); - giMPHUseNIV = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"ALLOW_CUSTOM_NIV", 0); - giMPHSendFiles = (INT32)props.getIntProperty( L"Ja2_mp Settings",L"SYNC_CLIENTS_MP_DIR", 1); - guiMPHGameType = (UINT8)props.getIntProperty( L"Ja2_mp Settings",L"GAME_MODE", MP_TYPE_DEATHMATCH); - guiMPHDifficultLevel = (UINT8)props.getIntProperty( L"Ja2_mp Settings",L"DIFFICULT_LEVEL", 3); // Expert -#endif + props.getStringProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_SERVER_NAME, gzServerNameField, 30, L"My JA2 Server"); - wchar_t* tok; - bool bTimeOK = true; - int hours = 0; - int mins = 0; - - tok = wcstok(&szTime[0],L"."); - - if (tok != NULL) - { - hours = _wtoi(tok); - // check for invalid conversion, ie alpha chars - // wtoi returns 0 if it cant convert, but we need this value - // therefore if tok <> 0 then it was a bad convert. - if (hours == 0 && wcscmp(tok,L"0") != 0) - { - // force error - bTimeOK = false; - } - - tok = wcstok(NULL,L"."); - if (tok != NULL) - { - mins = _wtoi(tok); - if (mins == 0 && wcscmp(tok,L"0") != 0) - { - // force error - bTimeOK = false; - } - - // fix for single digits - if (wcslen(tok) == 1) - mins = mins * 10; - } - else - { - bTimeOK = false; - } - } - else - { - bTimeOK = false; - } + guiMPHMaxPlayers = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_MAX_CLIENTS, 4); + + guiMPHSquadSize = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_MAX_MERCS, 6); + + guiMPHStartingCash = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_STARTING_BALANCE, 1); + + guiMPHWeaponDamage = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_DAMAGE_MULTIPLIER, 1); + + guiMPHTimeTurns = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_TIMED_TURN_SECS_PER_TICK, 2); + + props.getStringProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_FILE_TRANSFER_DIRECTORY, gzFileTransferDirectory, 100, L"MULTIPLAYER/Servers/My Server"); + + props.getStringProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_KIT_BAG, gzKitBag, 100, L""); + + guiMPHStartingTime = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_TIME, 1); + + guiMPHMaxEnemies = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_OVERRIDE_MAX_AI, 0); + + guiMPHNewTraits = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_NEW_TRAITS, 0); + + // It is not allowed to play with new traits + if (!gGameExternalOptions.fReadProfileDataFromXML) + guiMPHNewTraits = 0; + guiMPHHireMerc = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_RANDOM_MERCS, 0); + + guiMPHSameMerc = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_SAME_MERC, 1); + + guiMPHReportMerc = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_REPORT_NAME, 1); + + guiMPHBobbyRay = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_DISABLE_BOBBY_RAYS, 0); + + guiMPHSectorEdge = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_RANDOM_EDGES, 0); + + guiMPHCivs = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_CIV_ENABLED, 0); + + guiMPHInventory = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_ALLOW_CUSTOM_NIV, 0); + + // It is not allowed to play with NIV + if (!IsNIVModeValid(true)) + guiMPHInventory = 0; - if (bTimeOK) - { - giMPHTimeHours = hours; - float ratio = (float)mins / 100.0f; - giMPHTimeMins = (INT16)(ratio * 60); - swprintf(gzTimeOfDayField,L"%i:%i",giMPHTimeHours,giMPHTimeMins); - } + guiMPHSendFiles = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_SYNC_CLIENTS_MP_DIR, 1); + guiMPHGameType = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_GAME_MODE, MP_TYPE_DEATHMATCH); + + guiMPHDifficultLevel = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_DIFFICULT_LEVEL, 3) + 1; + return( 1 ); } @@ -764,8 +1724,6 @@ UINT32 MPHostScreenHandle( void ) if( gfMPHScreenEntry ) { -// PauseGame(); - // need to reload ja2_mp.ini MPHostScreenInit(); @@ -777,7 +1735,6 @@ UINT32 MPHostScreenHandle( void ) GetMPHScreenUserInput(); - HandleMPHScreen(); // render buttons marked dirty @@ -787,11 +1744,6 @@ UINT32 MPHostScreenHandle( void ) // render text boxes RenderAllTextFields(); // textbox system call - // render help -// RenderFastHelp( ); -// RenderButtonsFastHelp( ); - - ExecuteBaseDirtyRectQueue(); EndFrameBufferRender(); @@ -815,7 +1767,6 @@ UINT32 MPHostScreenHandle( void ) if ( HandleBeginFadeIn( gubMPHExitScreen ) ) { - } if( gfMPHScreenExit ) // we are exiting this screen @@ -824,7 +1775,7 @@ UINT32 MPHostScreenHandle( void ) } return( gubMPHExitScreen ); -} // end MPHoinScreenHandle() +} UINT32 MPHostScreenShutdown( void ) @@ -834,9 +1785,7 @@ UINT32 MPHostScreenShutdown( void ) BOOLEAN EnterMPHScreen() { - VOBJECT_DESC VObjectDesc; - UINT16 cnt; - UINT16 usPosY; + VOBJECT_DESC VObjectDesc, VObjectDesc2; if( gfMPHButtonsAllocated ) return( TRUE ); @@ -861,6 +1810,10 @@ BOOLEAN EnterMPHScreen() CHECKF(AddVideoObject(&VObjectDesc, &guiMPHMainBackGroundImage )); + VObjectDesc2.fCreateFlags=VOBJECT_CREATE_FROMFILE; + FilenameForBPP("INTERFACE\\GIOSmallFrame.sti", VObjectDesc2.ImageFile); + CHECKF(AddVideoObject(&VObjectDesc2, &guiMPHSMALLFRAME)); + //Join button giMPHStartBtnImage = LoadButtonImage("INTERFACE\\PreferencesButtons.sti", -1,0,-1,2,-1 ); guiMPHStartButton = CreateIconAndTextButton( giMPHStartBtnImage, gzMPHScreenText[MPH_START_TEXT], OPT_BUTTON_FONT, @@ -895,204 +1848,483 @@ BOOLEAN EnterMPHScreen() SetTextInputRegularColors( FONT_WHITE, 2 ); SetTextInputHilitedColors( 2, FONT_WHITE, FONT_WHITE ); SetCursorColor( Get16BPPColor(FROMRGB(255, 255, 255) ) ); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // MAX PLAYERS - //AddUserInputField( NULL ); // API Call that sets a special input-handling routine and method for the TAB key + giMPHMaxPlayersButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHMaxPlayersButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); - //Add Player Name textbox - AddTextInputField( MPH_TXT_SVRNAME_X, - MPH_TXT_SVRNAME_Y, - MPH_TXT_SVRNAME_WIDTH, - MPH_TXT_SVRNAME_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzServerNameField, - 30, - INPUTTYPE_ASCII );//23 + // left button - decrement difficulty level + giMPHMaxPlayersButton[ 0 ] = QuickCreateButton( giMPHMaxPlayersButtonImage[ 0 ], MPH_MAXPLAYERS_SETTING_X + 39, MPH_MAXPLAYERS_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHMaxPlayersSelectionLeftCallback ); - //Add Num Players textbox - AddTextInputField( MPH_TXT_MAXPLAYERS_X, - MPH_TXT_MAXPLAYERS_Y, - MPH_TXT_MAXPLAYERS_WIDTH, - MPH_TXT_MAXPLAYERS_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzMaxPlayersField, - 2, - INPUTTYPE_ASCII );//23 + // right button - increment difficulty level + giMPHMaxPlayersButton[ 1 ] = QuickCreateButton( giMPHMaxPlayersButtonImage[ 1 ], MPH_MAXPLAYERS_SETTING_X + 158, MPH_MAXPLAYERS_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHMaxPlayersSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHMaxPlayersButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHMaxPlayersButton[1],0, 1 ); - //Add Squad Size textbox - AddTextInputField( MPH_TXT_SQUAD_X, - MPH_TXT_SQUAD_Y, - MPH_TXT_SQUAD_WIDTH, - MPH_TXT_SQUAD_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzSquadSizeField, - 2, - INPUTTYPE_ASCII );//23 + iMPHMaxPlayers = guiMPHMaxPlayers; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // SQUAD SIZE - //Add Time of day textbox - AddTextInputField( MPH_TXT_TIME_X, - MPH_TXT_TIME_Y, - MPH_TXT_TIME_WIDTH, - MPH_TXT_TIME_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzTimeOfDayField, - 5, - INPUTTYPE_ASCII );//23 + giMPHSquadSizeButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHSquadSizeButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); - //Add Starting Cash textbox - AddTextInputField( MPH_TXT_CASH_X, - MPH_TXT_CASH_Y, - MPH_TXT_CASH_WIDTH, - MPH_TXT_CASH_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzStartingBalanceField, - 10, - INPUTTYPE_ASCII );//23 + // left button - decrement difficulty level + giMPHSquadSizeButton[ 0 ] = QuickCreateButton( giMPHSquadSizeButtonImage[ 0 ], MPH_SQUADSIZE_SETTING_X + 39, MPH_SQUADSIZE_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHSquadSizeSelectionLeftCallback ); - //Add Damage Multiplyer textbox - AddTextInputField( MPH_TXT_DMG_X, - MPH_TXT_DMG_Y, - MPH_TXT_DMG_WIDTH, - MPH_TXT_DMG_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzDmgMultiplierField, - 5, - INPUTTYPE_ASCII );//23 + // right button - increment difficulty level + giMPHSquadSizeButton[ 1 ] = QuickCreateButton( giMPHSquadSizeButtonImage[ 1 ], MPH_SQUADSIZE_SETTING_X + 158, MPH_SQUADSIZE_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHSquadSizeSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHSquadSizeButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHSquadSizeButton[1],0, 1 ); - //Add Turn Timer textbox - AddTextInputField( MPH_TXT_TIMER_X, - MPH_TXT_TIMER_Y, - MPH_TXT_TIMER_WIDTH, - MPH_TXT_TIMER_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzTimerField, - 5, - INPUTTYPE_ASCII );//23 + iMPHSquadSize= guiMPHSquadSize; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // STARTING TIME - //Add File transfer directory textbox - AddTextInputField( MPH_TXT_FILE_TRANSFER_DIR_X, - MPH_TXT_FILE_TRANSFER_DIR_Y, - MPH_TXT_FILE_TRANSFER_DIR_WIDTH, - MPH_TXT_FILE_TRANSFER_DIR_HEIGHT, - MSYS_PRIORITY_HIGH+2, - gzFileTransferDirectory, - 100, - INPUTTYPE_ASCII ); + giMPHStartingTimeButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHStartingTimeButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); + // left button - decrement difficulty level + giMPHStartingTimeButton[ 0 ] = QuickCreateButton( giMPHStartingTimeButtonImage[ 0 ], MPH_STARTINGTIME_SETTING_X + 39, MPH_STARTINGTIME_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHStartingTimeSelectionLeftCallback ); - SetActiveField( 0 ); // Playername textbox has focus + // right button - increment difficulty level + giMPHStartingTimeButton[ 1 ] = QuickCreateButton( giMPHStartingTimeButtonImage[ 1 ], MPH_STARTINGTIME_SETTING_X + 158, MPH_STARTINGTIME_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHStartingTimeSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHStartingTimeButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHStartingTimeButton[1],0, 1 ); + iMPHStartingTime = guiMPHStartingTime; - // - //Check box to toggle Difficulty settings - // - usPosY = MPH_DIF_SETTINGS_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y; + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // STARTING CASH - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; - else if( guiMPHDifficultLevel == DIF_LEVEL_INSANE ) - ButtonList[ guiMPHDifficultySettingsToggles[ MPH_DIFF_INSANE ] ]->uiFlags |= BUTTON_CLICKED_ON; + // right button - increment difficulty level + giMPHStartingCashButton[ 1 ] = QuickCreateButton( giMPHStartingCashButtonImage[ 1 ], MPH_STARTINGCASH_SETTING_X + 158, MPH_STARTINGCASH_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHStartingCashSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHStartingCashButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHStartingCashButton[1],0, 1 ); + + iMPHStartingCash = guiMPHStartingCash; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // WEAPON DAMAGE + + giMPHWeaponDamageButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHWeaponDamageButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giMPHWeaponDamageButton[ 0 ] = QuickCreateButton( giMPHWeaponDamageButtonImage[ 0 ], MPH_WEAPONDAMAGE_SETTING_X + 39, MPH_WEAPONDAMAGE_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHWeaponDamageSelectionLeftCallback ); + + // right button - increment difficulty level + giMPHWeaponDamageButton[ 1 ] = QuickCreateButton( giMPHWeaponDamageButtonImage[ 1 ], MPH_WEAPONDAMAGE_SETTING_X + 158, MPH_WEAPONDAMAGE_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHWeaponDamageSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHWeaponDamageButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHWeaponDamageButton[1],0, 1 ); + + iMPHWeaponDamage = guiMPHWeaponDamage; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // TIME TURNS + + giMPHTimeTurnsButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHTimeTurnsButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giMPHTimeTurnsButton[ 0 ] = QuickCreateButton( giMPHTimeTurnsButtonImage[ 0 ], MPH_TIMETURNS_SETTING_X + 39, MPH_TIMETURNS_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHTimeTurnsSelectionLeftCallback ); + + // right button - increment difficulty level + giMPHTimeTurnsButton[ 1 ] = QuickCreateButton( giMPHTimeTurnsButtonImage[ 1 ], MPH_TIMETURNS_SETTING_X + 158, MPH_TIMETURNS_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHTimeTurnsSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHTimeTurnsButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHTimeTurnsButton[1],0, 1 ); + + iMPHTimeTurns = guiMPHTimeTurns; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // DIFFICULTY SETTING + + giMPHDifficultyButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHDifficultyButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giMPHDifficultyButton[ 0 ] = QuickCreateButton( giMPHDifficultyButtonImage[ 0 ], MPH_DIFFICULTY_SETTING_X + 39, MPH_DIFFICULTY_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHDifficultySelectionLeftCallback ); + + // right button - increment difficulty level + giMPHDifficultyButton[ 1 ] = QuickCreateButton( giMPHDifficultyButtonImage[ 1 ], MPH_DIFFICULTY_SETTING_X + 158, MPH_DIFFICULTY_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHDifficultySelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHDifficultyButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHDifficultyButton[1],0, 1 ); + + iMPHDifficulty = guiMPHDifficultLevel - 1; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // GAME TYPE + + giMPHGameTypeButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,0,-1,1,-1 ); + giMPHGameTypeButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\GIO_SELECTION_ARROWS.STI" ,-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giMPHGameTypeButton[ 0 ] = QuickCreateButton( giMPHGameTypeButtonImage[ 0 ], MPH_GAMETYPE_SETTING_X + 39, MPH_GAMETYPE_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHGameTypeSelectionLeftCallback ); + + // right button - increment difficulty level + giMPHGameTypeButton[ 1 ] = QuickCreateButton( giMPHGameTypeButtonImage[ 1 ], MPH_GAMETYPE_SETTING_X + 158, MPH_GAMETYPE_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHGameTypeSelectionRightCallback ); + + // set user data + MSYS_SetBtnUserData(giMPHGameTypeButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHGameTypeButton[1],0, 1 ); + + iMPHGameType = guiMPHGameType; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // MAX ENEMIES + + guiMPHMaxEnemiesOptionTogglesImage[ MPH_MAXENEMIES_NO ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_NO ] = CreateIconAndTextButton( guiMPHMaxEnemiesOptionTogglesImage[ MPH_MAXENEMIES_NO ], gzMPHScreenText[ MPH_NO ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_MAXENEMIES_SETTING_X + 74), (MPH_MAXENEMIES_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHNoMaxEnemiesCallback); + + guiMPHMaxEnemiesOptionTogglesImage[ MPH_MAXENEMIES_YES ] = UseLoadedButtonImage( guiMPHMaxEnemiesOptionTogglesImage[ MPH_MAXENEMIES_NO ], -1,1,-1,3,-1 ); + guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_YES ] = CreateIconAndTextButton( guiMPHMaxEnemiesOptionTogglesImage[ MPH_MAXENEMIES_YES ], gzMPHScreenText[ MPH_YES ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_MAXENEMIES_SETTING_X), (MPH_MAXENEMIES_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHYesMaxEnemiesCallback ); + + SpecifyButtonSoundScheme( guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_NO ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_YES ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_NO ],0, 0 ); + MSYS_SetBtnUserData(guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_YES ],0, 1 ); + + if( guiMPHMaxEnemies ) + ButtonList[ guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_YES ] ]->uiFlags |= BUTTON_CLICKED_ON; else - ButtonList[ guiMPHDifficultySettingsToggles[ MPH_DIFF_HARD ] ]->uiFlags |= BUTTON_CLICKED_ON; + ButtonList[ guiMPHMaxEnemiesOptionToggles[ MPH_MAXENEMIES_NO ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // HIRE MERC + + guiMPHHireMercOptionTogglesImage[ MPH_HIREMERC_RANDOM ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHHireMercOptionToggles[ MPH_HIREMERC_RANDOM ] = CreateIconAndTextButton( guiMPHHireMercOptionTogglesImage[ MPH_HIREMERC_RANDOM ], gzMPHScreenText[ MPH_HIRE_RANDOM ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_HIREMERC_SETTING_X + 74), (MPH_HIREMERC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHRandomHireMercCallback); + + guiMPHHireMercOptionTogglesImage[ MPH_HIREMERC_NORMAL ] = UseLoadedButtonImage( guiMPHHireMercOptionTogglesImage[ MPH_HIREMERC_RANDOM ], -1,1,-1,3,-1 ); + guiMPHHireMercOptionToggles[ MPH_HIREMERC_NORMAL ] = CreateIconAndTextButton( guiMPHHireMercOptionTogglesImage[ MPH_HIREMERC_NORMAL ], gzMPHScreenText[ MPH_HIRE_NORMAL ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_HIREMERC_SETTING_X), (MPH_HIREMERC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHNormalHireMercCallback ); + + SpecifyButtonSoundScheme( guiMPHHireMercOptionToggles[ MPH_HIREMERC_RANDOM ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHHireMercOptionToggles[ MPH_HIREMERC_NORMAL ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHHireMercOptionToggles[ MPH_HIREMERC_RANDOM ],0, 0 ); + MSYS_SetBtnUserData(guiMPHHireMercOptionToggles[ MPH_HIREMERC_NORMAL ],0, 1 ); + + if( guiMPHHireMerc ) + ButtonList[ guiMPHHireMercOptionToggles[ MPH_HIREMERC_RANDOM ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHHireMercOptionToggles[ MPH_HIREMERC_NORMAL ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // SAME MERC + + guiMPHSameMercOptionTogglesImage[ MPH_SAMEMERC_DISABLE ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHSameMercOptionToggles[ MPH_SAMEMERC_DISABLE ] = CreateIconAndTextButton( guiMPHSameMercOptionTogglesImage[ MPH_SAMEMERC_DISABLE ], gzMPHScreenText[ MPH_DISABLE ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_SAMEMERC_SETTING_X + 74), (MPH_SAMEMERC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHDisableSameMercCallback); + + guiMPHSameMercOptionTogglesImage[ MPH_SAMEMERC_ALLOW ] = UseLoadedButtonImage( guiMPHSameMercOptionTogglesImage[ MPH_SAMEMERC_DISABLE ], -1,1,-1,3,-1 ); + guiMPHSameMercOptionToggles[ MPH_SAMEMERC_ALLOW ] = CreateIconAndTextButton( guiMPHSameMercOptionTogglesImage[ MPH_SAMEMERC_ALLOW ], gzMPHScreenText[ MPH_ALLOW ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_SAMEMERC_SETTING_X), (MPH_SAMEMERC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHAllowSameMercCallback ); + + SpecifyButtonSoundScheme( guiMPHSameMercOptionToggles[ MPH_SAMEMERC_DISABLE ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHSameMercOptionToggles[ MPH_SAMEMERC_ALLOW ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHSameMercOptionToggles[ MPH_SAMEMERC_DISABLE ],0, 0 ); + MSYS_SetBtnUserData(guiMPHSameMercOptionToggles[ MPH_SAMEMERC_ALLOW ],0, 1 ); + + if( guiMPHSameMerc ) + ButtonList[ guiMPHSameMercOptionToggles[ MPH_SAMEMERC_ALLOW ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHSameMercOptionToggles[ MPH_SAMEMERC_DISABLE ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // REPORT MERC + + guiMPHReportMercOptionTogglesImage[ MPH_REPORTMERC_NO ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHReportMercOptionToggles[ MPH_REPORTMERC_NO ] = CreateIconAndTextButton( guiMPHReportMercOptionTogglesImage[ MPH_REPORTMERC_NO ], gzMPHScreenText[ MPH_NO ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_REPORTMERC_SETTING_X + 74), (MPH_REPORTMERC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHNoReportMercCallback); + + guiMPHReportMercOptionTogglesImage[ MPH_REPORTMERC_YES ] = UseLoadedButtonImage( guiMPHReportMercOptionTogglesImage[ MPH_REPORTMERC_NO ], -1,1,-1,3,-1 ); + guiMPHReportMercOptionToggles[ MPH_REPORTMERC_YES ] = CreateIconAndTextButton( guiMPHReportMercOptionTogglesImage[ MPH_REPORTMERC_YES ], gzMPHScreenText[ MPH_YES ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_REPORTMERC_SETTING_X), (MPH_REPORTMERC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHYesReportMercCallback ); + + SpecifyButtonSoundScheme( guiMPHReportMercOptionToggles[ MPH_REPORTMERC_NO ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHReportMercOptionToggles[ MPH_REPORTMERC_YES ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHReportMercOptionToggles[ MPH_REPORTMERC_NO ],0, 0 ); + MSYS_SetBtnUserData(guiMPHReportMercOptionToggles[ MPH_REPORTMERC_YES ],0, 1 ); + + if( guiMPHReportMerc ) + ButtonList[ guiMPHReportMercOptionToggles[ MPH_REPORTMERC_YES ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHReportMercOptionToggles[ MPH_REPORTMERC_NO ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // BOBBY RAY + + guiMPHBobbyRayOptionTogglesImage[ MPH_BOBBYRAY_DISABLE ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_DISABLE ] = CreateIconAndTextButton( guiMPHBobbyRayOptionTogglesImage[ MPH_BOBBYRAY_DISABLE ], gzMPHScreenText[ MPH_DISABLE ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_BOBBYRAY_SETTING_X + 74), (MPH_BOBBYRAY_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHDisableBobbyRayCallback); + + guiMPHBobbyRayOptionTogglesImage[ MPH_BOBBYRAY_ALLOW ] = UseLoadedButtonImage( guiMPHBobbyRayOptionTogglesImage[ MPH_BOBBYRAY_DISABLE ], -1,1,-1,3,-1 ); + guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_ALLOW ] = CreateIconAndTextButton( guiMPHBobbyRayOptionTogglesImage[ MPH_BOBBYRAY_ALLOW ], gzMPHScreenText[ MPH_ALLOW ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_BOBBYRAY_SETTING_X), (MPH_BOBBYRAY_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHAllowBobbyRayCallback ); + + SpecifyButtonSoundScheme( guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_DISABLE ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_ALLOW ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_DISABLE ],0, 0 ); + MSYS_SetBtnUserData(guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_ALLOW ],0, 1 ); + + if( guiMPHBobbyRay ) + ButtonList[ guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_DISABLE ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHBobbyRayOptionToggles[ MPH_BOBBYRAY_ALLOW ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // SECTOR EDGE + + guiMPHSectorEdgeOptionTogglesImage[ MPH_SECTOREDGE_RANDOM ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_RANDOM ] = CreateIconAndTextButton( guiMPHSectorEdgeOptionTogglesImage[ MPH_SECTOREDGE_RANDOM ], gzMPHScreenText[ MPH_EDGE_RANDOM ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_SECTOREDGE_SETTING_X + 74), (MPH_SECTOREDGE_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHRandomSectorEdgeCallback); + + guiMPHSectorEdgeOptionTogglesImage[ MPH_SECTOREDGE_SELECTABLE ] = UseLoadedButtonImage( guiMPHSectorEdgeOptionTogglesImage[ MPH_SECTOREDGE_RANDOM ], -1,1,-1,3,-1 ); + guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_SELECTABLE ] = CreateIconAndTextButton( guiMPHSectorEdgeOptionTogglesImage[ MPH_SECTOREDGE_SELECTABLE ], gzMPHScreenText[ MPH_EDGE_SELECTABLE ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_SECTOREDGE_SETTING_X), (MPH_SECTOREDGE_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHSelectableSectorEdgeCallback ); + + SpecifyButtonSoundScheme( guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_RANDOM ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_SELECTABLE ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_RANDOM ],0, 0 ); + MSYS_SetBtnUserData(guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_SELECTABLE ],0, 1 ); + + if( guiMPHSectorEdge ) + ButtonList[ guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_RANDOM ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHSectorEdgeOptionToggles[ MPH_SECTOREDGE_SELECTABLE ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // CIVS + + guiMPHCivsOptionTogglesImage[ MPH_CIVS_NO ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHCivsOptionToggles[ MPH_CIVS_NO ] = CreateIconAndTextButton( guiMPHCivsOptionTogglesImage[ MPH_CIVS_NO ], gzMPHScreenText[ MPH_NO ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_CIVS_SETTING_X + 74), (MPH_CIVS_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHNoCivsCallback); + + guiMPHCivsOptionTogglesImage[ MPH_CIVS_YES ] = UseLoadedButtonImage( guiMPHCivsOptionTogglesImage[ MPH_CIVS_NO ], -1,1,-1,3,-1 ); + guiMPHCivsOptionToggles[ MPH_CIVS_YES ] = CreateIconAndTextButton( guiMPHCivsOptionTogglesImage[ MPH_CIVS_YES ], gzMPHScreenText[ MPH_YES ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_CIVS_SETTING_X), (MPH_CIVS_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHYesCivsCallback ); + + SpecifyButtonSoundScheme( guiMPHCivsOptionToggles[ MPH_CIVS_NO ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHCivsOptionToggles[ MPH_CIVS_YES ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHCivsOptionToggles[ MPH_CIVS_NO ],0, 0 ); + MSYS_SetBtnUserData(guiMPHCivsOptionToggles[ MPH_CIVS_YES ],0, 1 ); + + if( guiMPHCivs ) + ButtonList[ guiMPHCivsOptionToggles[ MPH_CIVS_YES ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHCivsOptionToggles[ MPH_CIVS_NO ] ]->uiFlags |= BUTTON_CLICKED_ON; + // ------------------------------------------------- + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // INVENTORY / ATTACHMENT + + if (IsNIVModeValid(true)) + { + giMPHInventoryButtonImage[ 0 ]= UseLoadedButtonImage( giMPHDifficultyButtonImage[ 0 ],-1,0,-1,1,-1 ); + giMPHInventoryButtonImage[ 1 ]= UseLoadedButtonImage( giMPHDifficultyButtonImage[ 1 ],-1,2,-1,3,-1 ); + + // left button - decrement difficulty level + giMPHInventoryButton[ 0 ] = QuickCreateButton( giMPHInventoryButtonImage[ 0 ], MPH_INVENTORY_SETTING_X + 39, MPH_INVENTORY_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHInventorySelectionLeftCallback ); + + // right button - increment difficulty level + giMPHInventoryButton[ 1 ] = QuickCreateButton( giMPHInventoryButtonImage[ 1 ], MPH_INVENTORY_SETTING_X + 158, MPH_INVENTORY_SETTING_Y , + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, + BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMPHInventorySelectionRightCallback ); - // - //Check box to toggle GameType settings - // - usPosY = MPH_GAMETYPE_SETTINGS_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y; + // set user data + MSYS_SetBtnUserData(giMPHInventoryButton[0],0, 0 ); + MSYS_SetBtnUserData(giMPHInventoryButton[1],0, 1 ); - for( cnt=0; cntuiFlags |= BUTTON_CLICKED_ON; + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // OLD/NEW TARITS SETTING - // Override Max AI - guiMPHOverrideMaxAIToggle = CreateCheckBoxButton( MPH_OVERRIDEMAXAI_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_OVERRIDEMAXAI_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHOverrideMaxAICallback ); - if ( giMPHOverrideMaxAI ) - ButtonList[ guiMPHOverrideMaxAIToggle ]->uiFlags |= BUTTON_CLICKED_ON; + guiMPHTraitsOptionTogglesImage[ MPH_TRAITS_OLD ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHTraitsOptionToggles[ MPH_TRAITS_OLD ] = CreateIconAndTextButton( guiMPHTraitsOptionTogglesImage[ MPH_TRAITS_OLD ], gzGIOScreenText[ GIO_TRAITS_OLD_TEXT ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_TRAITS_SETTING_X + 74), (MPH_TRAITS_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHOldTraitsCallback); - // Random Mercs - guiMPHRandomMercsToggle = CreateCheckBoxButton( MPH_RNDMERC_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_RNDMERC_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHRandomMercCallback ); - if ( giMPHRandomMercs ) - ButtonList[ guiMPHRandomMercsToggle ]->uiFlags |= BUTTON_CLICKED_ON; + guiMPHTraitsOptionTogglesImage[ MPH_TRAITS_NEW ] = UseLoadedButtonImage( guiMPHTraitsOptionTogglesImage[ MPH_TRAITS_OLD ], -1,1,-1,3,-1 ); + guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ] = CreateIconAndTextButton( guiMPHTraitsOptionTogglesImage[ MPH_TRAITS_NEW ], gzGIOScreenText[ GIO_TRAITS_NEW_TEXT ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_TRAITS_SETTING_X), (MPH_TRAITS_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHNewTraitsCallback ); - //checkbox for same merc - guiMPHSameMercToggle = CreateCheckBoxButton( MPH_SAMEMERC_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_SAMEMERC_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHSameMercCallback ); - if ( giMPHSameMercs ) - ButtonList[ guiMPHSameMercToggle ]->uiFlags |= BUTTON_CLICKED_ON; + SpecifyButtonSoundScheme( guiMPHTraitsOptionToggles[ MPH_TRAITS_OLD ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHTraitsOptionToggles[ MPH_TRAITS_OLD ],0, 0 ); + MSYS_SetBtnUserData(guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ],0, 1 ); - //checkbox for report purchase - guiMPHReportMercToggle = CreateCheckBoxButton( MPH_REPORTMERC_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_REPORTMERC_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHReportMercCallback ); - if (giMPHReportMercs) - ButtonList[ guiMPHReportMercToggle ]->uiFlags |= BUTTON_CLICKED_ON; + if( guiMPHNewTraits ) + ButtonList[ guiMPHTraitsOptionToggles[ MPH_TRAITS_NEW ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHTraitsOptionToggles[ MPH_TRAITS_OLD ] ]->uiFlags |= BUTTON_CLICKED_ON; + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // SYNC GAME DIR - //checkbox for bobby rays - guiMPHBobbyRayToggle = CreateCheckBoxButton( MPH_BOBBYRAY_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_BOBBYRAY_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHBobbyRayCallback ); + guiMPHSyncOptionTogglesImage[ MPH_SYNC_NO ] = LoadButtonImage( "INTERFACE\\GIOCheckButton.sti" ,-1,0,-1,2,-1 ); + guiMPHSyncOptionToggles[ MPH_SYNC_NO ] = CreateIconAndTextButton( guiMPHSyncOptionTogglesImage[ MPH_SYNC_NO ], gzMPHScreenText[ MPH_NO ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_SYNC_SETTING_X + 74), (MPH_SYNC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHNoSyncCallback); - if (!giMPHBobbyRays) - ButtonList[ guiMPHBobbyRayToggle ]->uiFlags |= BUTTON_CLICKED_ON; // the setting is actually DISABLE / NEGATIVE - - //checkbox for random spawn pos - guiMPHRandomSpawnToggle = CreateCheckBoxButton( MPH_RNDSPAWN_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_RNDSPAWN_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHRandomSpawnCallback ); - - if (giMPHRandomSpawn) - ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags |= BUTTON_CLICKED_ON; - - // checkbox for civillians - guiMPHCivsToggle = CreateCheckBoxButton( MPH_CIVS_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_CIVS_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHCivsCallback ); - if (giMPHEnableCivilians) - ButtonList[ guiMPHCivsToggle ]->uiFlags |= BUTTON_CLICKED_ON; - - // checkbox for use NIV - guiMPHUseNIVToggle = CreateCheckBoxButton( MPH_USENIV_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_USENIV_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHUseNIVCallback ); - if (giMPHUseNIV) - ButtonList[ guiMPHUseNIVToggle ]->uiFlags |= BUTTON_CLICKED_ON; - - - // checkbox for send files to clients - guiMPHSendFiles = CreateCheckBoxButton( MPH_SEND_FILES_X+MPH_OFFSET_TO_TOGGLE_BOX, MPH_SEND_FILES_Y - MPH_OFFSET_TO_TOGGLE_BOX_Y, - "INTERFACE\\OptionsCheck.sti", MSYS_PRIORITY_HIGH+10, - BtnMPHSendFilesCallback ); - - if (giMPHSendFiles) - ButtonList[ guiMPHSendFiles ]->uiFlags |= BUTTON_CLICKED_ON; + guiMPHSyncOptionTogglesImage[ MPH_SYNC_YES ] = UseLoadedButtonImage( guiMPHSyncOptionTogglesImage[ MPH_SYNC_NO ], -1,1,-1,3,-1 ); + guiMPHSyncOptionToggles[ MPH_SYNC_YES ] = CreateIconAndTextButton( guiMPHSyncOptionTogglesImage[ MPH_SYNC_YES ], gzMPHScreenText[ MPH_YES ], MPH_TOGGLE_TEXT_FONT, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + MPH_TOGGLE_TEXT_COLOR, NO_SHADOW, + TEXT_CJUSTIFIED, + (MPH_SYNC_SETTING_X), (MPH_SYNC_SETTING_Y + 10), BUTTON_TOGGLE, MSYS_PRIORITY_HIGH, + DEFAULT_MOVE_CALLBACK, BtnMPHYesSyncCallback ); + SpecifyButtonSoundScheme( guiMPHSyncOptionToggles[ MPH_SYNC_NO ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + SpecifyButtonSoundScheme( guiMPHSyncOptionToggles[ MPH_SYNC_YES ], BUTTON_SOUND_SCHEME_BIGSWITCH3 ); + MSYS_SetBtnUserData(guiMPHSyncOptionToggles[ MPH_SYNC_NO ],0, 0 ); + MSYS_SetBtnUserData(guiMPHSyncOptionToggles[ MPH_SYNC_YES ],0, 1 ); + if( guiMPHSendFiles ) + ButtonList[ guiMPHSyncOptionToggles[ MPH_SYNC_YES ] ]->uiFlags |= BUTTON_CLICKED_ON; + else + ButtonList[ guiMPHSyncOptionToggles[ MPH_SYNC_NO ] ]->uiFlags |= BUTTON_CLICKED_ON; + //Reset the exit screen - screen the main game loop will call next iteration gubMPHExitScreen = MP_HOST_SCREEN; @@ -1106,8 +2338,7 @@ BOOLEAN EnterMPHScreen() return( TRUE ); -} // End of EnterMPHScreen() - +} BOOLEAN ExitMPHScreen() { @@ -1119,30 +2350,169 @@ BOOLEAN ExitMPHScreen() //Delete the main options screen background DeleteVideoObjectFromIndex( guiMPHMainBackGroundImage ); + DeleteVideoObjectFromIndex( guiMPHSMALLFRAME ); + RemoveButton( guiMPHStartButton ); RemoveButton( guiMPHCancelButton ); - UnloadButtonImage( giMPHCancelBtnImage ); UnloadButtonImage( giMPHStartBtnImage ); - //Check box to toggle Difficulty settings - for( cnt=0; cnt review this, i think MPH_EXIT is the proceed mode... - //if( gubMPHScreenHandler == MPH_EXIT ) - // SetMusicMode( MUSIC_NONE ); - gfMPHScreenExit = FALSE; gfMPHScreenEntry = TRUE; return( TRUE ); -} // End of ExitMPHScreen() +} void HandleMPHScreen() @@ -1173,8 +2538,6 @@ void HandleMPHScreen() gubMPHExitScreen = MAINMENU_SCREEN; gfMPHScreenExit = TRUE; break; - - case MPH_START: { //if we are already fading out, get out of here @@ -1189,27 +2552,66 @@ void HandleMPHScreen() } break; } - } gubMPHScreenHandler = MPH_NOTHING; } - if( gfReRenderMPHScreen ) { RenderMPHScreen(); gfReRenderMPHScreen = FALSE; - } - - RestoreMPHButtonBackGrounds(); -} // end of HandleMPHScreen - + } +} BOOLEAN RenderMPHScreen() { HVOBJECT hPixHandle; - UINT16 usPosY; + + // -------------------------- + // Difficulty + RestoreExternBackgroundRect( MPH_DIFFICULTY_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_DIFFICULTY_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // MaxPlayers + RestoreExternBackgroundRect( MPH_MAXPLAYERS_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_MAXPLAYERS_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // StartingTime + RestoreExternBackgroundRect( MPH_STARTINGTIME_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_STARTINGTIME_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // StartingCash + RestoreExternBackgroundRect( MPH_STARTINGCASH_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_STARTINGCASH_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // WeaponDamage + RestoreExternBackgroundRect( MPH_WEAPONDAMAGE_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_WEAPONDAMAGE_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // TimeTurns + RestoreExternBackgroundRect( MPH_TIMETURNS_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_TIMETURNS_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // SquadSize + RestoreExternBackgroundRect( MPH_SQUADSIZE_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_SQUADSIZE_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // GameType + RestoreExternBackgroundRect( MPH_GAMETYPE_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_GAMETYPE_SETTING_Y-3, 120, 20 ); + // -------------------------- + + // -------------------------- + // Inventory + RestoreExternBackgroundRect( MPH_INVENTORY_SETTING_X+MPH_OFFSET_TO_TEXT + 20, MPH_INVENTORY_SETTING_Y-3, 120, 20 ); + // -------------------------- //Get the main background screen graphic and blt it GetVideoObject(&hPixHandle, guiMPHMainBackGroundImage ); @@ -1221,86 +2623,116 @@ BOOLEAN RenderMPHScreen() //Display the title DrawTextToScreen( gzMPHScreenText[ MPH_TITLE_TEXT ], MPH_MAIN_TITLE_X, MPH_MAIN_TITLE_Y, MPH_MAIN_TITLE_WIDTH, MPH_TITLE_FONT, MPH_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); - // Server name text label - DisplayWrappedString( MPH_LABEL_SVRNAME_X, MPH_LABEL_SVRNAME_Y, MPH_LABEL_SVRNAME_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_SERVERNAME_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // --------- + // MaxPlayers + RenderMPHSmallSelectionFrame( (MPH_MAXPLAYERS_SETTING_X + 36), (MPH_MAXPLAYERS_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_MAXPLAYERS_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_MAXPLAYERS_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_MAXPLAYERS_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_NUMPLAYERS_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_MAXPLAYERS_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_MAXPLAYERS_SETTING_Y+6), MPH_MAXPLAYERS_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ (MPH_1 - MPH_MAXPLAYERS_2 + 1) + iMPHMaxPlayers ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ----------------- - // Num Players text label - DisplayWrappedString( MPH_LABEL_MAXPLAYERS_X, MPH_LABEL_MAXPLAYERS_Y, MPH_LABEL_MAXPLAYERS_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_NUMPLAYERS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ----------------- + // SquadSize + RenderMPHSmallSelectionFrame( (MPH_SQUADSIZE_SETTING_X + 36), (MPH_SQUADSIZE_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_SQUADSIZE_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_SQUADSIZE_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_SQUADSIZE_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_SQUADSIZE_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_SQUADSIZE_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_SQUADSIZE_SETTING_Y+6), MPH_SQUADSIZE_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ (MPH_1 - MPH_SQUADSIZE_1) + iMPHSquadSize ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ----------------- - // Squad Size text label - DisplayWrappedString( MPH_LABEL_SQUAD_X, MPH_LABEL_SQUAD_Y, MPH_LABEL_SQUAD_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_SQUADSIZE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ---------- + // StartingTime + RenderMPHSmallSelectionFrame( (MPH_STARTINGTIME_SETTING_X + 36), (MPH_STARTINGTIME_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_STARTINGTIME_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_STARTINGTIME_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_STARTINGTIME_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_TIME_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_STARTINGTIME_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_STARTINGTIME_SETTING_Y+6), MPH_STARTINGTIME_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_MORNING + iMPHStartingTime ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ----------------- - // Time Of day text label - DisplayWrappedString( MPH_LABEL_TIME_X, MPH_LABEL_TIME_Y, MPH_LABEL_TIME_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_TIME_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ------------------ + // StartingCash + RenderMPHSmallSelectionFrame( (MPH_STARTINGCASH_SETTING_X + 36), (MPH_STARTINGCASH_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_STARTINGCASH_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_STARTINGCASH_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_STARTINGCASH_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_BALANCE_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_STARTINGCASH_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_STARTINGCASH_SETTING_Y+6), MPH_STARTINGCASH_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_CASH_LOW + iMPHStartingCash ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ----------------- - // Starting Cash text label - DisplayWrappedString( MPH_LABEL_CASH_X, MPH_LABEL_CASH_Y, MPH_LABEL_CASH_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_BALANCE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ---------- + // WeaponDamage + RenderMPHSmallSelectionFrame( (MPH_WEAPONDAMAGE_SETTING_X + 36), (MPH_WEAPONDAMAGE_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_WEAPONDAMAGE_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_WEAPONDAMAGE_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_WEAPONDAMAGE_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_DMG_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_WEAPONDAMAGE_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_WEAPONDAMAGE_SETTING_Y+6), MPH_STARTINGCASH_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_DAMAGE_VERYLOW + iMPHWeaponDamage ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // -------------- - // Damage multiplier text label - DisplayWrappedString( MPH_LABEL_DMG_X, MPH_LABEL_DMG_Y, MPH_LABEL_DMG_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_DMG_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ----------- + // TurnTimes + RenderMPHSmallSelectionFrame( (MPH_TIMETURNS_SETTING_X + 36), (MPH_TIMETURNS_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_TIMETURNS_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_TIMETURNS_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_TIMETURNS_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_TIMER_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_TIMETURNS_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_TIMETURNS_SETTING_Y+6), MPH_TIMETURNS_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_TIME_NEVER + iMPHTimeTurns ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ----------------- + + // --------------- + // Difficulty + RenderMPHSmallSelectionFrame( (MPH_DIFFICULTY_SETTING_X + 36), (MPH_DIFFICULTY_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_DIFFICULTY_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_DIFFICULTY_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_DIFFICULTY_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_DIF_LEVEL_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_DIFFICULTY_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_DIFFICULTY_SETTING_Y+6), MPH_DIFFICULTY_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ iMPHDifficulty + 9 ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // --------------- - // Turn timer text label - DisplayWrappedString( MPH_LABEL_TIMER_X, MPH_LABEL_TIMER_Y, MPH_LABEL_TIMER_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_TIMER_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // --------------- + // GameType + RenderMPHSmallSelectionFrame( (MPH_GAMETYPE_SETTING_X + 36), (MPH_GAMETYPE_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_GAMETYPE_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_GAMETYPE_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_GAMETYPE_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_GAMETYPE_SETTING_Y+6), MPH_GAMETYPE_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_DEATHMATCH_TEXT + iMPHGameType], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // --------------- + + // --------------- + // MaxEnemies + DisplayWrappedString( (MPH_MAXENEMIES_SETTING_X - 6), (UINT16)(MPH_MAXENEMIES_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_MAXENEMIES_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_OVERRIDEMAXAI_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ------------- - // File transfer directory (source directory for server, target directory for client) - DisplayWrappedString( MPH_LABEL_FILE_TRANSFER_DIR_X, MPH_LABEL_FILE_TRANSFER_DIR_Y, MPH_LABEL_FILE_TRANSFER_DIR_WIDTH, 2, MPH_LABEL_TEXT_FONT, MPH_LABEL_TEXT_COLOR, gzMPHScreenText[ MPH_FILE_TRANSFER_DIR_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // --------------- + // Traits + DisplayWrappedString( (MPH_TRAITS_SETTING_X - 6), (UINT16)(MPH_TRAITS_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_TRAITS_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_TRAITS_TEXT], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ------------- - //Display the Dif Settings Title Text - DisplayWrappedString( MPH_DIF_SETTINGS_X, (UINT16)(MPH_DIF_SETTINGS_Y-MPH_GAP_BN_SETTINGS), MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_DIF_LEVEL_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ----------- + // HireMerc + DisplayWrappedString( (MPH_HIREMERC_SETTING_X - 6), (UINT16)(MPH_HIREMERC_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_HIREMERC_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RANDOMMERCS_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ---------- - // Hard - usPosY = MPH_DIF_SETTINGS_Y+2; - DisplayWrappedString( (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_HARD_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ------------ + // SameMerc + DisplayWrappedString( (MPH_SAMEMERC_SETTING_X - 6), (UINT16)(MPH_SAMEMERC_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_SAMEMERC_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_SAMEMERC_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ---------- - // Insane - usPosY += MPH_GAP_BN_SETTINGS-5; - //DrawTextToScreen( gzMPHScreenText[ MPH_HARD_TEXT ], (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_MAIN_TITLE_WIDTH, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - DisplayWrappedString( (UINT16)(MPH_DIF_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_DIF_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_INSANE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ------------- + // ReportMerc + DisplayWrappedString( (MPH_REPORTMERC_SETTING_X - 6), (UINT16)(MPH_REPORTMERC_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_REPORTMERC_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RPTMERC_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ------------- - //Display the Game Type title - DisplayWrappedString( MPH_GAMETYPE_SETTINGS_X, (UINT16)(MPH_GAMETYPE_SETTINGS_Y-MPH_GAP_BN_SETTINGS), MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_GAMETYPE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ----------------- + // BobbyRay + DisplayWrappedString( (MPH_BOBBYRAY_SETTING_X - 6), (UINT16)(MPH_BOBBYRAY_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_BOBBYRAY_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_BOBBYRAY_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ---------- - // Deathmatch - usPosY = MPH_GAMETYPE_SETTINGS_Y+2; - DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_DEATHMATCH_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ------------------ + // SectorEdge + DisplayWrappedString( (MPH_SECTOREDGE_SETTING_X - 6), (UINT16)(MPH_SECTOREDGE_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_SECTOREDGE_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RNDMSTART_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ---------- - // Team Deathmatch - usPosY += MPH_GAP_BN_SETTINGS-5; - DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_TEAMDM_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // ------------ + // Civs + DisplayWrappedString( (MPH_CIVS_SETTING_X - 6), (UINT16)(MPH_CIVS_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_CIVS_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_ENABLECIV_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ------------- - // Co-operative - usPosY += MPH_GAP_BN_SETTINGS-5; - DisplayWrappedString( (UINT16)(MPH_GAMETYPE_SETTINGS_X+MPH_OFFSET_TO_TEXT), usPosY, MPH_GAMETYPE_SETTINGS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_COOP_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // -------------- + // Inventory + RenderMPHSmallSelectionFrame( (MPH_INVENTORY_SETTING_X + 36), (MPH_INVENTORY_SETTING_Y - 3) ); + DisplayWrappedString( (UINT16)(MPH_INVENTORY_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (UINT16)(MPH_INVENTORY_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE - 12), MPH_INVENTORY_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ GIO_INV_TEXT ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + DisplayWrappedString( (UINT16)(MPH_INVENTORY_SETTING_X+MPH_OFFSET_TO_TEXT + 1), (MPH_INVENTORY_SETTING_Y+6), MPH_INVENTORY_SETTING_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzGIOScreenText[ iMPHInventory + 54 ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // ---------------- - // Override Max AI - DisplayWrappedString( (UINT16)MPH_OVERRIDEMAXAI_X, MPH_OVERRIDEMAXAI_Y, MPH_OVERRIDEMAXAI_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_OVERRIDEMAXAI_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Random Mercs - DisplayWrappedString( (UINT16)MPH_RNDMERC_X, MPH_RNDMERC_Y, MPH_RNDMERC_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RANDOMMERCS_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Same Mercs - DisplayWrappedString( (UINT16)MPH_SAMEMERC_X, MPH_SAMEMERC_Y, MPH_SAMEMERC_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_SAMEMERC_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Report Mercs - DisplayWrappedString( (UINT16)MPH_REPORTMERC_X, MPH_REPORTMERC_Y, MPH_REPORTMERC_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RPTMERC_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Allow Bobby-Rays - DisplayWrappedString( (UINT16)MPH_BOBBYRAY_X, MPH_BOBBYRAY_Y, MPH_BOBBYRAY_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_BOBBYRAY_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Random Spawn - DisplayWrappedString( (UINT16)MPH_RNDSPAWN_X, MPH_RNDSPAWN_Y, MPH_RNDSPAWN_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_RNDMSTART_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Civs - DisplayWrappedString( (UINT16)MPH_CIVS_X, MPH_CIVS_Y, MPH_CIVS_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_ENABLECIV_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Use NIV - DisplayWrappedString( (UINT16)MPH_USENIV_X, MPH_USENIV_Y, MPH_USENIV_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_USENIV_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - - // Send Files - DisplayWrappedString( (UINT16)MPH_SEND_FILES_X, MPH_SEND_FILES_Y, MPH_SEND_FILES_WIDTH, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_SYNC_CLIENT_MP_DIR ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + // -------------------- + // Sync + DisplayWrappedString( (MPH_SYNC_SETTING_X - 6), (UINT16)(MPH_SYNC_SETTING_Y-MPH_GAP_BN_SETTINGS + MPH_TITLE_DISTANCE), MPH_SYNC_SETTING_WIDTH + 14, 2, MPH_TOGGLE_TEXT_FONT, MPH_TOGGLE_TEXT_COLOR, gzMPHScreenText[ MPH_SYNC_GAME_DIRECTORY ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + // -------------------- return( TRUE ); -} // end of RenderMPHScreen() +} @@ -1328,26 +2760,7 @@ void GetMPHScreenUserInput() if (ValidateMPSettings()) { SaveMPSettings(); // Update Profiles/UserProfile/ja2_mp.ini -#ifdef USE_VFS - // "gzFileTransferDirectory" is the new multiplayer profile root - vfs::CProfileStack *PS = getVFS()->getProfileStack(); - - // remove Multiplayer profile if it exists - vfs::CVirtualProfile *pProf = PS->getProfile("_MULTIPLAYER"); - if( pProf && (pProf == PS->topProfile()) ) - { - THROWIFFALSE(PS->popProfile(), "Could not remove old \"_MULTIPLAYER\" profile"); - // careful, pProf is not valid anymore - } - // create and initialize a new Multiplayer profile - pProf = new vfs::CVirtualProfile("_MULTIPLAYER",true); - PS->pushProfile(pProf); - if(!initWriteProfile(*pProf, vfs::Path(gzFileTransferDirectory))) - { - THROWIFFALSE(PS->popProfile(), L"Could not remove \"_MULTIPLAYER\" profile"); - THROWEXCEPTION(L"Directory exists, but Multiplayer profile could not be iniitalized"); - } -#endif + SGP_TRYCATCH_RETHROW( ja2::mp::InitializeMultiplayerProfile(vfs::Path(gzFileTransferDirectory)), L"" ); gubMPHScreenHandler = MPH_START; } break; @@ -1374,29 +2787,11 @@ void BtnMPHStartCallback(GUI_BUTTON *btn,INT32 reason) { gubMPHScreenHandler = MPH_START; SaveMPSettings(); // Update the Profiles/UserProfile/ja2_mp.ini -#ifdef USE_VFS - // "gzFileTransferDirectory" is the new multiplayer profile root - vfs::CProfileStack *PS = getVFS()->getProfileStack(); - - // remove Multiplayer profile if it exists - vfs::CVirtualProfile *pProf = PS->getProfile("_MULTIPLAYER"); - if( pProf && (pProf == PS->topProfile()) ) - { - THROWIFFALSE(PS->popProfile(), "Could not remove old \"_MULTIPLAYER\" profile"); - // careful, pProf is not valid anymore - } - // create and initialize a new Multiplayer profile - pProf = new vfs::CVirtualProfile("_MULTIPLAYER",true); - PS->pushProfile(pProf); - if(!initWriteProfile(*pProf, vfs::Path(gzFileTransferDirectory))) - { - THROWIFFALSE(PS->popProfile(), L"Could not remove \"_MULTIPLAYER\" profile"); - THROWEXCEPTION(L"Directory exists, but Multiplayer profile could not be iniitalized"); - } -#endif + SGP_TRYCATCH_RETHROW( ja2::mp::InitializeMultiplayerProfile(vfs::Path(gzFileTransferDirectory)), L"" ); // The difficult level has to be set there. This is the only value so far, because it is used for initialization! - gGameOptions.ubDifficultyLevel = GetMPHCurrentDifficultyButtonSetting(); + //gGameOptions.ubDifficultyLevel = GetMPHCurrentDifficultyButtonSetting(); + gGameOptions.ubDifficultyLevel = iMPHDifficulty + 1; // WANNE - MP: Reinit TableData folder and INIs LoadExternalGameplayData(TABLEDATA_DIRECTORY); @@ -1424,162 +2819,6 @@ void BtnMPHCancelCallback(GUI_BUTTON *btn,INT32 reason) } } -void BtnMPHDifficultyTogglesCallback( GUI_BUTTON *btn, INT32 reason ) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHGameTypeTogglesCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - /*UINT8 ubButton = (UINT8)*/MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - UINT8 cnt; - - for( cnt=0; cntuiFlags &= ~BUTTON_CLICKED_ON; - } - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - else - { - UINT8 cnt; - BOOLEAN fAnyChecked=FALSE; - - //if none of the other boxes are checked, do not uncheck this box - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - fAnyChecked = TRUE; - } - } - //if none are checked, re check this one - if( !fAnyChecked ) - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void RestoreMPHButtonBackGrounds() -{ - UINT8 cnt; - UINT16 usPosY; - - - usPosY = MPH_DIF_SETTINGS_Y-MPH_OFFSET_TO_TOGGLE_BOX_Y; - //Check box to toggle Difficulty settings - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - return( cnt + 3 ); // removed two difficulty options from MPH - } - } - - return( 0 ); -} - -UINT8 GetMPHGameTypeButtonSetting() -{ - UINT8 cnt; - - for( cnt=0; cntuiFlags & BUTTON_CLICKED_ON ) - { - return( cnt ); - } - } - - return( 0 ); -} - -BOOLEAN DoMPHMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen, UINT16 usFlags, MSGBOX_CALLBACK ReturnCallback ) -{ - SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; - - // reset exit mode -// gfExitGioDueToMessageBox = TRUE; - - // do message box and return - giMPHMessageBox = DoMessageBox( ubStyle, zString, uiExitScreen, ( UINT16 ) ( usFlags| MSG_BOX_FLAG_USE_CENTERING_RECT ), ReturnCallback, &CenteringRect ); - - // send back return state - return( ( giMPHMessageBox != -1 ) ); -} - void DoneFadeOutForExitMPHScreen( void ) { // As we bypassed the GIO screen, set up some game options for multiplayer here @@ -1588,59 +2827,18 @@ void DoneFadeOutForExitMPHScreen( void ) is_host = true; // we want to be the host, not we ARE the host yet (is_server) auto_retry = true; giNumTries = 5; - - // loop through and get the status of all the buttons - // Madd - /*gGameOptions.fGunNut = GetCurrentGunButtonSetting(); - gGameOptions.ubGameStyle = GetCurrentGameStyleButtonSetting(); - gGameOptions.ubDifficultyLevel = GetCurrentDifficultyButtonSetting() + 1;*/ - // JA2Gold: no more timed turns setting - //gGameOptions.fTurnTimeLimit = GetCurrentTimedTurnsButtonSetting();//hayden : re-enabled - + if (is_networked) gGameOptions.fTurnTimeLimit = TRUE; else gGameOptions.fTurnTimeLimit = FALSE; - // JA2Gold: iron man - //gGameOptions.fIronManMode = GetCurrentGameSaveButtonSetting(); - // Bobby Rays - why would we want anything less than the best gGameOptions.ubBobbyRay = BR_AWESOME; - - - // CHRISL: - /*if(IsNIVModeValid() == TRUE){ - switch ( GetCurrentINVOptionButtonSetting() ) - { - case GIO_INV_OLD: - gGameOptions.ubInventorySystem = INVENTORY_OLD; - break; - case GIO_INV_NEW: - gGameOptions.ubInventorySystem = INVENTORY_NEW; - break; - } - }*/ - - // gubGIOExitScreen = INIT_SCREEN; + gubMPHExitScreen = INTRO_SCREEN; - //set the fact that we should do the intro videos -// gbIntroScreenMode = INTRO_BEGINING; -#ifdef JA2TESTVERSION - if( gfKeyState[ ALT ] ) - { - if( gfKeyState[ CTRL ] ) - { - gMercProfiles[ MIGUEL ].bMercStatus = MERC_IS_DEAD; - gMercProfiles[ SKYRIDER ].bMercStatus = MERC_IS_DEAD; - } - - SetIntroType( INTRO_ENDING ); - } - else -#endif - SetIntroType( INTRO_BEGINING ); + SetIntroType( INTRO_BEGINNING ); ExitMPHScreen(); // cleanup please, if we called a fadeout then we didnt do it above @@ -1652,146 +2850,16 @@ void DoneFadeInForExitMPHScreen( void ) SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); } -void BtnMPHOverrideMaxAICallback(GUI_BUTTON *btn,INT32 reason) +void RenderMPHSmallSelectionFrame(INT16 sX, INT16 sY) { - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHOverrideMaxAIToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; + HVOBJECT hHandle; - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} + // get the video object + GetVideoObject(&hHandle, guiMPHSMALLFRAME); -void BtnMPHRandomMercCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); + // blt to sX, sY relative to upper left corner + BltVideoObject(FRAME_BUFFER, hHandle, 0, sX, sY , VO_BLT_SRCTRANSPARENCY,NULL); - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHRandomMercsToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHSameMercCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHSameMercToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHReportMercCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHReportMercToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHBobbyRayCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHBobbyRayToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHRandomSpawnCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHRandomSpawnToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHUseNIVCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHUseNIVToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHSendFilesCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHSendFiles ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } -} - -void BtnMPHCivsCallback(GUI_BUTTON *btn,INT32 reason) -{ - if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) - { - MSYS_GetBtnUserData( btn, 0 ); - - if( btn->uiFlags & BUTTON_CLICKED_ON ) - { - ButtonList[ guiMPHCivsToggle ]->uiFlags &= ~BUTTON_CLICKED_ON; - - //enable the current button - btn->uiFlags |= BUTTON_CLICKED_ON; - } - } + return; } \ No newline at end of file diff --git a/MPJoinScreen.cpp b/MPJoinScreen.cpp index b0c3e859..47e79a49 100644 --- a/MPJoinScreen.cpp +++ b/MPJoinScreen.cpp @@ -31,10 +31,10 @@ #include "saveloadscreen.h" #include "game init.h" -#include "VFS/vfs.h" -#include "VFS/vfs_init.h" -#include "VFS/PropertyContainer.h" -#include "VFS/os_functions.h" +#include +#include +#include +#include #include "Random.h" @@ -51,15 +51,17 @@ #define MPJ_LABEL_TEXT_COLOR FONT_MCOLOR_WHITE //buttons -#define MPJ_BTN_JOIN_X iScreenWidthOffset + 320 + 143 -#define MPJ_BTN_JOIN_Y iScreenHeightOffset + 435 -#define MPJ_BTN_HOST_X MPJ_BTN_JOIN_X-180 -#define MPJ_BTN_HOST_Y iScreenHeightOffset + 435 #define MPJ_CANCEL_X iScreenWidthOffset + ((320 - 115) / 2) +#define MPJ_BTN_HOST_X iScreenWidthOffset + 265 +#define MPJ_BTN_HOST_Y iScreenHeightOffset + 435 + +#define MPJ_BTN_JOIN_X iScreenWidthOffset + 425 +#define MPJ_BTN_JOIN_Y iScreenHeightOffset + 435 + //textboxes #define MPJ_TXT_HANDLE_X iScreenWidthOffset + 100 -#define MPJ_TXT_HANDLE_Y iScreenHeightOffset + 60 +#define MPJ_TXT_HANDLE_Y iScreenHeightOffset + 100 #define MPJ_TXT_HANDLE_WIDTH 120 #define MPJ_TXT_HANDLE_HEIGHT 17 #define MPJ_TXT_IP_X iScreenWidthOffset + 100 @@ -73,7 +75,7 @@ //main title -#define MPJ_MAIN_TITLE_X 0 +#define MPJ_MAIN_TITLE_X 0 #define MPJ_MAIN_TITLE_Y iScreenHeightOffset + 10 #define MPJ_MAIN_TITLE_WIDTH SCREEN_WIDTH @@ -91,7 +93,6 @@ #define MPJ_LABEL_PORT_WIDTH 80 #define MPJ_LABEL_PORT_HEIGHT 17 - //////////////////////////////////////////// // // Global Variables @@ -127,9 +128,8 @@ CHAR16 gzServerPortField[ 5+1 ] = {0} ; // client sets this when joining extern CHAR16 gzFileTransferDirectory[100]; -#ifdef USE_VFS -void CUniqueServerId::uniqueRandomString(utf8string& str) +void CUniqueServerId::uniqueRandomString(vfs::String& str) { std::vector _rand(30,0); int pos = 0; @@ -153,25 +153,24 @@ void CUniqueServerId::uniqueRandomString(utf8string& str) str.r_wcs().assign(&_rand[0],29); } -utf8string const& CUniqueServerId::getServerId(vfs::Path dir, CPropertyContainer* props) +vfs::String const& CUniqueServerId::getServerId(vfs::Path dir, vfs::PropertyContainer* props) { if(!props) { return _id; } - utf8string key = L"\"" + dir.c_wcs() + L"\""; - utf8string id = props->getStringProperty(L"SERVER",key); + vfs::String key = L"\"" + dir.c_wcs() + L"\""; + vfs::String id = props->getStringProperty(JA2MP_INI_SERVER_SECTION,key); if(id.empty()) { uniqueRandomString(id); } _id = id; - props->setStringProperty(L"SERVER",key,_id); + props->setStringProperty(JA2MP_INI_SERVER_SECTION,key,_id); return _id; } CUniqueServerId s_ServerId; -#endif //////////////////////////////////////////// // @@ -217,21 +216,30 @@ void DoneFadeOutForExitMPJScreen( void ); void DoneFadeInForExitMPJScreen( void ); +void MpIniExists() +{ + if(!getVFS()->fileExists(JA2MP_INI_FILENAME)) + { + SGP_THROW_IFFALSE(getVFS()->createNewFile(JA2MP_INI_FILENAME),L"could not create file : Ja2_mp.ini"); + vfs::tWritableFile* file = getVFS()->getWriteFile(JA2MP_INI_FILENAME); + if(file) + { + file->openWrite(true); + file->close(); + } + } +} + + UINT32 MPJoinScreenInit( void ) { -// WANNE - MP: Read the values from Profiles/UserProfile/ja2_mp.ini -#ifndef USE_VFS - // read settings from JA2 ini - GetPrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_IP", L"127.0.0.1", gzServerIPField, 16, L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_PORT", L"60005", gzServerPortField, 6, L"..\\Ja2_mp.ini" ); - GetPrivateProfileStringW( L"Ja2_mp Settings",L"CLIENT_NAME", L"Player Name", gzPlayerHandleField, 12 , L"..\\Ja2_mp.ini" ); -#else - CPropertyContainer props; - props.initFromIniFile( L"Ja2_mp.ini"); - props.getStringProperty( L"Ja2_mp Settings", L"SERVER_IP", gzServerIPField, 16, "127.0.0.1"); - props.getStringProperty( L"Ja2_mp Settings", L"SERVER_PORT", gzServerPortField, 6, "60005"); - props.getStringProperty( L"Ja2_mp Settings", L"CLIENT_NAME", gzPlayerHandleField, 12, L"Player Name"); -#endif + // WANNE - MP: Read the values from Profiles/UserProfile/ja2_mp.ini + MpIniExists(); + vfs::PropertyContainer props; + props.initFromIniFile( JA2MP_INI_FILENAME); + props.getStringProperty( JA2MP_INI_INITIAL_SECTION, JA2MP_SERVER_IP, gzServerIPField, 16, "127.0.0.1"); + props.getStringProperty( JA2MP_INI_INITIAL_SECTION, JA2MP_SERVER_PORT, gzServerPortField, 6, "60005"); + props.getStringProperty( JA2MP_INI_INITIAL_SECTION, JA2MP_CLIENT_NAME, gzPlayerHandleField, 12, L"Player Name"); return( 1 ); } @@ -244,23 +252,17 @@ void SaveJoinSettings(bool ReSaving) Get16BitStringFromField( 2, gzServerPortField, 6 ); } -#ifndef USE_VFS - // save settings to JA2_mp.ini - WritePrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_IP", gzServerIPField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"SERVER_PORT", gzServerPortField, L"..\\Ja2_mp.ini" ); - WritePrivateProfileStringW( L"Ja2_mp Settings",L"CLIENT_NAME", gzPlayerHandleField , L"..\\Ja2_mp.ini" ); -#else - CPropertyContainer props; - props.initFromIniFile("Ja2_mp.ini"); + MpIniExists(); + vfs::PropertyContainer props; + props.initFromIniFile(JA2MP_INI_FILENAME); - props.setStringProperty(L"Ja2_mp Settings",L"SERVER_IP", gzServerIPField); - props.setStringProperty(L"Ja2_mp Settings",L"SERVER_PORT", gzServerPortField); - props.setStringProperty(L"Ja2_mp Settings",L"CLIENT_NAME", gzPlayerHandleField); + props.setStringProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_SERVER_IP, gzServerIPField); + props.setStringProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_SERVER_PORT, gzServerPortField); + props.setStringProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_CLIENT_NAME, gzPlayerHandleField); s_ServerId.getServerId(vfs::Path(gzFileTransferDirectory), &props); - props.writeToIniFile(L"ja2_mp.ini",true); -#endif + props.writeToIniFile(JA2MP_INI_FILENAME,false); } bool ValidateJoinSettings(bool bSkipServerAddress, bool bSkipSyncDir) @@ -326,30 +328,10 @@ bool ValidateJoinSettings(bool bSkipServerAddress, bool bSkipSyncDir) if (!bSkipSyncDir) { -#ifndef USE_VFS - // Create MULTIPLAYER / SERVERS if it dosent exist - STRING512 syncDir; - STRING512 executableDir; - - GetExecutableDirectory(executableDir); - sprintf(syncDir, "%s\\multiplayer", executableDir); - - if (!DirectoryExists(syncDir)) + if(vfs::OS::createRealDirectory(vfs::Path(L"Multiplayer"))) { - CreateDirectoryA(syncDir, NULL); + vfs::OS::createRealDirectory(vfs::Path(L"Multiplayer/Servers")); } - - sprintf(syncDir, "%s\\multiplayer\\servers", executableDir); - if (!DirectoryExists(syncDir)) - { - CreateDirectoryA(syncDir, NULL); - } -#else - if(os::createRealDirectory(vfs::Path(L"Multiplayer"))) - { - os::createRealDirectory(vfs::Path(L"Multiplayer/Servers")); - } -#endif } return true; @@ -361,8 +343,6 @@ UINT32 MPJoinScreenHandle( void ) if( gfMPJScreenEntry ) { -// PauseGame(); - EnterMPJScreen(); gfMPJScreenEntry = FALSE; gfMPJScreenExit = FALSE; @@ -371,7 +351,6 @@ UINT32 MPJoinScreenHandle( void ) GetMPJScreenUserInput(); - HandleMPJScreen(); // render buttons marked dirty @@ -380,12 +359,7 @@ UINT32 MPJoinScreenHandle( void ) // render text boxes RenderAllTextFields(); // textbox system call - - // render help -// RenderFastHelp( ); -// RenderButtonsFastHelp( ); - - + ExecuteBaseDirtyRectQueue(); EndFrameBufferRender(); @@ -409,17 +383,15 @@ UINT32 MPJoinScreenHandle( void ) if ( HandleBeginFadeIn( gubMPJExitScreen ) ) { - } - if( gfMPJScreenExit ) // we are exiting this screen + if( gfMPJScreenExit ) { - ExitMPJScreen(); // perform destruction + ExitMPJScreen(); } return( gubMPJExitScreen ); -} // end MPJoinScreenHandle() - +} UINT32 MPJoinScreenShutdown( void ) { @@ -545,9 +517,7 @@ BOOLEAN EnterMPJScreen() gfMPJButtonsAllocated = TRUE; return( TRUE ); - -} // End of EnterMPJScreen() - +} BOOLEAN ExitMPJScreen() { @@ -582,10 +552,9 @@ BOOLEAN ExitMPJScreen() return( TRUE ); -} // End of ExitMPJScreen() +} - -void HandleMPJScreen() +void HandleMPJScreen() { if( gubMPJScreenHandler != MPJ_NOTHING ) { @@ -617,23 +586,54 @@ void HandleMPJScreen() } break; } - } gubMPJScreenHandler = MPJ_NOTHING; } - if( gfReRenderMPJScreen ) { RenderMPJScreen(); gfReRenderMPJScreen = FALSE; } +} - // add restore backgrounds in... - //RestoreGIOButtonBackGrounds(); -} // end of HandleMPJScreen +void DrawHelpText() +{ + int x = MPJ_LABEL_HANDLE_X; + int y = iScreenHeightOffset + 60; + int width = 640 - (2 * 50); + int lineSpacing = 12; + // Visit IRC + DrawTextToScreen( gzMPJHelpText[ 0 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + // Host + y += 150; + + y+= lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 1 ], x, y, width, FONT12ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y+= lineSpacing + 5; + DrawTextToScreen( gzMPJHelpText[ 2 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y+= lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 3 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y+= lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 4 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y+= lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 5 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + + // Join + y += 20; + + y += lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 6 ], x, y, width, FONT12ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y += lineSpacing + 5; + DrawTextToScreen( gzMPJHelpText[ 7 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y += lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 8 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + y += lineSpacing; + DrawTextToScreen( gzMPJHelpText[ 9 ], x, y, width, FONT10ARIAL, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); +} BOOLEAN RenderMPJScreen() { @@ -648,9 +648,11 @@ BOOLEAN RenderMPJScreen() //Display the title DrawTextToScreen( gzMPJScreenText[ MPJ_TITLE_TEXT ], MPJ_MAIN_TITLE_X, MPJ_MAIN_TITLE_Y, MPJ_MAIN_TITLE_WIDTH, MPJ_TITLE_FONT, MPJ_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED ); + + DrawHelpText(); // Player name text label - DisplayWrappedString( MPJ_LABEL_HANDLE_X, MPJ_LABEL_HANDLE_Y, MPJ_LABEL_HANDLE_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_HANDLE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + DisplayWrappedString( MPJ_LABEL_HANDLE_X, MPJ_LABEL_HANDLE_Y, MPJ_LABEL_HANDLE_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_HANDLE_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); // Server IP text label DisplayWrappedString( MPJ_LABEL_IP_X, MPJ_LABEL_IP_Y, MPJ_LABEL_IP_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_SERVERIP_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); @@ -659,16 +661,11 @@ BOOLEAN RenderMPJScreen() DisplayWrappedString( MPJ_LABEL_PORT_X, MPJ_LABEL_PORT_Y, MPJ_LABEL_PORT_WIDTH, 2, MPJ_LABEL_TEXT_FONT, MPJ_LABEL_TEXT_COLOR, gzMPJScreenText[ MPJ_SERVERPORT_TEXT ], FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); return( TRUE ); -} // end of RenderMPJScreen() +} - - -void GetMPJScreenUserInput() +void GetMPJScreenUserInput() { InputAtom Event; -// POINT MousePos; - -// GetCursorPos(&MousePos); while( DequeueEvent( &Event ) ) { @@ -697,11 +694,9 @@ void GetMPJScreenUserInput() } } } -} // end of GetMPJScreenUserInput() - +} // CALLBACKS - void BtnMPJoinCallback(GUI_BUTTON *btn,INT32 reason) { if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) @@ -768,9 +763,6 @@ BOOLEAN DoMPJMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen { SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; - // reset exit mode -// gfExitGioDueToMessageBox = TRUE; - // do message box and return giMPJMessageBox = DoMessageBox( ubStyle, zString, uiExitScreen, ( UINT16 ) ( usFlags| MSG_BOX_FLAG_USE_CENTERING_RECT ), ReturnCallback, &CenteringRect ); @@ -780,8 +772,7 @@ BOOLEAN DoMPJMessageBox( UINT8 ubStyle, const STR16 zString, UINT32 uiExitScreen void DoneFadeOutForExitMPJScreen( void ) { - // As we bypassed the GIO screen, set up some game options for multiplayer here - // most things i have left as thier defaults here for testing. + // As we bypassed the GIO screen, set up some game options for multiplayer here is_networked = true; is_host = false; // we want to be a client, not we ARE a client yet (is_client) auto_retry = true; diff --git a/MPJoinScreen.h b/MPJoinScreen.h index ff829119..ea6a0934 100644 --- a/MPJoinScreen.h +++ b/MPJoinScreen.h @@ -1,31 +1,31 @@ #ifndef _MP_JOIN_SCREEN_H_ #define _MP_JOIN_SCREEN_H_ -#include "VFS/vfs.h" +#include -#ifdef USE_VFS - -class CPropertyContainer; +namespace vfs{ + class PropertyContainer; +} class CUniqueServerId { public: - utf8string const& getServerId(vfs::Path dir, CPropertyContainer* props = NULL); + vfs::String const& getServerId(vfs::Path dir, vfs::PropertyContainer* props = NULL); - static void uniqueRandomString(utf8string& str); + static void uniqueRandomString(vfs::String& str); private: - utf8string _id; + vfs::String _id; }; extern CUniqueServerId s_ServerId; -#endif - UINT32 MPJoinScreenInit( void ); UINT32 MPJoinScreenHandle( void ); UINT32 MPJoinScreenShutdown( void ); -void SaveJoinSettings(bool ReSaving); +void SaveJoinSettings(bool ReSaving); + +void MpIniExists(); diff --git a/MPScoreScreen.cpp b/MPScoreScreen.cpp index 9bcf7cf8..5d489128 100644 --- a/MPScoreScreen.cpp +++ b/MPScoreScreen.cpp @@ -329,7 +329,6 @@ void HandleMPSScreen() switch( gubMPSScreenHandler ) { case MPS_CANCEL: - // TODO.RW: Exit game, disconnect if (is_server) server_disconnect(); @@ -475,7 +474,7 @@ BOOLEAN RenderMPSScreen() } } - if (PLAYER_BSIDE==MP_TYPE_COOP) + if (cGameType==MP_TYPE_COOP) { // CO-OP Mode, show stats for queens army usPosY = MPS_PLAYERLIST_Y + (5 * MPS_PLAYER_GAP); // leave a space between players and AI @@ -610,7 +609,7 @@ void DoneFadeOutForExitMPSScreen( void ) } else #endif - SetIntroType( INTRO_BEGINING ); + SetIntroType( INTRO_BEGINNING ); ExitMPSScreen(); // cleanup please, if we called a fadeout then we didnt do it above diff --git a/MPXmlTeams.cpp b/MPXmlTeams.cpp index ddd184ff..1bff9cab 100644 --- a/MPXmlTeams.cpp +++ b/MPXmlTeams.cpp @@ -10,10 +10,10 @@ MultiplayerTeams mpTeams = MultiplayerTeams(); // fallback data const int MultiplayerTeams::random_merc_teams[NUM_RANDOM_MERC_TEAMS][RANDOM_MERC_TEAM_SIZE] = { - { 16, 10, 19, 25, 4 , 11, 39 }, // Gus , Shadow, Spider , Raven , Vicki , Red , Meltdown - { 29, 36, 28, 2 , 22, 8 , 32 }, // Magic , Scope, Danny , Lynx , Hitman , Steroid , Malice - { 12, 5 , 20, 23, 48, 34, 17 }, // Reaper , Trevor, Cliff , Buzz , Cougar , Nails , Buns - { 31, 7 , 33, 35, 27, 37, 1 }, // Scully , Ivan , Dr Q , Thor , Len , Wolf , Blood + { 16, 10, 19, 25, 4 , 11, 39 }, // Gus , Shadow, Spider , Raven , Vicki , Red , Meltdown + { 173, 36, 28, 2 , 22, 8 , 32 }, // Henning , Scope, Danny , Lynx , Hitman , Steroid , Malice + { 12, 175, 20, 23, 48, 34, 17 }, // Reaper , Laura, Cliff , Buzz , Cougar , Nails , Buns + { 31, 7, 33, 35, 27, 37, 1 }, // Scully , Ivan , Dr Q , Thor , Len , Wolf , Blood }; void MultiplayerTeams::SerializeProfiles(int* dest) diff --git a/MainMenuScreen.cpp b/MainMenuScreen.cpp index e65e03fe..0f55c989 100644 --- a/MainMenuScreen.cpp +++ b/MainMenuScreen.cpp @@ -38,8 +38,8 @@ #include "mercs.h" #include "gamesettings.h" #include "connect.h" -#include "VFS/vfs.h" -#include "VFS/vfs_profile.h" +#include +#include #define MAINMENU_TEXT_FILE "LoadScreens\\MainMenu.edt" #define MAINMENU_RECORD_SIZE 80 * 2 @@ -294,7 +294,7 @@ BOOLEAN InitMainMenu( ) vfs::CVirtualProfile *pProf = PS->getProfile("_MULTIPLAYER"); if( pProf && (pProf == PS->topProfile()) ) { - THROWIFFALSE(PS->popProfile(), "Leaving Multiplayer mode : Could not remove \"_MULTIPLAYER\" profile"); + SGP_THROW_IFFALSE(PS->popProfile(), "Leaving Multiplayer mode : Could not remove \"_MULTIPLAYER\" profile"); } #endif @@ -318,7 +318,7 @@ BOOLEAN InitMainMenu( ) if (iResolution == 0) { - FilenameForBPP("LOADSCREENS\\MainMenuBackGround.sti", VObjectDesc.ImageFile); + FilenameForBPP("LOADSCREENS\\MainMenuBackGround.sti", VObjectDesc.ImageFile); } else if (iResolution == 1) { @@ -339,7 +339,7 @@ BOOLEAN InitMainMenu( ) /* // Gray out some buttons based on status of game! - if( gGameSettings.bLastSavedGameSlot < 0 || gGameSettings.bLastSavedGameSlot >= NUM_SAVE_GAMES ) + if( gGameSettings.bLastSavedGameSlot < 0 || gGameSettings.bLastSavedGameSlot >= NUM_SLOT ) { DisableButton( iMenuButtons[ LOAD_GAME ] ); } @@ -362,7 +362,8 @@ BOOLEAN InitMainMenu( ) SetPendingNewScreen( MAINMENU_SCREEN); guiMainMenuExitScreen = MAINMENU_SCREEN; - InitGameOptions(); + // WANNE: I don't think that is needed! + //InitGameOptions(); DequeueAllKeyBoardEvents(); @@ -406,22 +407,14 @@ void InitDependingGameStyleOptions() LoadGameAPBPConstants(); // Load ja2_options.ini LoadGameExternalOptions(); + // Load new STOMP ini - SANDRO + LoadSkillTraitsExternalSettings(); + // HEADROCK HAM 4: CTH constants + LoadCTHConstants(); + InitSightRange(); //lal - ReStartingGame(); - - if (is_networked) - { - NUMBER_OF_MERCS = 28; - LAST_MERC_ID = 27; - } - else - { - InitGameOptions(); - - NUMBER_OF_MERCS = 15; - LAST_MERC_ID = 14; - } + ReStartingGame(); } diff --git a/Multiplayer/client.cpp b/Multiplayer/client.cpp index 5460dbfd..c189676d 100644 --- a/Multiplayer/client.cpp +++ b/Multiplayer/client.cpp @@ -72,6 +72,7 @@ #include "Explosion Control.h" #include "SmokeEffects.h" #include "MPChatScreen.h" +#include "sgp_logger.h" #endif #include "MessageIdentifiers.h" @@ -106,16 +107,15 @@ #include "MessageBoxScreen.h" -#include "VFS/vfs.h" -#include "VFS/vfs_init.h" -#include "VFS/vfs_profile.h" -#include "VFS/vfs_file_raii.h" -#include "VFS/os_functions.h" -#include "VFS/File/vfs_file.h" -#include "VFS/Tools/ParserTools.h" +#include +#include +#include +#include +#include +#include +#include "transfer_rules.h" #include "keys.h" - #include "new.h" #include "Types.h" #include "connect.h" @@ -128,15 +128,11 @@ #include "soldier profile.h" #include "environment.h" #include "lighting.h" - #include "laptop.h" -#include "test_space.h" #include "interface panels.h" - #include "game init.h" #include "Debug Control.h" #include "MPConnectScreen.h" - #include "IniReader.h" extern CHAR16 gzFileTransferDirectory[100]; @@ -187,69 +183,7 @@ class ClientTransferCB : public FileListTransferCBInterface // Now the file will be saved on the client bool OnFile(OnFileStruct *onFileStruct) { -#ifndef USE_VFS - // Get the directory path of the file and output it to the user! - char* targetFileName = ExtractFilename(onFileStruct->fileName); - //ScreenMsg( FONT_BCOLOR_ORANGE, MSG_MPSYSTEM, MPClientMessage[58], targetFileName); - //ScreenMsg( FONT_BCOLOR_ORANGE, MSG_MPSYSTEM, L"%i. (100%%) %i/%i %S %ib->%ib / %ib->%ib\n", onFileStruct->setID, onFileStruct->fileIndex+1, onFileStruct->setCount, onFileStruct->fileName, onFileStruct->compressedTransmissionLength, onFileStruct->finalDataLength, onFileStruct->setTotalCompressedTransmissionLength, onFileStruct->setTotalFinalLength); - // Replace server executable directory with client executable directory then we have the correct path - char* tempFile = ReplaceCharactersInString_Client(onFileStruct->fileName, server_fileTransferDirectoryPath, client_fileTransferDirectoryPath); - char* pathWithoutFile = ReplaceCharactersInString_Client(tempFile, targetFileName, ""); - - // ---------------------------------- - // The directory does not exist, create it (and parent directories if needed) - // ---------------------------------- - if (!DirectoryExists(pathWithoutFile)) - { - // Remove the executable directory path - pathWithoutFile = ReplaceCharactersInString_Client(pathWithoutFile, client_executableDir, ""); - - wchar_t pathWithoutFileWChar[600]; - STRING512 currentDirectoryPath; - wchar_t* directoryName; - char directoryNameChar[100]; - - // Convert char* to wchar_t* - MultiByteToWideChar( CP_UTF8, 0, pathWithoutFile, -1, pathWithoutFileWChar, 600); - strcpy(currentDirectoryPath, client_executableDir); - - directoryName = wcstok(pathWithoutFileWChar,L"\\"); - while (directoryName != NULL) - { - // Convert to wchar_t* to char* - WideCharToMultiByte(CP_UTF8,0,directoryName,-1, directoryNameChar,100,NULL,NULL); - - // Get the full path of the directory - strcat(currentDirectoryPath, "\\"); - strcat(currentDirectoryPath, directoryNameChar); - - if (!DirectoryExists(currentDirectoryPath)) - { - // Folder does not exist, create it - if( !MakeFileManDirectory( currentDirectoryPath ) ) - AssertMsg( 0, String("Can't create new directory '%s'.", currentDirectoryPath) ); - } - - // get next directory (split on "\") - directoryName = wcstok(NULL,L"\\"); - } - } - - // OJW - 20090405 - char *relativeFname = ReplaceCharactersInString_Client(onFileStruct->fileName, server_fileTransferDirectoryPath,""); - strcpy(gCurrentTransferFilename,relativeFname); - SetConnectScreenSubMessageA(gCurrentTransferFilename); // setting this also causes connect screen to refresh - - // ---------------------------------- - // Save the file to clients harddisk - // ---------------------------------- - char *fileToSave = ReplaceCharactersInString_Client(onFileStruct->fileName, server_fileTransferDirectoryPath, client_fileTransferDirectoryPath); - - FILE *fp = fopen(fileToSave, "wb"); - fwrite(onFileStruct->fileData, onFileStruct->finalDataLength, 1, fp); - fclose(fp); -#else if(!transferRules) { transferRules = new CTransferRules(); @@ -260,9 +194,9 @@ class ClientTransferCB : public FileListTransferCBInterface //ScreenMsg( FONT_BCOLOR_ORANGE, MSG_CHAT, MPClientMessage[58], targetFileName); vfs::Path fileName(onFileStruct->fileName); - utf8string::str_t const& valid_str = fileName.c_wcs(); - utf8string::size_t pos = valid_str.find(L":"); - if(pos != utf8string::str_t::npos) + vfs::String::str_t const& valid_str = fileName.c_wcs(); + vfs::String::size_t pos = valid_str.find(L":"); + if(pos != vfs::String::str_t::npos) { // absolute path?? these are invalid and the server is not supposed to send us such paths // potentialy malicious server -> output error @@ -287,15 +221,13 @@ class ClientTransferCB : public FileListTransferCBInterface try { vfs::COpenWriteFile wfile(fileName,true,true); - wfile.file().write(onFileStruct->fileData,onFileStruct->finalDataLength); + wfile->write(onFileStruct->fileData,onFileStruct->finalDataLength); } - catch(CBasicException& ex) + catch(vfs::Exception& ex) { - logException(ex); - ScreenMsg( FONT_BCOLOR_BLUE, MSG_CHAT, L"Could not write received file '%S'", targetFileName); - //RETHROWEXCEPTION(L"Could not write received file",ex); + SGP_ERROR(ex.what()); + ScreenMsg( FONT_BCOLOR_BLUE, MSG_CHAT, MPClientMessage[70], targetFileName); } -#endif /* // Make sure it worked @@ -384,13 +316,11 @@ class ClientTransferCB : public FileListTransferCBInterface SetConnectScreenSubMessageW(MPClientMessage[60]); // setting this also causes connect screen to refresh //fileTransferProgress = 0; -#ifdef USE_VFS if(transferRules) { delete transferRules; transferRules = NULL; } -#endif if (recieved_settings && CLIENT_NUM > 0 && CLIENT_NUM <= 4) { @@ -427,15 +357,15 @@ class ClientTransferCB : public FileListTransferCBInterface else s = pathname; return s; } -#ifdef USE_VFS + // client has an ignore list too, as the server doesn't have to play by the rules static CTransferRules* transferRules; -#endif + } transferCallback; -#ifdef USE_VFS + CTransferRules* ClientTransferCB::transferRules = NULL; -#endif + ClientTransferCB transferCBClient; @@ -481,7 +411,6 @@ typedef struct UINT8 tsubNextTeam; } turn_struct; - typedef struct { @@ -635,94 +564,72 @@ int random_mercs[7]; // OJW - 20090305 int client_downloading[4]; int client_progress[4]; +int TEAM; -INT32 MAX_MERCS; - -int TEAM; -//int OP_TEAM_2; -//int OP_TEAM_3; -//int OP_TEAM_4; - - - -UINT8 netbTeam; +UINT8 netbTeam; UINT8 ubID_prefix; - bool is_connected=false; - bool is_connecting=false; - bool is_client=false; - bool is_server=false; - bool is_networked=false; - - bool is_host=false; // OJW - added 20081130 - new flag to signal our intention to host, coming in from the HOST screen - bool auto_retry=true; - int giNumTries = MAX_CONNECT_RETRIES; // default is 5 retries - UINT32 giNextRetryTime = 0; - - bool requested=false; - -int tcount; +bool is_connected=false; +bool is_connecting=false; +bool is_client=false; +bool is_server=false; +bool is_networked=false; +bool is_host=false; // OJW - added 20081130 - new flag to signal our intention to host, coming in from the HOST screen +bool auto_retry=true; +int giNumTries = MAX_CONNECT_RETRIES; // default is 5 retries +UINT32 giNextRetryTime = 0; +bool requested=false; int kit[20]; -bool DISABLE_MORALE; - int TESTING; - bool allowlaptop=false; +bool allowlaptop=false; +bool recieved_settings=false; +// OJW - 20090422 +bool recieved_transfer_settings = false; +bool getReal=false; - bool recieved_settings=false; - // OJW - 20090422 - bool recieved_transfer_settings = false; +int CLIENT_NUM; - bool getReal=false; +// -------------------- +// Global Client Variables +// -------------------- +UINT8 cStartingSectorEdge; +char cKitBag[100]; +char cClientName[30]; +UINT8 gRandomStartingEdge; +UINT8 gRandomMercs; +char cServerName[30]; +char cGameDataSyncDirectory[100]; +UINT8 cReportHiredMerc; +UINT8 cWeaponReadyBonus; +UINT8 cDisableSpectatorMode; +UINT8 gEnemyEnabled; +UINT8 gCreatureEnabled; +UINT8 gMilitiaEnabled; +UINT8 gCivEnabled; +UINT8 cAllowMercEquipment; +UINT8 cSameMercAllowed; +UINT8 cGameType; +UINT8 cMaxMercs; +FLOAT cDamageMultiplier; +UINT8 cMaxClients; +UINT8 cDisableMorale; +// -------------------- - //char CLIENT_NUM[30]; - int CLIENT_NUM; - char SECT_EDGE[30]; -char ckbag[100]; - char CLIENT_NAME[30]; - // OJW - 20081204 - char SERVER_NAME[30]; - int RANDOM_SPAWN; - int RANDOM_MERCS; - - char SERVER_IP[30] ; - char SERVER_PORT[30]; - char FILE_TRANSFER_DIRECTORY_CLIENT[100]; - - int SEND_FILES_CLIENT; - - int INVENTORY_MODE; - int REPORT_NAME; - int WEAPON_READIED_BONUS; - int DISABLE_SPEC_MODE; - - int ENEMY_ENABLED; - int CREATURE_ENABLED; - int MILITIA_ENABLED; - int CIV_ENABLED; - - int ALLOW_EQUIP; - - int SAME_MERC; - int PLAYER_BSIDE; - -int START_TEAM_TURN; - - bool goahead = 0; - int numready = 0; - int readystage = 0; - bool status = 0; - - bool wiped; - - bool lockedgui = 0; - -FLOAT DAMAGE_MULTIPLIER; - -//int INTERRUPTS; -int MAX_CLIENTS; - -UINT32 crate_usMapPos; - -INT16 crate_sGridX, crate_sGridY; +// -------------------- +// Other client variables +// -------------------- +bool goahead = 0; +int numready = 0; +int readystage = 0; +bool status = 0; +bool wiped; +UINT32 iScoreScreenTime = 0; +int iTeamsWiped = 0; // counts how many teams have wiped +bool is_game_over = false; +bool isOwnTeamWipedOut = false; +int iDisconnectedScreen = 0; +int bClosingChatBoxToStartGame = false; +UINT32 iCCStartGameTime = 0; +bool is_game_started = false; void overide_callback( UINT8 ubResult ); void kick_callback( UINT8 ubResult ); @@ -734,21 +641,6 @@ void disconnected_callback(UINT8 ubResult); // OJW - 20081222 void send_gameover( void ); void StartScoreScreen(); // this screen will send us to the multiplayer score screen -bool is_game_over = false; -UINT32 iScoreScreenTime = 0; -int iTeamsWiped = 0; // counts how many teams have wiped - -bool isOwnTeamWipedOut = false; - -//OJW - 20090210 -int iDisconnectedScreen = 0; - -//OJW - 20090302 -int bClosingChatBoxToStartGame = false; -UINT32 iCCStartGameTime = 0; - -// OJW - 20090317 -bool is_game_started = false; // OJW - 20090403 extern BOOLEAN gfMPSScoreScreenCanContinue; // can the score screen continue @@ -760,7 +652,6 @@ SystemAddress serverAddr; settings_struct gMPServerSettings; // store a copy of our settings after we receive them CHAR16 gszDisconnectReason[255]; // the reason we were disconnected from the server - // OJW - added 20081130 // - add retry timer and notification void NetworkAutoStart() @@ -804,6 +695,20 @@ void NetworkAutoStart() } } +void InvalidClientSettingsOkBoxCallback( UINT8 bExitValue ) +{ + // yes, load the game + if( bExitValue == MSG_BOX_RETURN_OK ) + { + // gracefully disconnect to the main menu + client_disconnect(); + guiPendingScreen = MP_JOIN_SCREEN; + } + + return; +} + + // OJW - this is just a fudge for now and needs to be improved later bool are_clients_downloading() { @@ -822,7 +727,7 @@ bool are_clients_downloading() void HireRandomMercs() { MERC_HIRE_STRUCT HireMercStruct; - for (int i=0; i < MAX_MERCS; i++) + for (int i=0; i < cMaxMercs; i++) { memset(&HireMercStruct, 0, sizeof(MERC_HIRE_STRUCT)); @@ -857,7 +762,6 @@ void send_path ( SOLDIERTYPE *pSoldier, INT32 sDestGridNo, UINT16 usMovementAni { //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"Sending new path" ); - EV_S_SENDPATHTONETWORK SNetPath; if(pSoldier->ubID < 20) @@ -866,67 +770,49 @@ void send_path ( SOLDIERTYPE *pSoldier, INT32 sDestGridNo, UINT16 usMovementAni SNetPath.usSoldierID = pSoldier->ubID; SNetPath.sAtGridNo=pSoldier->sGridNo; - - - SNetPath.ubNewState=usMovementAnim; - //if(fFromUI==255)SNetPath.ubNewState=255; - - SNetPath.usCurrentPathIndex=pSoldier->pathing.usPathIndex; - memcpy(SNetPath.usPathData, pSoldier->pathing.usPathingData, sizeof(UINT16)*30); - SNetPath.usPathDataSize=pSoldier->pathing.usPathDataSize; - SNetPath.sDestGridNo=sDestGridNo; + + SNetPath.ubNewState=usMovementAnim; + SNetPath.usCurrentPathIndex=pSoldier->pathing.usPathIndex; + memcpy(SNetPath.usPathData, pSoldier->pathing.usPathingData, sizeof(UINT16)*30); + SNetPath.usPathDataSize=pSoldier->pathing.usPathDataSize; + SNetPath.sDestGridNo=sDestGridNo; -//this stops soldier from advancing further than one square,and requests "clearance" for another after that... :) - //if(pSoldier->flags.fIsSoldierDelayed==FALSE) - //{ - // pSoldier->flags.fIsSoldierDelayed=TRUE; - // request_ovh(pSoldier->ubID); - //} - - client->RPC("sendPATH",(const char*)&SNetPath, (int)sizeof(EV_S_SENDPATHTONETWORK)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } - } void recievePATH(RPCParameters *rpcParameters) { + //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"Recieving new path," ); + + EV_S_SENDPATHTONETWORK* SNetPath = (EV_S_SENDPATHTONETWORK*)rpcParameters->input; - //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"Recieving new path," ); - - EV_S_SENDPATHTONETWORK* SNetPath = (EV_S_SENDPATHTONETWORK*)rpcParameters->input; + SOLDIERTYPE *pSoldier = MercPtrs[ SNetPath->usSoldierID ]; - SOLDIERTYPE *pSoldier = MercPtrs[ SNetPath->usSoldierID ]; + + memcpy(pSoldier->pathing.usPathingData, SNetPath->usPathData,sizeof(UINT16)*30); + + pSoldier->pathing.sDestination = SNetPath->sDestGridNo; + pSoldier->pathing.sFinalDestination = SNetPath->sDestGridNo; + pSoldier->pathing.usPathIndex=SNetPath->usCurrentPathIndex; + pSoldier->pathing.usPathDataSize=SNetPath->usPathDataSize; + + SendGetNewSoldierPathEvent( pSoldier, SNetPath->sDestGridNo, SNetPath->ubNewState ); + + INT16 sCellX, sCellY; - - memcpy(pSoldier->pathing.usPathingData, SNetPath->usPathData,sizeof(UINT16)*30); - - pSoldier->pathing.sDestination = SNetPath->sDestGridNo; - pSoldier->pathing.sFinalDestination = SNetPath->sDestGridNo; - pSoldier->pathing.usPathIndex=SNetPath->usCurrentPathIndex; - pSoldier->pathing.usPathDataSize=SNetPath->usPathDataSize; - - SendGetNewSoldierPathEvent( pSoldier, SNetPath->sDestGridNo, SNetPath->ubNewState ); - - INT16 sCellX, sCellY; - - - sCellX = CenterX( SNetPath->sAtGridNo ); - sCellY = CenterY( SNetPath->sAtGridNo ); - - //if ( !( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING | ANIM_SPECIALMOVE ) ) && pSoldier->fNoAPToFinishMove ) && !pSoldier->fPauseAllAnimation ) - if (( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING | ANIM_SPECIALMOVE ) ) && !(pSoldier->flags.fNoAPToFinishMove ) ) - { - } - else - { - pSoldier->EVENT_InternalSetSoldierPosition( sCellX, sCellY ,FALSE, FALSE, FALSE ); - - } + sCellX = CenterX( SNetPath->sAtGridNo ); + sCellY = CenterY( SNetPath->sAtGridNo ); - if(pSoldier)pSoldier->EVENT_InitNewSoldierAnim( SNetPath->ubNewState, 0, FALSE ); + if (( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_MOVING | ANIM_SPECIALMOVE ) ) && !(pSoldier->flags.fNoAPToFinishMove ) ) + { + } + else + { + pSoldier->EVENT_InternalSetSoldierPosition( sCellX, sCellY ,FALSE, FALSE, FALSE ); + } - + if(pSoldier)pSoldier->EVENT_InitNewSoldierAnim( SNetPath->ubNewState, 0, FALSE ); } @@ -950,6 +836,7 @@ void send_stance ( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance ) SChangeStance.sXPos = pSoldier->sX; SChangeStance.sYPos = pSoldier->sY; SChangeStance.uiUniqueId = pSoldier -> uiUniqueSoldierIdValue; + //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"change stance: %d",ubDesiredStance ); client->RPC("sendSTANCE",(const char*)&SChangeStance, (int)sizeof(EV_S_CHANGESTANCE)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); @@ -1041,81 +928,71 @@ void send_fire( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) } void recieveFIRE(RPCParameters *rpcParameters) -{ - - EV_S_BEGINFIREWEAPON* SBeginFireWeapon = (EV_S_BEGINFIREWEAPON*)rpcParameters->input; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"SendBeginFireWeaponEvent" ); +{ + EV_S_BEGINFIREWEAPON* SBeginFireWeapon = (EV_S_BEGINFIREWEAPON*)rpcParameters->input; + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"SendBeginFireWeaponEvent" ); - SOLDIERTYPE *pSoldier = MercPtrs[ SBeginFireWeapon->usSoldierID ]; + SOLDIERTYPE *pSoldier = MercPtrs[ SBeginFireWeapon->usSoldierID ]; - pSoldier->sTargetGridNo = SBeginFireWeapon->sTargetGridNo; - pSoldier->bTargetLevel = SBeginFireWeapon->bTargetLevel; - pSoldier->bTargetCubeLevel = SBeginFireWeapon->bTargetCubeLevel; - pSoldier->usAttackingWeapon = SBeginFireWeapon->uiUniqueId; //cheap hack to pass wep id. + pSoldier->sTargetGridNo = SBeginFireWeapon->sTargetGridNo; + pSoldier->bTargetLevel = SBeginFireWeapon->bTargetLevel; + pSoldier->bTargetCubeLevel = SBeginFireWeapon->bTargetCubeLevel; + pSoldier->usAttackingWeapon = SBeginFireWeapon->uiUniqueId; //cheap hack to pass wep id. - - SendBeginFireWeaponEvent( pSoldier, SBeginFireWeapon->sTargetGridNo ); + SendBeginFireWeaponEvent( pSoldier, SBeginFireWeapon->sTargetGridNo ); } void send_hit( EV_S_WEAPONHIT *SWeaponHit ) { + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"sendHIT" ); + //EV_S_WEAPONHIT* pWeaponHit = (EV_S_WEAPONHIT*)pEventData; + //SOLDIERTYPE *pSoldier = MercPtrs[ usSoldierID ]; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"sendHIT" ); - //EV_S_WEAPONHIT* pWeaponHit = (EV_S_WEAPONHIT*)pEventData; - //SOLDIERTYPE *pSoldier = MercPtrs[ usSoldierID ]; - - EV_S_WEAPONHIT weaphit_struct; - - memcpy( &weaphit_struct , SWeaponHit, sizeof( EV_S_WEAPONHIT )); - - UINT16 usSoldierID=weaphit_struct.usSoldierID; - - if(SWeaponHit->usSoldierID < 20)weaphit_struct.usSoldierID = weaphit_struct.usSoldierID+ubID_prefix; - if(SWeaponHit->ubAttackerID < 20)weaphit_struct.ubAttackerID = weaphit_struct.ubAttackerID+ubID_prefix; + EV_S_WEAPONHIT weaphit_struct; + memcpy( &weaphit_struct , SWeaponHit, sizeof( EV_S_WEAPONHIT )); + + UINT16 usSoldierID=weaphit_struct.usSoldierID; - client->RPC("sendHIT",(const char*)&weaphit_struct, (int)sizeof(EV_S_WEAPONHIT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - + if(SWeaponHit->usSoldierID < 20)weaphit_struct.usSoldierID = weaphit_struct.usSoldierID+ubID_prefix; + if(SWeaponHit->ubAttackerID < 20)weaphit_struct.ubAttackerID = weaphit_struct.ubAttackerID+ubID_prefix; + + client->RPC("sendHIT",(const char*)&weaphit_struct, (int)sizeof(EV_S_WEAPONHIT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieveHIT(RPCParameters *rpcParameters) { + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveHIT" ); - EV_S_WEAPONHIT* SWeaponHit = (EV_S_WEAPONHIT*)rpcParameters->input; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveHIT" ); - - SOLDIERTYPE *pSoldier = MercPtrs[ SWeaponHit->usSoldierID ]; - UINT16 usSoldierID; - UINT8 ubAttackerID; - - if((SWeaponHit->usSoldierID >= ubID_prefix) && (SWeaponHit->usSoldierID < (ubID_prefix+6))) // within our netbTeam range... - usSoldierID = (SWeaponHit->usSoldierID - ubID_prefix); - else - usSoldierID = SWeaponHit->usSoldierID; - - if((SWeaponHit->ubAttackerID >= ubID_prefix) && (SWeaponHit->ubAttackerID < (ubID_prefix+6))) - ubAttackerID = (SWeaponHit->ubAttackerID - ubID_prefix); - else - ubAttackerID = SWeaponHit->ubAttackerID; + EV_S_WEAPONHIT* SWeaponHit = (EV_S_WEAPONHIT*)rpcParameters->input; + SOLDIERTYPE *pSoldier = MercPtrs[ SWeaponHit->usSoldierID ]; + UINT16 usSoldierID; + UINT8 ubAttackerID; - - //AddGameEvent( S_WEAPONHIT, 0, &SWeaponHit ); - WeaponHit( usSoldierID, SWeaponHit->usWeaponIndex, SWeaponHit->sDamage, SWeaponHit->sBreathLoss, SWeaponHit->usDirection, SWeaponHit->sXPos, SWeaponHit->sYPos, SWeaponHit->sZPos, SWeaponHit->sRange, ubAttackerID, SWeaponHit->fHit, SWeaponHit->ubSpecial, SWeaponHit->ubLocation ); + if((SWeaponHit->usSoldierID >= ubID_prefix) && (SWeaponHit->usSoldierID < (ubID_prefix+6))) // within our netbTeam range... + usSoldierID = (SWeaponHit->usSoldierID - ubID_prefix); + else + usSoldierID = SWeaponHit->usSoldierID; - if(SWeaponHit->fStopped) - { - INT8 bTeam=pSoldier->bTeam; - INT32 iBullet = bTable[bTeam][SWeaponHit->iBullet].local_id; - - RemoveBullet(iBullet); - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"removed bullet" ); + if((SWeaponHit->ubAttackerID >= ubID_prefix) && (SWeaponHit->ubAttackerID < (ubID_prefix+6))) + ubAttackerID = (SWeaponHit->ubAttackerID - ubID_prefix); + else + ubAttackerID = SWeaponHit->ubAttackerID; - - } - + WeaponHit( usSoldierID, SWeaponHit->usWeaponIndex, SWeaponHit->sDamage, SWeaponHit->sBreathLoss, SWeaponHit->usDirection, SWeaponHit->sXPos, SWeaponHit->sYPos, SWeaponHit->sZPos, SWeaponHit->sRange, ubAttackerID, SWeaponHit->fHit, SWeaponHit->ubSpecial, SWeaponHit->ubLocation ); + + if(SWeaponHit->fStopped) + { + INT8 bTeam=pSoldier->bTeam; + INT32 iBullet = bTable[bTeam][SWeaponHit->iBullet].local_id; + + RemoveBullet(iBullet); + + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"removed bullet" ); + } } @@ -1130,78 +1007,50 @@ void send_dismiss(UINT8 ubCurrentSoldierID) void send_hire( UINT8 iNewIndex, UINT8 ubCurrentSoldier, INT16 iTotalContractLength, BOOLEAN fCopyProfileItemsOver) { - + send_hire_struct sHireMerc; + + sHireMerc.ubProfileID=ubCurrentSoldier; + sHireMerc.team=TEAM; + sHireMerc.fCopyProfileItemsOver=fCopyProfileItemsOver; + sHireMerc.bTeam=netbTeam; + + SOLDIERTYPE *pSoldier = MercPtrs[ iNewIndex ]; + + UINT8 sectorEdge = cStartingSectorEdge; + + // WANNE - MP: Center + if (sectorEdge == MP_EDGE_CENTER) + sectorEdge = INSERTION_CODE_CENTER; + + pSoldier->ubStrategicInsertionCode = sectorEdge; + + if(ubCurrentSoldier==64)//slay + { + pSoldier->ubBodyType = REGMALE; + gMercProfiles[ pSoldier->ubProfile ].ubBodyType = REGMALE; + } + + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[44], pSoldier->name); + + AddCharacterToAnySquad( pSoldier ); + + //add recruited flag + gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED; + + OBJECTTYPE Object; + int cnt; + for (cnt=0; cnt<20;cnt++) + { + int item=kit[cnt]; + + if(item != 0) { - send_hire_struct sHireMerc; - - sHireMerc.ubProfileID=ubCurrentSoldier; - //sHireMerc.iTotalContractLength=iTotalContractLength; - sHireMerc.team=TEAM; - sHireMerc.fCopyProfileItemsOver=fCopyProfileItemsOver; - - - sHireMerc.bTeam=netbTeam; - - SOLDIERTYPE *pSoldier = MercPtrs[ iNewIndex ]; - - UINT8 sectorEdge = atoi(SECT_EDGE); - - // WANNE - MP: Center - if (sectorEdge == MP_EDGE_CENTER) - sectorEdge = INSERTION_CODE_CENTER; - - pSoldier->ubStrategicInsertionCode = sectorEdge; - - if(ubCurrentSoldier==64)//slay - { - pSoldier->ubBodyType = REGMALE; - //pSoldier->EVENT_InitNewSoldierAnim( STANDING, 0 , TRUE ); - gMercProfiles[ pSoldier->ubProfile ].ubBodyType = REGMALE; - - } - - - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[44], pSoldier->name); - - - AddCharacterToAnySquad( pSoldier ); - //AddSoldierToSector( pSoldier->ubID ); //add g\hired merc to sector so can access sector inv. - - //add recruited flag - gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED; - - OBJECTTYPE Object; - int cnt; - for (cnt=0; cnt<20;cnt++) - { - int item=kit[cnt]; - - if(item != 0) - { - CreateItem( item, 100, &Object ); - AutoPlaceObject( pSoldier, &Object, TRUE ); - } - } - - - - - //if (pSoldier->ubID==0) - //{ - // ///create crate apon first hire - ////crate_usMapPos = MAPROWCOLTOPOS( crate_sGridY, crate_sGridX ); - //crate_usMapPos = ChooseMapEdgepoint(pSoldier->ubStrategicInsertionCode); - - ////crate_usMapPos = ChooseMapEdgepoint(atoi(SECT_EDGE)); - //AddStructToUnLoadedMapTempFile( crate_usMapPos, SECONDOSTRUCT3, gsMercArriveSectorX, gsMercArriveSectorY, 0 ); - //} - - - - - - client->RPC("sendHIRE",(const char*)&sHireMerc, (int)sizeof(send_hire_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + CreateItem( item, 100, &Object ); + AutoPlaceObject( pSoldier, &Object, TRUE ); } + } + + client->RPC("sendHIRE",(const char*)&sHireMerc, (int)sizeof(send_hire_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieveDISMISS(RPCParameters *rpcParameters) @@ -1216,26 +1065,15 @@ void recieveDISMISS(RPCParameters *rpcParameters) void recieveHIRE(RPCParameters *rpcParameters) { - send_hire_struct* sHireMerc = (send_hire_struct*)rpcParameters->input; - - SOLDIERTYPE *pSoldier; UINT8 iNewIndex; UINT8 ubCount=0; - SOLDIERCREATE_STRUCT MercCreateStruct; BOOLEAN fReturn = FALSE; - - - // WANNE - MP: Fix by Realist (avoid CTDs) - //memset( &MercCreateStruct, 0, sizeof( MercCreateStruct ) ); - //MercCreateStruct = SOLDIERCREATE_STRUCT(); - - MercCreateStruct.ubProfile = sHireMerc->ubProfileID; MercCreateStruct.fPlayerMerc = 0; MercCreateStruct.sSectorX = gsMercArriveSectorX; @@ -1243,47 +1081,43 @@ void recieveHIRE(RPCParameters *rpcParameters) MercCreateStruct.bSectorZ = 0; MercCreateStruct.bTeam = sHireMerc->bTeam; MercCreateStruct.fCopyProfileItemsOver = sHireMerc->fCopyProfileItemsOver; - - TacticalCreateSoldier( &MercCreateStruct, &iNewIndex ) ; pSoldier = &Menptr[iNewIndex]; pSoldier->flags.uiStatusFlags |= SOLDIER_PC; gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED; - if(!SAME_MERC)gMercProfiles[ pSoldier->ubProfile ].bMercStatus = MERC_WORKING_ELSEWHERE; + + if(!cSameMercAllowed) + gMercProfiles[ pSoldier->ubProfile ].bMercStatus = MERC_WORKING_ELSEWHERE; + pSoldier->bSide=0; //default coop only gTacticalStatus.Team[MercCreateStruct.bTeam ].bSide=0; - if(MercCreateStruct.ubProfile==64)//slay - { - pSoldier->ubBodyType = REGMALE; - //pSoldier->EVENT_InitNewSoldierAnim( STANDING, 0 , TRUE ); - gMercProfiles[ pSoldier->ubProfile ].ubBodyType = REGMALE; - - } + if(MercCreateStruct.ubProfile==64)//slay + { + pSoldier->ubBodyType = REGMALE; + gMercProfiles[ pSoldier->ubProfile ].ubBodyType = REGMALE; + } - if(PLAYER_BSIDE==0)//all vs all only + if(cGameType==MP_TYPE_DEATHMATCH)//all vs all only { pSoldier->bSide=1; gTacticalStatus.Team[MercCreateStruct.bTeam ].bSide=1; } - if(PLAYER_BSIDE==1) //allow teams + if(cGameType==MP_TYPE_TEAMDEATMATCH) //allow teams { - if(sHireMerc->team != TEAM) - { - pSoldier->bSide=1; - gTacticalStatus.Team[MercCreateStruct.bTeam ].bSide=1; - } - + if(sHireMerc->team != TEAM) + { + pSoldier->bSide=1; + gTacticalStatus.Team[MercCreateStruct.bTeam ].bSide=1; + } } - AddSoldierToSector( iNewIndex ); - - if(REPORT_NAME==1) + if(cReportHiredMerc == 1) { ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[5],MercCreateStruct.bTeam-5,client_names[MercCreateStruct.bTeam-6],pSoldier->name ); } @@ -1291,120 +1125,85 @@ void recieveHIRE(RPCParameters *rpcParameters) { ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[6],MercCreateStruct.bTeam-5,client_names[MercCreateStruct.bTeam-6] ); } - - } void send_gui_pos(SOLDIERTYPE *pSoldier, FLOAT dNewXPos, FLOAT dNewYPos) { - - { - - gui_pos gnPOS; + gui_pos gnPOS; - + gnPOS.usSoldierID = (pSoldier->ubID)+ubID_prefix; + gnPOS.dNewXPos = dNewXPos; + gnPOS.dNewYPos = dNewYPos; - gnPOS.usSoldierID = (pSoldier->ubID)+ubID_prefix; - - gnPOS.dNewXPos = dNewXPos; - gnPOS.dNewYPos = dNewYPos; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"guiPOS: %f , %f", dNewXPos,dNewYPos); - - - client->RPC("sendguiPOS",(const char*)&gnPOS, (int)sizeof(gui_pos)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } - + client->RPC("sendguiPOS",(const char*)&gnPOS, (int)sizeof(gui_pos)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } + void recieveguiPOS(RPCParameters *rpcParameters) { - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveguiPOS" ); - gui_pos* gnPOS = (gui_pos*)rpcParameters->input; + gui_pos* gnPOS = (gui_pos*)rpcParameters->input; - SOLDIERTYPE *pSoldier = MercPtrs[ gnPOS->usSoldierID ]; + SOLDIERTYPE *pSoldier = MercPtrs[ gnPOS->usSoldierID ]; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"guiPOS: %f , %f", gnPOS->dNewXPos,gnPOS->dNewYPos); - - INT32 sNewGridNo; + INT32 sNewGridNo; - sNewGridNo = GETWORLDINDEXFROMWORLDCOORDS(gnPOS->dNewXPos, gnPOS->dNewYPos ); - pSoldier->usStrategicInsertionData=sNewGridNo; - pSoldier->ubStrategicInsertionCode=INSERTION_CODE_GRIDNO; - pSoldier->sInsertionGridNo = pSoldier->usStrategicInsertionData; + sNewGridNo = GETWORLDINDEXFROMWORLDCOORDS(gnPOS->dNewXPos, gnPOS->dNewYPos ); + pSoldier->usStrategicInsertionData=sNewGridNo; + pSoldier->ubStrategicInsertionCode=INSERTION_CODE_GRIDNO; + pSoldier->sInsertionGridNo = pSoldier->usStrategicInsertionData; - - pSoldier->EVENT_SetSoldierPosition( gnPOS->dNewXPos, gnPOS->dNewYPos ); - + pSoldier->EVENT_SetSoldierPosition( gnPOS->dNewXPos, gnPOS->dNewYPos ); } void send_gui_dir(SOLDIERTYPE *pSoldier, UINT16 usNewDirection) -{ - - { - - gui_dir gnDIR; +{ + gui_dir gnDIR; - - - gnDIR.usSoldierID = (pSoldier->ubID)+ubID_prefix; - gnDIR.usNewDirection = usNewDirection; - - - - client->RPC("sendguiDIR",(const char*)&gnDIR, (int)sizeof(gui_dir)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } + gnDIR.usSoldierID = (pSoldier->ubID)+ubID_prefix; + gnDIR.usNewDirection = usNewDirection; + client->RPC("sendguiDIR",(const char*)&gnDIR, (int)sizeof(gui_dir)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieveguiDIR(RPCParameters *rpcParameters) { - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveguiDIR" ); - gui_dir* gnDIR = (gui_dir*)rpcParameters->input; + gui_dir* gnDIR = (gui_dir*)rpcParameters->input; - SOLDIERTYPE *pSoldier = MercPtrs[ gnDIR->usSoldierID ]; - - pSoldier->EVENT_SetSoldierDirection( gnDIR->usNewDirection ); - //pSoldier->ubInsertionDirection = pSoldier->bDirection; + SOLDIERTYPE *pSoldier = MercPtrs[ gnDIR->usSoldierID ]; + + pSoldier->EVENT_SetSoldierDirection( gnDIR->usNewDirection ); } - - void send_EndTurn( UINT8 ubNextTeam ) { - - { - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"sendEndTurn" ); - - if(ubNextTeam==0) - { - // translate next team id for clients - ubNextTeam=netbTeam; - } - + if(ubNextTeam==0) + { + // translate next team id for clients + ubNextTeam=netbTeam; + } - turn_struct tStruct; - if(is_server)Sawarded=false; - - tStruct.tsnetbTeam = netbTeam; - tStruct.tsubNextTeam = ubNextTeam; - - - client->RPC("sendEndTurn",(const char*)&tStruct, (int)sizeof(turn_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } + turn_struct tStruct; + if(is_server) + Sawarded=false; + tStruct.tsnetbTeam = netbTeam; + tStruct.tsubNextTeam = ubNextTeam; + + client->RPC("sendEndTurn",(const char*)&tStruct, (int)sizeof(turn_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieveEndTurn(RPCParameters *rpcParameters) { turn_struct* tStruct = (turn_struct*)rpcParameters->input; - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"recieveEndTurn" ); UINT8 sender_bTeam; UINT8 ubTeam; sender_bTeam=tStruct->tsnetbTeam; ubTeam=tStruct->tsubNextTeam; - if(is_server)Sawarded=false; + + if(is_server) + Sawarded=false; // if the message was recieved from the server.. if(is_server || sender_bTeam==6) @@ -1423,208 +1222,167 @@ void recieveEndTurn(RPCParameters *rpcParameters) if(!is_server && is_client) EndTurn( ubTeam ); + requested=false ;//request for realtime made or not BeginTeamTurn( ubTeam ); } } - UINT8 numenemyLAN( UINT8 ubSectorX, UINT8 ubSectorY ) { - SOLDIERTYPE *pSoldier; UINT8 cnt ; //first posible lan player UINT8 ubNumEnemies = 0; - for ( cnt=120 ; cnt <= 155; cnt++ ) { pSoldier = MercPtrs[cnt]; if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 ) { - if ( !pSoldier->aiData.bNeutral && (pSoldier->bSide != 0 ) ) { ubNumEnemies++; } } - } - return ubNumEnemies; + return ubNumEnemies; } void send_AI( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 *pubID ) { - //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"send_AI" ); + AI_STRUCT send_inv; + send_inv.standard_data = *pCreateStruct; - //SOLDIERCREATE_STRUCT aaa = *pCreateStruct; + for(int x=0;x<55;x++) + { + send_inv.slot[x] = pCreateStruct->Inv[x]; + } - AI_STRUCT send_inv; - - send_inv.standard_data = *pCreateStruct; - - - - for(int x=0;x<55;x++) - { - send_inv.slot[x] = pCreateStruct->Inv[x]; - } - - - - client->RPC("sendAI",(const char*)&send_inv, (int)sizeof(AI_STRUCT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - + client->RPC("sendAI",(const char*)&send_inv, (int)sizeof(AI_STRUCT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieveAI (RPCParameters *rpcParameters) { - UINT8 iNewIndex; - SOLDIERTYPE *pSoldier; + UINT8 iNewIndex; + SOLDIERTYPE *pSoldier; + AI_STRUCT* send_inv = (AI_STRUCT*)rpcParameters->input; + SOLDIERCREATE_STRUCT new_standard_data; //as originally my soldiercreate_struct would get its INV mangled through the RPC, so i send it packaged with it, then create a new struct and add in the bits that are still ok from the original struct, along with the packaged INV components... - AI_STRUCT* send_inv = (AI_STRUCT*)rpcParameters->input; + new_standard_data.bAgility = send_inv->standard_data.bAgility; + new_standard_data.bAIMorale = send_inv->standard_data.bAIMorale; + new_standard_data.bAttitude = send_inv->standard_data.bAttitude; + new_standard_data.bBodyType = send_inv->standard_data.bBodyType; + new_standard_data.bDexterity = send_inv->standard_data.bDexterity; + new_standard_data.ubDirection = send_inv->standard_data.ubDirection; + new_standard_data.bExpLevel = send_inv->standard_data.bExpLevel; + new_standard_data.bExplosive = send_inv->standard_data.bExplosive; + new_standard_data.bLeadership = send_inv->standard_data.bLeadership; + new_standard_data.bLife = send_inv->standard_data.bLife; + new_standard_data.bLifeMax = send_inv->standard_data.bLifeMax; + new_standard_data.bMarksmanship = send_inv->standard_data.bMarksmanship; + new_standard_data.bMechanical = send_inv->standard_data.bMechanical; + new_standard_data.bMedical = send_inv->standard_data.bMedical; + new_standard_data.bMorale = send_inv->standard_data.bMorale; + new_standard_data.bOrders = send_inv->standard_data.bOrders; + new_standard_data.bPatrolCnt = send_inv->standard_data.bPatrolCnt; + new_standard_data.bSectorZ = send_inv->standard_data.bSectorZ; + new_standard_data.bStrength = send_inv->standard_data.bStrength; + new_standard_data.bTeam = send_inv->standard_data.bTeam; + new_standard_data.bUseGivenVehicleID = send_inv->standard_data.bUseGivenVehicleID; + new_standard_data.bWisdom = send_inv->standard_data.bWisdom; + new_standard_data.endOfPOD = send_inv->standard_data.endOfPOD; + new_standard_data.fCopyProfileItemsOver = send_inv->standard_data.fCopyProfileItemsOver; + new_standard_data.fHasKeys = send_inv->standard_data.fHasKeys; + new_standard_data.fKillSlotIfOwnerDies = send_inv->standard_data.fKillSlotIfOwnerDies; + new_standard_data.fOnRoof = send_inv->standard_data.fOnRoof; + new_standard_data.fPlayerMerc = send_inv->standard_data.fPlayerMerc; + new_standard_data.fPlayerPlan = send_inv->standard_data.fPlayerPlan; + new_standard_data.fStatic = send_inv->standard_data.fStatic; + new_standard_data.fUseExistingSoldier = send_inv->standard_data.fUseExistingSoldier; + new_standard_data.fUseGivenVehicle = send_inv->standard_data.fUseGivenVehicle; + new_standard_data.fVisible = send_inv->standard_data.fVisible; + memcpy( new_standard_data.HeadPal , send_inv->standard_data.HeadPal, sizeof( PaletteRepID )); + memcpy( new_standard_data.MiscPal , send_inv->standard_data.MiscPal, sizeof( PaletteRepID )); + memcpy( new_standard_data.name , send_inv->standard_data.name, sizeof( CHAR16 ) * 10 ); + memcpy( new_standard_data.PantsPal , send_inv->standard_data.PantsPal, sizeof( PaletteRepID )); + new_standard_data.pExistingSoldier = send_inv->standard_data.pExistingSoldier; + new_standard_data.sInsertionGridNo = send_inv->standard_data.sInsertionGridNo; + memcpy( new_standard_data.SkinPal , send_inv->standard_data.SkinPal, sizeof( PaletteRepID )); + memcpy( new_standard_data.sPatrolGrid, send_inv->standard_data.sPatrolGrid, sizeof( INT32 ) * MAXPATROLGRIDS );//dnl ch27 230909 + new_standard_data.sSectorX = send_inv->standard_data.sSectorX; + new_standard_data.sSectorY = send_inv->standard_data.sSectorY; + new_standard_data.ubCivilianGroup = send_inv->standard_data.ubCivilianGroup; + new_standard_data.ubProfile = send_inv->standard_data.ubProfile; + new_standard_data.ubScheduleID = send_inv->standard_data.ubScheduleID; + new_standard_data.ubSoldierClass = send_inv->standard_data.ubSoldierClass; + memcpy( new_standard_data.VestPal , send_inv->standard_data.VestPal, sizeof( PaletteRepID )); - SOLDIERCREATE_STRUCT new_standard_data; //as originally my soldiercreate_struct would get its INV mangled through the RPC, so i send it packaged with it, then create a new struct and add in the bits that are still ok from the original struct, along with the packaged INV components... - + for(int x=0;x<55;x++) + { + if(send_inv->slot[x].usItem != 0) + CreateItems( send_inv->slot[x].usItem, 100, send_inv->slot[x].ubNumberOfObjects, &new_standard_data.Inv[x] ); + } - new_standard_data.bAgility = send_inv->standard_data.bAgility; - new_standard_data.bAIMorale = send_inv->standard_data.bAIMorale; - new_standard_data.bAttitude = send_inv->standard_data.bAttitude; - new_standard_data.bBodyType = send_inv->standard_data.bBodyType; - new_standard_data.bDexterity = send_inv->standard_data.bDexterity; - new_standard_data.ubDirection = send_inv->standard_data.ubDirection; - new_standard_data.bExpLevel = send_inv->standard_data.bExpLevel; - new_standard_data.bExplosive = send_inv->standard_data.bExplosive; - new_standard_data.bLeadership = send_inv->standard_data.bLeadership; - new_standard_data.bLife = send_inv->standard_data.bLife; - new_standard_data.bLifeMax = send_inv->standard_data.bLifeMax; - new_standard_data.bMarksmanship = send_inv->standard_data.bMarksmanship; - new_standard_data.bMechanical = send_inv->standard_data.bMechanical; - new_standard_data.bMedical = send_inv->standard_data.bMedical; - new_standard_data.bMorale = send_inv->standard_data.bMorale; - new_standard_data.bOrders = send_inv->standard_data.bOrders; - - // WANNE - MP: I had to remove this line of code, because PADDINGSLOTS in the structure - // breaks the editor and leads to crashed of modifed maps! - //memcpy( new_standard_data.PADDINGSLOTS, send_inv->standard_data.PADDINGSLOTS, sizeof( INT8 ) * 14 ); - - new_standard_data.bPatrolCnt = send_inv->standard_data.bPatrolCnt; - new_standard_data.bSectorZ = send_inv->standard_data.bSectorZ; - new_standard_data.bStrength = send_inv->standard_data.bStrength; - new_standard_data.bTeam = send_inv->standard_data.bTeam; - new_standard_data.bUseGivenVehicleID = send_inv->standard_data.bUseGivenVehicleID; - new_standard_data.bWisdom = send_inv->standard_data.bWisdom; - //new_standard_data.ef1 = send_inv->standard_data.ef1; - //new_standard_data.ef2 = send_inv->standard_data.ef2; - new_standard_data.endOfPOD = send_inv->standard_data.endOfPOD; - new_standard_data.fCopyProfileItemsOver = send_inv->standard_data.fCopyProfileItemsOver; - new_standard_data.fHasKeys = send_inv->standard_data.fHasKeys; - new_standard_data.fKillSlotIfOwnerDies = send_inv->standard_data.fKillSlotIfOwnerDies; - new_standard_data.fOnRoof = send_inv->standard_data.fOnRoof; - new_standard_data.fPlayerMerc = send_inv->standard_data.fPlayerMerc; - new_standard_data.fPlayerPlan = send_inv->standard_data.fPlayerPlan; - new_standard_data.fStatic = send_inv->standard_data.fStatic; - new_standard_data.fUseExistingSoldier = send_inv->standard_data.fUseExistingSoldier; - new_standard_data.fUseGivenVehicle = send_inv->standard_data.fUseGivenVehicle; - new_standard_data.fVisible = send_inv->standard_data.fVisible; - memcpy( new_standard_data.HeadPal , send_inv->standard_data.HeadPal, sizeof( PaletteRepID )); - memcpy( new_standard_data.MiscPal , send_inv->standard_data.MiscPal, sizeof( PaletteRepID )); - memcpy( new_standard_data.name , send_inv->standard_data.name, sizeof( CHAR16 ) * 10 ); - memcpy( new_standard_data.PantsPal , send_inv->standard_data.PantsPal, sizeof( PaletteRepID )); - new_standard_data.pExistingSoldier = send_inv->standard_data.pExistingSoldier; - new_standard_data.sInsertionGridNo = send_inv->standard_data.sInsertionGridNo; - memcpy( new_standard_data.SkinPal , send_inv->standard_data.SkinPal, sizeof( PaletteRepID )); - memcpy( new_standard_data.sPatrolGrid, send_inv->standard_data.sPatrolGrid, sizeof( INT32 ) * MAXPATROLGRIDS );//dnl ch27 230909 - new_standard_data.sSectorX = send_inv->standard_data.sSectorX; - new_standard_data.sSectorY = send_inv->standard_data.sSectorY; - new_standard_data.ubCivilianGroup = send_inv->standard_data.ubCivilianGroup; - new_standard_data.ubProfile = send_inv->standard_data.ubProfile; - new_standard_data.ubScheduleID = send_inv->standard_data.ubScheduleID; - new_standard_data.ubSoldierClass = send_inv->standard_data.ubSoldierClass; - memcpy( new_standard_data.VestPal , send_inv->standard_data.VestPal, sizeof( PaletteRepID )); - + new_standard_data.fPlayerPlan=1; - for(int x=0;x<55;x++) - { - //OBJECTTYPE Object; - //new_standard_data.Inv[x] + TacticalCreateSoldier( &new_standard_data, &iNewIndex ); + pSoldier = &Menptr[iNewIndex]; + pSoldier->flags.uiStatusFlags |= SOLDIER_PC; - //new_standard_data.Inv[x].fFlags = send_inv->slot[x].fFlags; - if(send_inv->slot[x].usItem != 0)CreateItems( send_inv->slot[x].usItem, 100, send_inv->slot[x].ubNumberOfObjects, &new_standard_data.Inv[x] ); - //new_standard_data.Inv[x] = Object; - } - - - new_standard_data.fPlayerPlan=1; - - - TacticalCreateSoldier( &new_standard_data, &iNewIndex ); - pSoldier = &Menptr[iNewIndex]; - pSoldier->flags.uiStatusFlags |= SOLDIER_PC; - - AddSoldierToSector( iNewIndex ); - //ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"recieveAI" ); - - - + AddSoldierToSector( iNewIndex ); } void send_ready ( void ) { - ready_struct info; - info.client_num = CLIENT_NUM; - - if(readystage==0) - { - - info.ready_stage = 0; - if(status==0) - { - info.status = 1; - status=1; - numready = numready+1; - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[7],numready,MAX_CLIENTS ); - // OJW - 20081204 - client_ready[info.client_num-1]=1; - fDrawCharacterList = true; // set the character list to be redrawn - } - else - { - info.status = 0; - status=0; - numready = numready-1; - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[8],numready,MAX_CLIENTS ); - // OJW - 20081204 - client_ready[info.client_num-1]=0; - fDrawCharacterList = true; // set the character list to be redrawn - } - } - - - - if(is_server && numready == MAX_CLIENTS) //all ready. and server tells all to load... - { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[9] ); + ready_struct info; + info.client_num = CLIENT_NUM; - goahead=1; - readystage=1; - - info.ready_stage = 1; - info.status = 1; - } - - - - client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - - if(is_server && numready == MAX_CLIENTS) + if(readystage==0) + { + info.ready_stage = 0; + if(status==0) { - - status=0;//reset - numready=0; - start_battle();//server loads + info.status = 1; + status=1; + numready = numready+1; + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[7],numready,cMaxClients ); + // OJW - 20081204 + client_ready[info.client_num-1]=1; + fDrawCharacterList = true; // set the character list to be redrawn } + else + { + info.status = 0; + status=0; + numready = numready-1; + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[8],numready,cMaxClients ); + // OJW - 20081204 + client_ready[info.client_num-1]=0; + fDrawCharacterList = true; // set the character list to be redrawn + } + } + + if(is_server && numready == cMaxClients) //all ready. and server tells all to load... + { + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[9] ); + + goahead=1; + readystage=1; + + info.ready_stage = 1; + info.status = 1; + } + + client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + + if(is_server && numready == cMaxClients) + { + status=0;//reset + numready=0; + start_battle();//server loads + } } void recieveREADY (RPCParameters *rpcParameters) @@ -1634,7 +1392,7 @@ void recieveREADY (RPCParameters *rpcParameters) if(info->ready_stage==1)//recived ok for go ahead from server for level load { numready++; - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[10], info->client_num,client_names[info->client_num-1],numready,MAX_CLIENTS ); + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[10], info->client_num,client_names[info->client_num-1],numready,cMaxClients ); ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[9] ); status=0;//reset numready=0; @@ -1645,35 +1403,34 @@ void recieveREADY (RPCParameters *rpcParameters) { if (info->status==1) { - numready = numready+1; - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[10], info->client_num,client_names[info->client_num-1],numready,MAX_CLIENTS ); - // OJW - 20081204 - client_ready[info->client_num-1]=1; - fDrawCharacterList = true; // set the character list to be redrawn + numready = numready+1; + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[10], info->client_num,client_names[info->client_num-1],numready,cMaxClients ); + // OJW - 20081204 + client_ready[info->client_num-1]=1; + fDrawCharacterList = true; // set the character list to be redrawn } else { - numready = numready-1; - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[11], info->client_num,client_names[info->client_num-1],numready,MAX_CLIENTS ); - // OJW - 20081204 - client_ready[info->client_num-1]=0; - fDrawCharacterList = true; // set the character list to be redrawn + numready = numready-1; + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[11], info->client_num,client_names[info->client_num-1],numready,cMaxClients ); + // OJW - 20081204 + client_ready[info->client_num-1]=0; + fDrawCharacterList = true; // set the character list to be redrawn } - if(is_server && numready == MAX_CLIENTS) //all ready. and server tells all to load...and loads himself + if(is_server && numready == cMaxClients) //all ready. and server tells all to load...and loads himself { goahead=1; readystage=1; send_ready(); start_battle(); - } } else if(info->ready_stage==36)//server allows laptop access { ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[36] ); allowlaptop=1; - if (RANDOM_MERCS) + if (gRandomMercs) HireRandomMercs(); // server is starting the game, adjust the games max players @@ -1684,130 +1441,123 @@ void recieveREADY (RPCParameters *rpcParameters) if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) iPlayersConnected++; - MAX_CLIENTS = iPlayersConnected; + cMaxClients = iPlayersConnected; } - } void send_loaded (void) { - ready_struct info; - info.client_num = CLIENT_NUM; - info.ready_stage = 1;//done loading level + ready_struct info; + info.client_num = CLIENT_NUM; + info.ready_stage = 1;//done loading level + info.status=1; + + numready++; + if(numready==cMaxClients && is_server) + { + lockui(1);//unlock ui + readystage=0; + numready=0; + + info.ready_stage = 2;//done placing mercs info.status=1; + } - numready++; - if(numready==MAX_CLIENTS && is_server) - { - lockui(1);//unlock ui - readystage=0; - numready=0; - - info.ready_stage = 2;//done placing mercs - info.status=1; - - //client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } - - client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - + client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void send_donegui ( UINT8 ubResult ) { - if(ubResult==1 && status==0)return;//avoid double remove callback response from final message box removal - ready_struct info; - info.client_num = CLIENT_NUM; - if(ubResult==1)DialogRemoved(1);//cleanup msgbox after not ready - if(status==0)//now ready - { - status=1; - numready++; + if(ubResult==1 && status==0) + return;//avoid double remove callback response from final message box removal + + ready_struct info; + info.client_num = CLIENT_NUM; + + if(ubResult==1) + DialogRemoved(1);//cleanup msgbox after not ready + + if(status==0)//now ready + { + status=1; + numready++; info.ready_stage = 3;//done placing mercs info.status=1; - - SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; - DoMessageBox( MSG_BOX_BASIC_STYLE, MPClientMessage[12], guiCurrentScreen, MSG_BOX_FLAG_OK | MSG_BOX_FLAG_USE_CENTERING_RECT, send_donegui, &CenterRect ); - - - if(numready==MAX_CLIENTS && is_server)//all done - { - - numready=0; - status=0; - info.ready_stage = 4;//done placing mercs - info.status=1; - gMsgBox.bHandled = MSG_BOX_RETURN_OK; - KillTacticalPlacementGUI(); //send and kill - ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[13]); - } - } - else if(status==1)//was ready - { - status=0; - numready--; - info.ready_stage = 3;//not done placing mercs - info.status=0; - } - + SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; + DoMessageBox( MSG_BOX_BASIC_STYLE, MPClientMessage[12], guiCurrentScreen, MSG_BOX_FLAG_OK | MSG_BOX_FLAG_USE_CENTERING_RECT, send_donegui, &CenterRect ); - client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + if(numready==cMaxClients && is_server)//all done + { + numready=0; + status=0; + info.ready_stage = 4;//done placing mercs + info.status=1; + gMsgBox.bHandled = MSG_BOX_RETURN_OK; + KillTacticalPlacementGUI(); //send and kill + ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[13]); + } + } + else if(status==1)//was ready + { + status=0; + numready--; + info.ready_stage = 3;//not done placing mercs + info.status=0; + } + + client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieveGUI (RPCParameters *rpcParameters) { - - ready_struct* info = (ready_struct*)rpcParameters->input; if(info->ready_stage==1 && info->status==1) { numready++; - if(numready==MAX_CLIENTS && is_server) + if(numready==cMaxClients && is_server) { lockui(1);//unlock ui readystage=0; numready=0; - ready_struct info; - info.client_num = CLIENT_NUM; - info.ready_stage = 2;//done placing mercs - info.status=1; + ready_struct info; + info.client_num = CLIENT_NUM; + info.ready_stage = 2;//done placing mercs + info.status=1; - client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } - } + if(info->ready_stage==2 && info->status ==1) { lockui(1);//unlock ui readystage=0; numready=0; - } if(info->ready_stage==3 && info->status==1)//recieved client done placement { numready++; - if(numready==MAX_CLIENTS && is_server)//all done + if(numready==cMaxClients && is_server)//all done { - numready=0; + numready=0; - ready_struct info; - info.client_num = CLIENT_NUM; - info.ready_stage = 4;//all done placing mercs, kill all - info.status=1; - gMsgBox.bHandled = MSG_BOX_RETURN_OK; - status=0; - KillTacticalPlacementGUI(); - ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[13]); + ready_struct info; + info.client_num = CLIENT_NUM; + info.ready_stage = 4;//all done placing mercs, kill all + info.status=1; + gMsgBox.bHandled = MSG_BOX_RETURN_OK; + status=0; + KillTacticalPlacementGUI(); + ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[13]); - client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } } - if(info->ready_stage==3 && info->status==0)//recieved client retracted place ready... { numready--; @@ -1821,36 +1571,34 @@ void recieveGUI (RPCParameters *rpcParameters) numready=0; status=0; } - } + void allowlaptop_callback ( UINT8 ubResult ) { - if(ubResult==2) { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[36] ); - allowlaptop=1; + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[36] ); + allowlaptop=1; - ready_struct info; - info.client_num = CLIENT_NUM; - info.ready_stage=36; - info.status=1; + ready_struct info; + info.client_num = CLIENT_NUM; + info.ready_stage=36; + info.status=1; - if (RANDOM_MERCS) - HireRandomMercs(); + if (gRandomMercs) + HireRandomMercs(); - // server client is starting the game, adjust the games max players - // this will allow the game to be started, rather than saying 2/4 players are connected - // where there are only two players connected - int iPlayersConnected = 0; - for (int i=0; i< 4; i++) - if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) - iPlayersConnected++; + // server client is starting the game, adjust the games max players + // this will allow the game to be started, rather than saying 2/4 players are connected + // where there are only two players connected + int iPlayersConnected = 0; + for (int i=0; i< 4; i++) + if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) + iPlayersConnected++; - MAX_CLIENTS = iPlayersConnected; - - client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + cMaxClients = iPlayersConnected; + client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } } @@ -1861,13 +1609,11 @@ void StartBattleChatBoxClosedCallback(void) is_game_started = true; } - - void start_battle ( void ) { if(!is_client) { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[14] ); + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[14] ); } else if(!allowlaptop && is_server) { @@ -1881,7 +1627,6 @@ void start_battle ( void ) if (client_names[i] != NULL && strcmp(client_names[i],"") != 0) iPlayersConnected++; - if (iPlayersConnected <= 1) { numPlayersValid = FALSE; @@ -1897,7 +1642,7 @@ void start_battle ( void ) ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[63] ); } // WANNE - MP: If choosen team deathmatch, there must be at least 2 different teams - else if (PLAYER_BSIDE == MP_TYPE_TEAMDEATMATCH) + else if (cGameType == MP_TYPE_TEAMDEATMATCH) { bool areTeamsValid = FALSE; int clientTeam = client_teams[0]; @@ -1929,10 +1674,9 @@ void start_battle ( void ) } else if(allowlaptop) { - if ( NumberOfMercsOnPlayerTeam() ==0) { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[15] ); + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[15] ); } else if(goahead==1) { @@ -1963,9 +1707,9 @@ void start_battle ( void ) GROUP *pGroup; pGroup = GetGroup( ubGroupID ); gpBattleGroup = pGroup; - gubPBSectorX = gpBattleGroup->ubSectorX; - gubPBSectorY = gpBattleGroup->ubSectorY; - gubPBSectorZ = gpBattleGroup->ubSectorZ; + gubPBSectorX = gpBattleGroup->ubSectorX; + gubPBSectorY = gpBattleGroup->ubSectorY; + gubPBSectorZ = gpBattleGroup->ubSectorZ; gfEnterTacticalPlacementGUI = 1; // OJW - 20090205 @@ -2001,18 +1745,16 @@ void start_battle ( void ) SetCurrentWorldSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); is_game_started = true; } - } else { - send_ready(); + send_ready(); } } else if(!allowlaptop && is_client && !is_server) { ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[16] ); } - } void DropOffItemsInSector( UINT8 ubOrderNum ) @@ -2025,8 +1767,6 @@ void DropOffItemsInSector( UINT8 ubOrderNum ) UINT8 ubItemsDelivered, ubTempNumItems; UINT32 i; - - // determine if the sector is loaded if( ( gWorldSectorX == gsMercArriveSectorX ) && ( gWorldSectorY == gsMercArriveSectorY ) && ( gbWorldSectorZ == 0 ) ) fSectorLoaded = TRUE; @@ -2035,8 +1775,6 @@ void DropOffItemsInSector( UINT8 ubOrderNum ) SetSectorFlag( gsMercArriveSectorX, gsMercArriveSectorY, 0, SF_ALREADY_VISITED);//allows update of item count - - for(i=0; iusSoldierID < 120) { - //ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"send_stop" ); if(SStopMerc->usSoldierID < 20) { stop_struct.usSoldierID = (SStopMerc->usSoldierID)+ubID_prefix; @@ -2120,11 +1853,12 @@ void send_stop (EV_S_STOP_MERC *SStopMerc) // used to stop a merc when he spots stop_struct.sGridNo=SStopMerc->sGridNo; stop_struct.ubDirection=SStopMerc->ubDirection; stop_struct.fset=SStopMerc->fset; + if(stop_struct.fset==FALSE) { - //ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"skipped" ); return; } + stop_struct.sXPos=SStopMerc->sXPos; stop_struct.sYPos=SStopMerc->sYPos; client->RPC("sendSTOP",(const char*)&stop_struct, (int)sizeof(EV_S_STOP_MERC)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); @@ -2133,34 +1867,18 @@ void send_stop (EV_S_STOP_MERC *SStopMerc) // used to stop a merc when he spots void recieveSTOP (RPCParameters *rpcParameters) { - //ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"recieve_stop" ); - EV_S_STOP_MERC* SStopMerc =(EV_S_STOP_MERC*)rpcParameters->input; SOLDIERTYPE *pSoldier = MercPtrs[ SStopMerc->usSoldierID ]; - - //INT16 sCellX, sCellY; - //sCellX = CenterX( SStopMerc->sGridNo ); - //sCellY = CenterY( SStopMerc->sGridNo ); - pSoldier->EVENT_InternalSetSoldierPosition( SStopMerc->sXPos, SStopMerc->sYPos,FALSE, FALSE, FALSE ); - pSoldier->EVENT_SetSoldierDirection( SStopMerc->ubDirection ); - //pSoldier->HaultSoldierFromSighting(TRUE); - pSoldier->AdjustNoAPToFinishMove( SStopMerc->fset ); - //EVENT_StopMerc( pSoldier, SStopMerc->sGridNo, SStopMerc->bDirection ); - //pSoldier->AdjustNoAPToFinishMove( TRUE ); - - pSoldier->flags.bTurningFromPronePosition = FALSE; - - - + pSoldier->EVENT_SetSoldierDirection( SStopMerc->ubDirection ); + pSoldier->AdjustNoAPToFinishMove( SStopMerc->fset ); + pSoldier->flags.bTurningFromPronePosition = FALSE; } void send_interrupt (SOLDIERTYPE *pSoldier) { - - INT_STRUCT INT; INT.ubID = pSoldier->ubID; @@ -2169,7 +1887,6 @@ void send_interrupt (SOLDIERTYPE *pSoldier) INT.gubOutOfTurnPersons = gubOutOfTurnPersons; INT.Interrupted=gusSelectedSoldier+ubID_prefix; - if(INT.bTeam==0) { @@ -2177,21 +1894,18 @@ void send_interrupt (SOLDIERTYPE *pSoldier) INT.ubID=INT.ubID+ubID_prefix; } - for(int i=0; i <= INT.gubOutOfTurnPersons; i++) + for(int i=0; i <= INT.gubOutOfTurnPersons; i++) + { + if(INT.gubOutOfTurnOrder[i] < 20) { - if(INT.gubOutOfTurnOrder[i] < 20) - { - INT.gubOutOfTurnOrder[i]=INT.gubOutOfTurnOrder[i]+ubID_prefix; - } + INT.gubOutOfTurnOrder[i]=INT.gubOutOfTurnOrder[i]+ubID_prefix; } + } - //if(gubOutOfTurnPersons>0)ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Sent Int: bTeam-%d ubID-%d", INT.bTeam,INT.ubID ); - - if(INT.bTeam !=netbTeam) gTacticalStatus.ubCurrentTeam=INT.bTeam; + if(INT.bTeam !=netbTeam) + gTacticalStatus.ubCurrentTeam=INT.bTeam; client->RPC("sendINTERRUPT",(const char*)&INT, (int)sizeof(INT_STRUCT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - - } // WANNE - MP: Here we have to add AddTopMessage() on the clients @@ -2200,7 +1914,7 @@ void recieveINTERRUPT (RPCParameters *rpcParameters) INT_STRUCT* INT = (INT_STRUCT*)rpcParameters->input; SOLDIERTYPE* pOpponent = MercPtrs[ INT->Interrupted]; - if(INT->bTeam==netbTeam)// ||pOpponent->bTeam==1 )//for us or AI + if(INT->bTeam==netbTeam)//for us or AI { INT->bTeam=0; INT->ubID=INT->ubID - ubID_prefix; @@ -2231,32 +1945,25 @@ void recieveINTERRUPT (RPCParameters *rpcParameters) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[17] ); //stop moving merc who was interrupted and init UI bar - SOLDIERTYPE* pMerc = MercPtrs[ INT->ubID ]; - //AdjustNoAPToFinishMove( pMerc, TRUE ); + SOLDIERTYPE* pMerc = MercPtrs[ INT->ubID ]; pMerc->HaultSoldierFromSighting(TRUE); - //pMerc->fTurningFromPronePosition = FALSE;// hmmm ?? FreezeInterfaceForEnemyTurn(); InitEnemyUIBar( 0, 0 ); fInterfacePanelDirty = DIRTYLEVEL2; - - //if (is_server) - // AddTopMessage( COMPUTER_TURN_MESSAGE, TeamTurnString[ INT->bTeam ] ); gTacticalStatus.fInterruptOccurred = TRUE; - } else { //it for us ! :) if(INT->gubOutOfTurnPersons==0)//indicates finished interrupt maybe can just call end interrupt { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"old int finish" ); + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"old int finish" ); } else //start our interrupt turn { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[37] ); SOLDIERTYPE* pSoldier = MercPtrs[ INT->ubID ]; - //SOLDIERTYPE* pOpponent = MercPtrs[ INT->Interrupted]; ManSeesMan(pSoldier,pOpponent,pOpponent->sGridNo,pOpponent->pathing.bLevel,2,1); StartInterrupt(); } @@ -2264,29 +1971,17 @@ void recieveINTERRUPT (RPCParameters *rpcParameters) } void intAI (SOLDIERTYPE *pSoldier ) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[17] ); - //stop moving merc who was interrupted and init UI bar - //SOLDIERTYPE* pMerc = MercPtrs[ INT->ubID ]; - ////AdjustNoAPToFinishMove( pMerc, TRUE ); - //pMerc->HaultSoldierFromSighting(TRUE); - //pMerc->fTurningFromPronePosition = FALSE;// hmmm ?? - //FreezeInterfaceForEnemyTurn(); - //InitEnemyUIBar( 0, 0 ); - //fInterfacePanelDirty = DIRTYLEVEL2; - AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, TeamTurnString[ pSoldier->bTeam ] ); - gTacticalStatus.fInterruptOccurred = TRUE; - - } +{ + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[17] ); + AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, TeamTurnString[ pSoldier->bTeam ] ); + gTacticalStatus.fInterruptOccurred = TRUE; +} + void end_interrupt ( BOOLEAN fMarkInterruptOccurred ) { - - SOLDIERTYPE * pSoldier = MercPtrs[(gubOutOfTurnOrder[gubOutOfTurnPersons])]; - INT_STRUCT INT; - INT.ubID = pSoldier->ubID; INT.bTeam = pSoldier->bTeam; memcpy(INT.gubOutOfTurnOrder, gubOutOfTurnOrder, sizeof(UINT8) * MAXMERCS); @@ -2300,52 +1995,45 @@ void end_interrupt ( BOOLEAN fMarkInterruptOccurred ) INT.ubID=INT.ubID+ubID_prefix; } - for(int i=0; i <= INT.gubOutOfTurnPersons; i++) + for(int i=0; i <= INT.gubOutOfTurnPersons; i++) + { + if(INT.gubOutOfTurnOrder[i] < 20) { - if(INT.gubOutOfTurnOrder[i] < 20) - { - INT.gubOutOfTurnOrder[i]=INT.gubOutOfTurnOrder[i]+ubID_prefix; - } + INT.gubOutOfTurnOrder[i]=INT.gubOutOfTurnOrder[i]+ubID_prefix; } + } - - client->RPC("endINTERRUPT",(const char*)&INT, (int)sizeof(INT_STRUCT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - - } void resume_turn(RPCParameters *rpcParameters) { INT_STRUCT* INT = (INT_STRUCT*)rpcParameters->input; - if(is_server)Sawarded=false; + + if(is_server) + Sawarded=false; if(INT->bTeam==netbTeam || (INT->bTeam==1 && is_server))//may need working { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[18] ); for(int i=0; i <= INT->gubOutOfTurnPersons; i++) + { + if((INT->gubOutOfTurnOrder[i] >= ubID_prefix) && (INT->gubOutOfTurnOrder[i] < (ubID_prefix+6))) { - if((INT->gubOutOfTurnOrder[i] >= ubID_prefix) && (INT->gubOutOfTurnOrder[i] < (ubID_prefix+6))) - { - INT->gubOutOfTurnOrder[i]=INT->gubOutOfTurnOrder[i]-ubID_prefix; - } + INT->gubOutOfTurnOrder[i]=INT->gubOutOfTurnOrder[i]-ubID_prefix; } + } memcpy(gubOutOfTurnOrder,INT->gubOutOfTurnOrder, sizeof(UINT8) * MAXMERCS); gubOutOfTurnPersons = INT->gubOutOfTurnPersons; - - - EndInterrupt( INT->fMarkInterruptOccurred ); } + // WANNE - MP: This happens, when client 1 (=server) has done its interrupt and now it is enemies turn! else if(INT->bTeam==1) { - // WANNE - MP: This happens, when client 1 (=server) has done its interrupt and now it is enemies turn! - // WANNE - MP: Removed the AddTopMessage() again ... - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"im not server but ai just got back its turn after being interrupted..." ); + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"im not server but ai just got back its turn after being interrupted..." ); AddTopMessage( COMPUTER_TURN_MESSAGE, TeamTurnString[ 1 ] ); - //maybe can add something. } } @@ -2362,108 +2050,48 @@ void grid_display ( void ) //print mouse coordinates, helpfull for crate placeme ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[21], usMapPos ); } -// WANNE: No more needed -void mp_help(void) -{ - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, L" "); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[2]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[3]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, L" "); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[4]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[5]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[6]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[7]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[8]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[9]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[10]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, L" "); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[11]); -} - -// WANNE: No more needed -void mp_help2(void) -{ - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, L" "); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[12]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, L" "); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[13]); - - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[14]); - - - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[15]); - - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, L" "); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[16]); - ScreenMsg( MSG_FONT_WHITE, MSG_MPSYSTEM, MPHelp[11]); - -} - -void manual_overide (void)//now bound to "7" -{ - if(is_server) - { - //manual overide command for server - const STR16 msg = MPClientMessage[23]; - - SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; - DoMessageBox( MSG_BOX_BASIC_STYLE, msg, guiCurrentScreen, MSG_BOX_FLAG_FOUR_NUMBERED_BUTTONS | MSG_BOX_FLAG_USE_CENTERING_RECT, overide_callback, &CenterRect ); - - } - else ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[22] ); - -} - void overide_callback( UINT8 ubResult ) { if(is_server) { - if(ubResult==1) - { - allowlaptop=true; - } - if(ubResult==2)//overide stop #1 (awaiting client ready for launch/load) - - - { - goahead=0; - status=0;//reset - numready=0; - SOLDIERTYPE *pSoldier = MercPtrs[ 0 ]; - UINT8 ubGroupID = pSoldier->ubGroupID; + if(ubResult==1) + { + allowlaptop=true; + } - GROUP *pGroup; - pGroup = GetGroup( ubGroupID ); - gpBattleGroup = pGroup; - gubPBSectorX = gpBattleGroup->ubSectorX; - gubPBSectorY = gpBattleGroup->ubSectorY; - gubPBSectorZ = gpBattleGroup->ubSectorZ; + if(ubResult==2)//overide stop #1 (awaiting client ready for launch/load) + { + goahead=0; + status=0;//reset + numready=0; + SOLDIERTYPE *pSoldier = MercPtrs[ 0 ]; + UINT8 ubGroupID = pSoldier->ubGroupID; - gfEnterTacticalPlacementGUI = 1; - - + GROUP *pGroup; + pGroup = GetGroup( ubGroupID ); + gpBattleGroup = pGroup; + gubPBSectorX = gpBattleGroup->ubSectorX; + gubPBSectorY = gpBattleGroup->ubSectorY; + gubPBSectorZ = gpBattleGroup->ubSectorZ; - goahead=1; - readystage=1; - ready_struct info; //send - info.client_num = CLIENT_NUM; - info.ready_stage = 1; - info.status = 1; - + gfEnterTacticalPlacementGUI = 1; + goahead=1; + readystage=1; + ready_struct info; //send + info.client_num = CLIENT_NUM; + info.ready_stage = 1; + info.status = 1; - - - client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - - status=0;//reset - numready=0; - - SetCurrentWorldSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); //load - } - - - if(ubResult==3) - { + client->RPC("sendREADY",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + + status=0;//reset + numready=0; + + SetCurrentWorldSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); //load + } + + if(ubResult==3) + { lockui(1);//unlock ui paused while wainting for loaders ready_struct info; @@ -2473,33 +2101,28 @@ void overide_callback( UINT8 ubResult ) info.ready_stage = 2;//done placing mercs info.status=1; client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - - } - if(ubResult==4) //overide waiting on merc placement - { - numready=0; + } - ready_struct info; //send - info.client_num = CLIENT_NUM; - info.ready_stage = 4;//all done placing mercs, kill all - info.status=1; - gMsgBox.bHandled = MSG_BOX_RETURN_OK; - status=0; - KillTacticalPlacementGUI(); //kill - ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[13]); + if(ubResult==4) //overide waiting on merc placement + { + numready=0; - client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - - } - + ready_struct info; //send + info.client_num = CLIENT_NUM; + info.ready_stage = 4;//all done placing mercs, kill all + info.status=1; + gMsgBox.bHandled = MSG_BOX_RETURN_OK; + status=0; + KillTacticalPlacementGUI(); //kill + ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[13]); + client->RPC("sendGUI",(const char*)&info, (int)sizeof(ready_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + } + goahead = 0; numready = 0; readystage = 0; status = 0; - - - } } @@ -2544,32 +2167,25 @@ void requestSETID(RPCParameters *rpcParameters) if (!fClientReceivedAllFiles) { serverAddr = rpcParameters->sender; - + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; DoMessageBox( MSG_BOX_BASIC_STYLE , MPClientMessage[64] , guiCurrentScreen, MSG_BOX_FLAG_YESNO | MSG_BOX_FLAG_USE_CENTERING_RECT, allowDownloadCallback, &CenteringRect ); - } } } } - - void requestSETTINGS(void) { client_info cl_name; - //cl_name.client_num=CLIENT_NUM; - strcpy(cl_name.client_name , CLIENT_NAME); - cl_name.team=TEAM; - - cl_name.cl_edge=atoi(SECT_EDGE); + strcpy(cl_name.client_name , cClientName); + cl_name.team = TEAM; + cl_name.cl_edge = cStartingSectorEdge; // OJW - 20090507 // send client version to server strcpy(cl_name.client_version,MPVERSION); - client->RPC("requestSETTINGS",(const char*)&cl_name, (int)sizeof(client_info)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } // OJW: FILE TRANSFER: Clients get notified of other clients transfer progress @@ -2592,47 +2208,13 @@ void recieveDOWNLOADSTATUS(RPCParameters *rpcParameters) fDrawCharacterList = true; } - // WANNE: FILE TRANSFER: Get executable Directory from Server. This is used to get corret file location on client side void recieveFILE_TRANSFER_SETTINGS (RPCParameters *rpcParameters) { if (!is_server && recieved_transfer_settings == 0) { filetransfersettings_struct* fts = (filetransfersettings_struct*)rpcParameters->input; -#ifndef USE_VFS - // OJW - 20090405 - gCurrentTransferBytes = 0; - gTotalTransferBytes = fts->totalTransferBytes; - // Now get directory - strcpy( server_fileTransferDirectoryPath, fts->fileTransferDirectory ); - - // Convert string to lowercase. This is needed, because the file path we received (see OnFile()) from list transfer is also lowercase - for (INT32 i = 0; server_fileTransferDirectoryPath[i]; ++i) - { - server_fileTransferDirectoryPath[i] = tolower(server_fileTransferDirectoryPath[i]); - putchar(server_fileTransferDirectoryPath[i]); - } - - recieved_transfer_settings = 1; - serverSyncClientsDirectory = fts->syncClientsDirectory; - - // We sync our MP game dir from the server - if (fts->syncClientsDirectory == 1) - { - strcat(client_fileTransferDirectoryPath, "\\"); - strcat(client_fileTransferDirectoryPath, fts->serverName); - - // Replace "/" with "\" - char* client_correctFileTransferDirectoryPath = ReplaceCharactersInString_Client(client_fileTransferDirectoryPath, "/", "\\"); - - strcpy(client_fileTransferDirectoryPath, client_correctFileTransferDirectoryPath); - - // Delete the clients mp directory. It will be recreated later when we receive the files from the server - if (DirectoryExists(client_fileTransferDirectoryPath)) - RemoveFileManDirectory(client_fileTransferDirectoryPath, true); - } -#else gCurrentTransferBytes = 0; gTotalTransferBytes = fts->totalTransferBytes; @@ -2641,36 +2223,9 @@ void recieveFILE_TRANSFER_SETTINGS (RPCParameters *rpcParameters) vfs::Path profileRoot = vfs::Path(gzFileTransferDirectory) + vfs::Path(server_fileTransferDirectoryPath); ///////////////////////////////////////////////////////////////////// - vfs::CProfileStack *PS = getVFS()->getProfileStack(); - - // remove Multiplayer profile if it exists - vfs::CVirtualProfile *pProf = PS->getProfile("_MULTIPLAYER"); - if( pProf && (pProf == PS->topProfile()) ) - { - THROWIFFALSE(PS->popProfile(), L"Could not remove old \"_MULTIPLAYER\" profile"); - // careful, pProf is not valid anymore - } - // create and initialize a new Multiplayer profile - pProf = new vfs::CVirtualProfile("_MULTIPLAYER",true); - PS->pushProfile(pProf); - if(!initWriteProfile(*pProf,profileRoot)) - { - // OK, directory did not exist, probably a new server - if(!os::createRealDirectory(profileRoot)) - { - THROWIFFALSE(PS->popProfile(), L"Could not remove \"_MULTIPLAYER\" profile"); - THROWEXCEPTION(L"could not create client directory"); - } - // OK, try again - if(!initWriteProfile(*pProf,profileRoot)) - { - THROWIFFALSE(PS->popProfile(), L"Could not remove \"_MULTIPLAYER\" profile"); - THROWEXCEPTION(L"Could not initialize client profile"); - } - } + SGP_TRYCATCH_RETHROW( ja2::mp::InitializeMultiplayerProfile(profileRoot), L"" ); ///////////////////////////////////////////////////////////////////// - recieved_transfer_settings = 1; serverSyncClientsDirectory = fts->syncClientsDirectory; @@ -2679,7 +2234,6 @@ void recieveFILE_TRANSFER_SETTINGS (RPCParameters *rpcParameters) { // profile is setup, nothing to do here } -#endif } } @@ -2689,209 +2243,231 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve settings_struct* cl_lan = (settings_struct*)rpcParameters->input; - char szDefault[30]; - sprintf(szDefault, "%s",cl_lan->client_name); + char szDefault[30]; + sprintf(szDefault, "%s",cl_lan->client_name); + + // OJW - 20081204 + // get complete client data from the server + memcpy( client_edges, cl_lan->client_edges , sizeof(int) * 5); + memcpy( client_teams, cl_lan->client_teams , sizeof(int) * 4); + + if(!recieved_settings && strcmp(cl_lan->client_name, cClientName)==0) + { + // This settings packet contains information and settings specifically for us + recieved_settings=1; + + // save the settings so if we need to re-apply them after a reinitialisation ( after file transfer ) we can + memcpy ( &gMPServerSettings , cl_lan , sizeof(settings_struct) ); + + CLIENT_NUM=cl_lan->client_num;//assign client number from server + + netbTeam = (CLIENT_NUM)+5; + ubID_prefix = gTacticalStatus.Team[ netbTeam ].bFirstID;//over here now + + memcpy( client_names , cl_lan->client_names, sizeof( char ) * 4 * 30 ); + + strcpy(client_names[cl_lan->client_num-1],szDefault); // OJW - 20081204 - // get complete client data from the server - memcpy( client_edges, cl_lan->client_edges , sizeof(int) * 5); - memcpy( client_teams, cl_lan->client_teams , sizeof(int) * 4); + strcpy(cServerName,cl_lan->server_name); + gRandomMercs = cl_lan->randomMercs; + gRandomStartingEdge = cl_lan->randomStartingEdge; - if(!recieved_settings && strcmp(cl_lan->client_name, CLIENT_NAME)==0) + cStartingSectorEdge = cl_lan->startingSectorEdge; + + if(gRandomMercs) { - // This settings packet contains information and settings specifically for us - recieved_settings=1; + // copy the random merc list locally + memcpy(random_mercs,cl_lan->random_mercs,sizeof(int) * 7); + } - // save the settings so if we need to re-apply them after a reinitialisation ( after file transfer ) we can - memcpy ( &gMPServerSettings , cl_lan , sizeof(settings_struct) ); - - CLIENT_NUM=cl_lan->client_num;//assign client number from server - - netbTeam = (CLIENT_NUM)+5; - ubID_prefix = gTacticalStatus.Team[ netbTeam ].bFirstID;//over here now - - memcpy( client_names , cl_lan->client_names, sizeof( char ) * 4 * 30 ); - - strcpy(client_names[cl_lan->client_num-1],szDefault); - - // OJW - 20081204 - strcpy(SERVER_NAME,cl_lan->server_name); - RANDOM_MERCS = cl_lan->RANDOM_MERCS; - RANDOM_SPAWN = cl_lan->RANDOM_SPAWN; - - // Set the starting edge - _itoa(cl_lan->cl_edge,SECT_EDGE,10); - - if(RANDOM_MERCS) - { - // copy the random merc list locally - memcpy(random_mercs,cl_lan->random_mercs,sizeof(int) * 7); - } - - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[2] ); - - - MAX_CLIENTS=cl_lan->max_clients; - memcpy( ckbag, cl_lan->kitbag, sizeof(char)*100); - - int cnt; - int numnum = 0; - int kitnum = 0; - char tempstring[4]; - memset( &kit, 0, sizeof( int )*20 ); + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[2] ); - for(cnt=0; cnt < 100; cnt++) - { - char tempc = ckbag[cnt]; - - if( _strnicmp(&tempc, "[",1) == 0) - { - - continue; - } - - else if( _strnicmp(&tempc, ",",1) == 0) - { - numnum=0; - kit[kitnum]=atoi(tempstring); - - memset( &tempstring, 0, sizeof( char )*4 ); - - kitnum++; - continue; - } - - else if( _strnicmp(&tempc, "]",1) == 0) - { - kit[kitnum]=atoi(tempstring); - break; - } - else - { - strncpy(&tempstring[numnum],&tempc,1); - numnum++; - //temp = atoi(tempstring); - } - } - - - DAMAGE_MULTIPLIER=cl_lan->damage_multiplier; - SAME_MERC=cl_lan->same_merc; - - - gsMercArriveSectorX=cl_lan->gsMercArriveSectorX; - gsMercArriveSectorY=cl_lan->gsMercArriveSectorY; - - // WANNE - BMP: We have to initialize the map size here!! - InitializeWorldSize(gsMercArriveSectorX, gsMercArriveSectorY, 0); - - PLAYER_BSIDE=cl_lan->gsPLAYER_BSIDE; - DISABLE_MORALE=cl_lan->emorale; - ChangeSelectedMapSector( gsMercArriveSectorX, gsMercArriveSectorY, 0 ); - CHAR16 str[128]; - GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, str, TRUE ); + cMaxClients=cl_lan->maxClients; + memcpy( cKitBag, cl_lan->kitBag, sizeof(char)*100); - // WANNE - MP: If time set to 0, then no time turns - INT32 secs_per_tick; - if (cl_lan->secs_per_tick == 0) + int cnt; + int numnum = 0; + int kitnum = 0; + char tempstring[4]; + memset( &kit, 0, sizeof( int )*20 ); + + for(cnt=0; cnt < 100; cnt++) + { + char tempc = cKitBag[cnt]; + + if( _strnicmp(&tempc, "[",1) == 0) { - gGameOptions.fTurnTimeLimit=FALSE; - secs_per_tick=1; + + continue; + } + + else if( _strnicmp(&tempc, ",",1) == 0) + { + numnum=0; + + kit[kitnum]=atoi(tempstring); + + memset( &tempstring, 0, sizeof( char )*4 ); + + kitnum++; + continue; + } + + else if( _strnicmp(&tempc, "]",1) == 0) + { + kit[kitnum]=atoi(tempstring); + break; } else { - gGameOptions.fTurnTimeLimit=cl_lan->sofTurnTimeLimit; - secs_per_tick=cl_lan->secs_per_tick; + strncpy(&tempstring[numnum],&tempc,1); + numnum++; } - - - PLAYER_TEAM_TIMER_SEC_PER_TICKS=secs_per_tick; + } - INT32 clstarting_balance=cl_lan->starting_balance;//set starting balance + cDamageMultiplier=cl_lan->damageMultiplier; + cSameMercAllowed=cl_lan->sameMercAllowed; + + gsMercArriveSectorX=cl_lan->gsMercArriveSectorX; + gsMercArriveSectorY=cl_lan->gsMercArriveSectorY; - if(LaptopSaveInfo.iCurrentBalancegameType; + cDisableMorale=cl_lan->disableMorale; + ChangeSelectedMapSector( gsMercArriveSectorX, gsMercArriveSectorY, 0 ); + CHAR16 str[128]; + GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, str, TRUE ); + + // WANNE - MP: If time set to 0, then no time turns + INT32 secs_per_tick; + if (cl_lan->secondsPerTick == 0) + { + gGameOptions.fTurnTimeLimit=FALSE; + secs_per_tick=1; + } + else + { + gGameOptions.fTurnTimeLimit=cl_lan->sofTurnTimeLimit; + secs_per_tick=cl_lan->secondsPerTick; + } + + PLAYER_TEAM_TIMER_SEC_PER_TICKS=secs_per_tick; + + INT32 clstarting_balance=cl_lan->startingCash;//set starting balance + + if(LaptopSaveInfo.iCurrentBalancesofGunNut; - gGameOptions.ubGameStyle=cl_lan->soubGameStyle; - gGameOptions.ubDifficultyLevel=cl_lan->soubDifficultyLevel; - - gGameOptions.fIronManMode=cl_lan->sofIronManMode; - gGameOptions.ubBobbyRay=cl_lan->soubBobbyRay; + gGameOptions.fGunNut=cl_lan->sofGunNut; + gGameOptions.ubGameStyle=cl_lan->soubGameStyle; + gGameOptions.ubDifficultyLevel=cl_lan->soubDifficultyLevel; + gGameOptions.fNewTraitSystem = cl_lan->soubSkillTraits; + gGameOptions.fIronManMode=cl_lan->sofIronManMode; + gGameOptions.ubBobbyRay=cl_lan->soubBobbyRay; - - // Set Bobby Ray "Under Construction"? - if(!cl_lan->soDis_Bobby) - { - SetBookMark( BOBBYR_BOOKMARK ); - LaptopSaveInfo.fBobbyRSiteCanBeAccessed = TRUE; - } + // Set Bobby Ray "Under Construction"? + if(!cl_lan->disableBobbyRay) + { + SetBookMark( BOBBYR_BOOKMARK ); + LaptopSaveInfo.fBobbyRSiteCanBeAccessed = TRUE; + } - // Enable "AIM" and "MERC" only if random merc is false! - if (!cl_lan->RANDOM_MERCS) - { - SetBookMark( AIM_BOOKMARK ); - SetBookMark( MERC_BOOKMARK ); - } + // Enable "AIM" and "MERC" only if random merc is false! + if (!cl_lan->randomMercs) + { + SetBookMark( AIM_BOOKMARK ); + SetBookMark( MERC_BOOKMARK ); + } - if(!cl_lan->soDis_Equip) - ALLOW_EQUIP=TRUE; + if(!cl_lan->disableMercEquipment) + cAllowMercEquipment = 1; - MAX_MERCS=cl_lan->gsMAX_MERCS; - TESTING=cl_lan->TESTING; - REPORT_NAME=cl_lan->gsREPORT_NAME; + cMaxMercs = cl_lan->maxMercs; + cReportHiredMerc = cl_lan->reportHiredMerc; - ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, MPClientMessage[24],str,MAX_CLIENTS,MAX_MERCS,PLAYER_BSIDE,SAME_MERC,DAMAGE_MULTIPLIER,gGameOptions.fTurnTimeLimit,secs_per_tick,cl_lan->soDis_Bobby,cl_lan->soDis_Equip,DISABLE_MORALE,TESTING); - if(TESTING) ScreenMsg( FONT_WHITE, MSG_MPSYSTEM, MPClientMessage[25] ); + // WANNE: Removed + /* + ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, MPClientMessage[24],str,cMaxClients,cMaxMercs,cGameType,cSameMercAllowed,cDamageMultiplier,gGameOptions.fTurnTimeLimit,secs_per_tick,cl_lan->disableBobbyRay,cl_lan->disableMercEquipment,cDisableMorale,0); + */ + + // WANNE - MP: I just added the NUM_SEC_IN_DAY so the game starts at Day 1 instead of Day 0 + gGameExternalOptions.iGameStartingTime= NUM_SEC_IN_DAY + int(cl_lan->startingTime*3600); + // WANNE - MP: In mulitplayer the hired merc arrive immediatly, so iFirstArrivalDelay must be set to 0 + // This also fixed the bug of the wrong hired hours! + gGameExternalOptions.iFirstArrivalDelay = 0; + + // Disable Reinforcements + gGameExternalOptions.gfAllowReinforcements = false; + gGameExternalOptions.gfAllowReinforcementsOnlyInCity = false; + + // Disable Real-Time Mode + // SANDRO - huh? real-time sneak is in preferences + //gGameExternalOptions.fAllowRealTimeSneak = false; - // WANNE - MP: I just added the NUM_SEC_IN_DAY so the game starts at Day 1 instead of Day 0 - gGameExternalOptions.iGameStartingTime= NUM_SEC_IN_DAY + int(cl_lan->TIME*3600); - // WANNE - MP: In mulitplayer the hired merc arrive immediatly, so iFirstArrivalDelay must be set to 0 - // This also fixed the bug of the wrong hired hours! - gGameExternalOptions.iFirstArrivalDelay = 0; + gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] = false; + gGameExternalOptions.fQuietRealTimeSneak = false; - // Disable Reinforcements - gGameExternalOptions.gfAllowReinforcements = false; - gGameExternalOptions.gfAllowReinforcementsOnlyInCity = false; + // WANNE: fix HOT DAY in night at arrival by night. + // Explanation: If game starting time + first arrival delay < 07:00 (111600) -> we arrive before the sun rises or + // if game starting time + first arrival delay >= 21:00 (162000) -> we arrive after the sun goes down + if( (gGameExternalOptions.iGameStartingTime + gGameExternalOptions. iFirstArrivalDelay) < 111600 || + (gGameExternalOptions.iGameStartingTime + gGameExternalOptions.iFirstArrivalDelay >= 162000)) + { + // Default: Night + gubEnvLightValue = 12; + } + else + { + // Default: Day + gubEnvLightValue = 3; + } - // Disable Real-Time Mode - gGameExternalOptions.fAllowRealTimeSneak = false; - gGameExternalOptions.fQuietRealTimeSneak = false; + LightSetBaseLevel(gubEnvLightValue); - // WANNE: fix HOT DAY in night at arrival by night. - // Explanation: If game starting time + first arrival delay < 07:00 (111600) -> we arrive before the sun rises or - // if game starting time + first arrival delay >= 21:00 (162000) -> we arrive after the sun goes down - if( (gGameExternalOptions.iGameStartingTime + gGameExternalOptions. iFirstArrivalDelay) < 111600 || - (gGameExternalOptions.iGameStartingTime + gGameExternalOptions.iFirstArrivalDelay >= 162000)) - { - // Default: Night - gubEnvLightValue = 12; - } - else - { - // Default: Day - gubEnvLightValue = 3; - } - - LightSetBaseLevel(gubEnvLightValue); - - InitNewGameClock( ); - - WEAPON_READIED_BONUS=cl_lan->WEAPON_READIED_BONUS; - DISABLE_SPEC_MODE=cl_lan->DISABLE_SPEC_MODE; - - // We have to take the selected inventory mode from the server - gGameOptions.ubInventorySystem=cl_lan->sofNewInv; + InitNewGameClock( ); + + cWeaponReadyBonus = cl_lan->weaponReadyBonus; + cDisableSpectatorMode = cl_lan->disableSpectatorMode; + + // ----------------- + // RW: Inventory + switch (cl_lan->inventoryAttachment) + { + case 0: // Old/Old + gGameOptions.ubInventorySystem = INVENTORY_OLD; + gGameOptions.ubAttachmentSystem = ATTACHMENT_OLD; + break; + case 1: // New/Old + gGameOptions.ubInventorySystem = INVENTORY_NEW; + gGameOptions.ubAttachmentSystem = ATTACHMENT_OLD; + break; + case 2: // New/New + gGameOptions.ubInventorySystem = INVENTORY_NEW; + gGameOptions.ubAttachmentSystem = ATTACHMENT_NEW; + break; + } + // Server forces us to play with new Inventory, but NIV is not allowed on the client, + // because of wrong resolution or other stuff + if ( UsingNewInventorySystem() == true && !IsNIVModeValid(true) ) + { + SGPRect CenteringRect= {0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 }; + DoMessageBox( MSG_BOX_BASIC_STYLE , MPClientMessage[69] , guiCurrentScreen, MSG_BOX_FLAG_OK | MSG_BOX_FLAG_USE_CENTERING_RECT, InvalidClientSettingsOkBoxCallback, &CenteringRect ); + } + else + { // WANNE - MP: We have to re-initialize the correct interface - if((UsingNewInventorySystem() == true) && IsNIVModeValid(true)) + if((UsingNewInventorySystem() == true)) { InitNewInventorySystem(); InitializeSMPanelCoordsNew(); @@ -2917,17 +2493,17 @@ void recieveSETTINGS (RPCParameters *rpcParameters) //recive settings from serve // OJW - 20091024 - extract random table if (!is_server) - memcpy(guiPreRandomNums,cl_lan->random_table,sizeof(UINT32)*MAX_PREGENERATED_NUMS); + memcpy(guiPreRandomNums,cl_lan->random_table,sizeof(UINT32)*MAX_PREGENERATED_NUMS); } - else - { - fDrawCharacterList = true; // set the character list to be redrawn + } + else + { + fDrawCharacterList = true; // set the character list to be redrawn - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[26],cl_lan->client_num,szDefault ); - - strcpy(client_names[cl_lan->client_num-1],szDefault); - - } + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[26],cl_lan->client_num,szDefault ); + + strcpy(client_names[cl_lan->client_num-1],szDefault); + } } void reapplySETTINGS() @@ -2961,15 +2537,15 @@ void reapplySETTINGS() gsMercArriveSectorX=gMPServerSettings.gsMercArriveSectorX; gsMercArriveSectorY=gMPServerSettings.gsMercArriveSectorY; - PLAYER_BSIDE=gMPServerSettings.gsPLAYER_BSIDE; - DISABLE_MORALE=gMPServerSettings.emorale; + cGameType=gMPServerSettings.gameType; + cDisableMorale=gMPServerSettings.disableMorale; ChangeSelectedMapSector( gsMercArriveSectorX, gsMercArriveSectorY, 0 ); CHAR16 str[128]; GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, str, TRUE ); // WANNE - MP: If time set to 0, then no time turns INT32 secs_per_tick; - if (gMPServerSettings.secs_per_tick == 0) + if (gMPServerSettings.secondsPerTick == 0) { gGameOptions.fTurnTimeLimit=FALSE; secs_per_tick=1; @@ -2977,53 +2553,52 @@ void reapplySETTINGS() else { gGameOptions.fTurnTimeLimit=gMPServerSettings.sofTurnTimeLimit; - secs_per_tick=gMPServerSettings.secs_per_tick; + secs_per_tick=gMPServerSettings.secondsPerTick; } - PLAYER_TEAM_TIMER_SEC_PER_TICKS=secs_per_tick; - INT32 clstarting_balance=gMPServerSettings.starting_balance;//set starting balance + INT32 clstarting_balance=gMPServerSettings.startingCash;//set starting balance if(LaptopSaveInfo.iCurrentBalanceclient_num == CLIENT_NUM) { // store the setting locally - _itoa(cl_lan->newedge,SECT_EDGE,10); + cStartingSectorEdge = cl_lan->newedge; } } } - void recieveMAPCHANGE( RPCParameters *rpcParameters ) { mapchange_struct* cl_lan = (mapchange_struct*)rpcParameters->input; @@ -3149,7 +2740,7 @@ void recieveMAPCHANGE( RPCParameters *rpcParameters ) // WANNE - BMP: InitializeWorldSize( gsMercArriveSectorX, gsMercArriveSectorY, 0 ); - gGameExternalOptions.iGameStartingTime= NUM_SEC_IN_DAY + int(cl_lan->TIME*3600); + gGameExternalOptions.iGameStartingTime= NUM_SEC_IN_DAY + int(cl_lan->startingTime*3600); CHAR16 str[128]; GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, str, TRUE ); @@ -3290,7 +2881,6 @@ void recieveGRENADERESULT (RPCParameters *rpcParameters) SOLDIERTYPE* pThrower = MercPtrs[ gres->ubOwnerID ]; if (pThrower != NULL) { - // grenade wasnt thrown by one of our guys, so we should do it on the client if (!IsOurSoldier(pThrower) && (pThrower->bTeam != 1 || !is_server)) { @@ -3659,7 +3249,7 @@ void recieveDISARMEXPLOSIVE (RPCParameters *rpcParameters) SOLDIERTYPE * pBombOwner = MercPtrs[gWorldItems[ gWorldBombs[ uiCount ].iItemIndex ].soldierID]; if (pBombOwner != NULL) { - ScreenMsg( FONT_LTBLUE , MSG_MPSYSTEM , L"%s's bomb was disarmed by %s", pBombOwner->name, pSoldier->name); + ScreenMsg( FONT_LTBLUE , MSG_MPSYSTEM , MPClientMessage[71], pBombOwner->name, pSoldier->name); } } @@ -3755,7 +3345,6 @@ void recieveSPREADEFFECT (RPCParameters *rpcParameters) { SpreadEffect( sef->sGridNo , sef->ubRadius , sef->usItem , sef->ubOwner , sef->fSubsequent , sef->bLevel , sef->iSmokeEffectID , TRUE); } - } } else @@ -3958,15 +3547,17 @@ void recieveBULLET(RPCParameters *rpcParameters) if (iBullet == -1) { - ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Failed to create bullet"); - } -//add bullet to bullet table for translation +#ifdef BETAVERSION + ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Failed to create bullet"); +#endif + + } + + //add bullet to bullet table for translation bTable[bTeam][net_iBullet].remote_id = net_iBullet; bTable[bTeam][net_iBullet].local_id = iBullet; - - pBullet = GetBulletPtr( iBullet ); //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"Created Bullet Id: %d",iBullet); @@ -3990,7 +3581,6 @@ void recieveBULLET(RPCParameters *rpcParameters) pBullet->iDistanceLimit=netb->net_bullet.iDistanceLimit; FireBullet( pFirer, pBullet, FALSE ); - } void send_changestate (EV_S_CHANGESTATE * SChangeState) @@ -3999,14 +3589,10 @@ void send_changestate (EV_S_CHANGESTATE * SChangeState) memcpy( &new_state , SChangeState, sizeof( EV_S_CHANGESTATE )); - if(new_state.usSoldierID < 20)new_state.usSoldierID = new_state.usSoldierID+ubID_prefix; + if(new_state.usSoldierID < 20) + new_state.usSoldierID = new_state.usSoldierID+ubID_prefix; - - client->RPC("sendSTATE",(const char*)&new_state, (int)sizeof(EV_S_CHANGESTATE)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"sent state"); - - } void recieveSTATE(RPCParameters *rpcParameters) @@ -4015,26 +3601,26 @@ void recieveSTATE(RPCParameters *rpcParameters) SOLDIERTYPE * pSoldier=MercPtrs[ new_state->usSoldierID ]; - if(pSoldier->bActive) + if(pSoldier->bActive) + { + // Start first AID + if(new_state->usNewState==START_AID) { - // Start first AID - if(new_state->usNewState==START_AID) - { - pSoldier->EVENT_InternalSetSoldierPosition( new_state->sXPos, new_state->sYPos ,FALSE, FALSE, FALSE ); - pSoldier->ChangeSoldierStance( ANIM_CROUCH ); - pSoldier->EVENT_SetSoldierDirection( new_state->usNewDirection ); + pSoldier->EVENT_InternalSetSoldierPosition( new_state->sXPos, new_state->sYPos ,FALSE, FALSE, FALSE ); + pSoldier->ChangeSoldierStance( ANIM_CROUCH ); + pSoldier->EVENT_SetSoldierDirection( new_state->usNewDirection ); - } - // Start cutting fence - else if (new_state->usNewState==CUTTING_FENCE) - { - // The usTargetGridNo holds the GridNo of the fence tile - pSoldier->sTargetGridNo = new_state->usTargetGridNo; + } + // Start cutting fence + else if (new_state->usNewState==CUTTING_FENCE) + { + // The usTargetGridNo holds the GridNo of the fence tile + pSoldier->sTargetGridNo = new_state->usTargetGridNo; - pSoldier->EVENT_InternalSetSoldierPosition( new_state->sXPos, new_state->sYPos ,FALSE, FALSE, FALSE ); - pSoldier->ChangeSoldierStance( ANIM_CROUCH ); - pSoldier->EVENT_SetSoldierDirection( new_state->usNewDirection ); - } + pSoldier->EVENT_InternalSetSoldierPosition( new_state->sXPos, new_state->sYPos ,FALSE, FALSE, FALSE ); + pSoldier->ChangeSoldierStance( ANIM_CROUCH ); + pSoldier->EVENT_SetSoldierDirection( new_state->usNewDirection ); + } pSoldier->EVENT_InitNewSoldierAnim( new_state->usNewState, new_state->usStartingAniCode, new_state->fForce ); } @@ -4049,7 +3635,6 @@ void send_death( SOLDIERTYPE *pSoldier ) // Translate soldier id for other clients if the soldier was one of ours if(pSoldier->ubID<20)nDeath.soldier_id=nDeath.soldier_id+ubID_prefix; - // if soldier died from bleeding if(pSoldier->ubAttackerID==NULL || pSoldier->ubAttackerID == NOBODY) { @@ -4084,14 +3669,13 @@ void send_death( SOLDIERTYPE *pSoldier ) nDeath.attacker_id = pAttacker->ubID; } - - // Translate attacker id for other clients if attacker was one of ours if(pAttacker->ubID<20)nDeath.attacker_id=pAttacker->ubID+ubID_prefix; pA_bTeam=pAttacker->bTeam; memcpy(pA_name,pAttacker->name,sizeof(CHAR16)*10); - if (pA_bTeam==1 && PLAYER_BSIDE==MP_TYPE_COOP) + + if (pA_bTeam==1 && cGameType==MP_TYPE_COOP) { // CO-OP Kill by an enemy ai pA_bTeam = 5; // the server subtracts 1 from these numbers to score in scoreboard, AI is index 4 @@ -4099,15 +3683,19 @@ void send_death( SOLDIERTYPE *pSoldier ) else { // Any mode, kill by a players merc - if(pA_bTeam>5)pA_bTeam=pA_bTeam-5; - if(pA_bTeam==0)pA_bTeam= CLIENT_NUM; + if(pA_bTeam>5) + pA_bTeam=pA_bTeam-5; + + if(pA_bTeam==0) + pA_bTeam= CLIENT_NUM; } } + if(pSoldier) { pS_bTeam=pSoldier->bTeam; memcpy(pS_name,pSoldier->name,sizeof(CHAR16)*10); - if(pS_bTeam==1 && PLAYER_BSIDE==MP_TYPE_COOP) + if(pS_bTeam==1 && cGameType==MP_TYPE_COOP) { // CO-OP Death of an enemy ai pS_bTeam = 5; // the server subtracts 1 from these numbers to score in scoreboard, AI is index 4 @@ -4115,8 +3703,11 @@ void send_death( SOLDIERTYPE *pSoldier ) else { // Any mode death of a players merc - if(pS_bTeam>5)pS_bTeam=pS_bTeam-5; - if(pS_bTeam==0)pS_bTeam=CLIENT_NUM; + if(pS_bTeam>5) + pS_bTeam=pS_bTeam-5; + + if(pS_bTeam==0) + pS_bTeam=CLIENT_NUM; } } @@ -4137,24 +3728,26 @@ void send_death( SOLDIERTYPE *pSoldier ) char a_name[10]; WideCharToMultiByte(CP_UTF8,0,pS_name,-1, s_name,10,NULL,NULL); WideCharToMultiByte(CP_UTF8,0,pA_name,-1, a_name,10,NULL,NULL); - if (pSoldier->bTeam==1) MPDebugMsg( String ( "MPDEBUG SEND - Enemy AI #%d was killed by ('%s' - %d) (client %d - '%s')\n",nDeath.soldier_id,a_name,nDeath.attacker_id,pA_bTeam,client_names[pA_bTeam-1]) ); - else if (pAttacker->bTeam==1) MPDebugMsg( String ( "MPDEBUG SEND - '%s' (client %d - '%S') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,"Queens Army") ); - else MPDebugMsg( String ( "MPDEBUG SEND - '%s' (client %d - '%S') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,client_names[(pA_bTeam-1)]) ); + + if (pSoldier->bTeam==1) + MPDebugMsg( String ( "MPDEBUG SEND - Enemy AI #%d was killed by ('%s' - %d) (client %d - '%s')\n",nDeath.soldier_id,a_name,nDeath.attacker_id,pA_bTeam,client_names[pA_bTeam-1]) ); + else if (pAttacker->bTeam==1) + MPDebugMsg( String ( "MPDEBUG SEND - '%s' (client %d - '%S') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,"Queens Army") ); + else + MPDebugMsg( String ( "MPDEBUG SEND - '%s' (client %d - '%S') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,client_names[(pA_bTeam-1)]) ); #endif - //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[28],(pS_bTeam), pS_name,client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); } void recieveDEATH (RPCParameters *rpcParameters) { - death_struct* nDeath = (death_struct*)rpcParameters->input; SOLDIERTYPE * pSoldier=MercPtrs[ nDeath->soldier_id ]; UINT16 ubAttackerID; - if((nDeath->attacker_id >= ubID_prefix) && (nDeath->attacker_id < (ubID_prefix+6))) - ubAttackerID = (nDeath->attacker_id - ubID_prefix); - else - ubAttackerID = nDeath->attacker_id; + if((nDeath->attacker_id >= ubID_prefix) && (nDeath->attacker_id < (ubID_prefix+6))) + ubAttackerID = (nDeath->attacker_id - ubID_prefix); + else + ubAttackerID = nDeath->attacker_id; SOLDIERTYPE * pAttacker=MercPtrs[ ubAttackerID ]; INT8 pA_bTeam; @@ -4164,20 +3757,26 @@ void recieveDEATH (RPCParameters *rpcParameters) if(pAttacker) { - pA_bTeam=pAttacker->bTeam; - memcpy(pA_name,pAttacker->name,sizeof(CHAR16)*10); - if(pA_bTeam>5)pA_bTeam=pA_bTeam-5; - if(pA_bTeam==0)pA_bTeam=CLIENT_NUM; + pA_bTeam=pAttacker->bTeam; + memcpy(pA_name,pAttacker->name,sizeof(CHAR16)*10); + + if(pA_bTeam>5) + pA_bTeam=pA_bTeam-5; + if(pA_bTeam==0) + pA_bTeam=CLIENT_NUM; } + if(pSoldier) { - pS_bTeam=pSoldier->bTeam; - memcpy(pS_name,pSoldier->name,sizeof(CHAR16)*10); - if(pS_bTeam>5)pS_bTeam=pS_bTeam-5; - if(pS_bTeam==0)pS_bTeam=CLIENT_NUM; + pS_bTeam=pSoldier->bTeam; + memcpy(pS_name,pSoldier->name,sizeof(CHAR16)*10); + + if(pS_bTeam>5) + pS_bTeam=pS_bTeam-5; + if(pS_bTeam==0) + pS_bTeam=CLIENT_NUM; } - if(pSoldier->bActive) { pSoldier->usAnimState=50; @@ -4190,15 +3789,15 @@ void recieveDEATH (RPCParameters *rpcParameters) TurnSoldierIntoCorpse( pSoldier, TRUE, TRUE ); - if ( CheckForEndOfBattle( FALSE ) ) - { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"All over red rover..."); - } + if ( CheckForEndOfBattle( FALSE ) ) + { + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[72]); + } + if (pSoldier->bTeam==1) ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, MPClientMessage[67]); - else ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[28],pS_name,(pS_bTeam),client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); - //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[28],(pS_bTeam),pS_name,client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); - + else + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[28],pS_name,(pS_bTeam),client_names[(pS_bTeam-1)],pA_name,(pA_bTeam),client_names[(pA_bTeam-1)] ); } else { @@ -4206,7 +3805,9 @@ void recieveDEATH (RPCParameters *rpcParameters) ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"merc already corpse/dead"); #endif - if (pSoldier->bTeam==1) ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, MPClientMessage[67]); + if (pSoldier->bTeam==1) + ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, MPClientMessage[67]); + CheckForEndOfBattle( FALSE ); } @@ -4215,9 +3816,13 @@ void recieveDEATH (RPCParameters *rpcParameters) char a_name[10]; WideCharToMultiByte(CP_UTF8,0,pS_name,-1, s_name,10,NULL,NULL); WideCharToMultiByte(CP_UTF8,0,pA_name,-1, a_name,10,NULL,NULL); - if (pSoldier->bTeam==1) MPDebugMsg( String ( "MPDEBUG RECV - Enemy AI #%d was killed by ('%s' - #%d) (client %d - '%s')\n",nDeath->soldier_id,a_name,nDeath->attacker_id,pA_bTeam,client_names[pA_bTeam-1]) ); - else if (pAttacker->bTeam==1) MPDebugMsg( String ( "MPDEBUG RECV - '%s' (client %d - '%s') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,"Queens Army") ); - else MPDebugMsg( String ( "MPDEBUG RECV - '%s' (client %d - '%s') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,client_names[(pA_bTeam-1)]) ); + + if (pSoldier->bTeam==1) + MPDebugMsg( String ( "MPDEBUG RECV - Enemy AI #%d was killed by ('%s' - #%d) (client %d - '%s')\n",nDeath->soldier_id,a_name,nDeath->attacker_id,pA_bTeam,client_names[pA_bTeam-1]) ); + else if (pAttacker->bTeam==1) + MPDebugMsg( String ( "MPDEBUG RECV - '%s' (client %d - '%s') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,"Queens Army") ); + else + MPDebugMsg( String ( "MPDEBUG RECV - '%s' (client %d - '%s') was killed by '%s' (client %d - '%s')\n",s_name,pS_bTeam,client_names[(pS_bTeam-1)],a_name,pA_bTeam,client_names[(pA_bTeam-1)]) ); #endif } @@ -4227,77 +3832,62 @@ void send_hitstruct(EV_S_STRUCTUREHIT * SStructureHit) memcpy( &struct_hit , SStructureHit, sizeof( EV_S_STRUCTUREHIT )); if(SStructureHit->ubAttackerID <20)struct_hit.ubAttackerID = SStructureHit->ubAttackerID+ubID_prefix; - client->RPC("sendhitSTRUCT",(const char*)&struct_hit, (int)sizeof(EV_S_STRUCTUREHIT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } void send_hitwindow(EV_S_WINDOWHIT * SWindowHit) { - EV_S_WINDOWHIT window_hit; + EV_S_WINDOWHIT window_hit; memcpy( &window_hit , SWindowHit, sizeof( EV_S_WINDOWHIT )); - if(SWindowHit->ubAttackerID <20)window_hit.ubAttackerID = SWindowHit->ubAttackerID+ubID_prefix; + + if(SWindowHit->ubAttackerID <20) + window_hit.ubAttackerID = SWindowHit->ubAttackerID+ubID_prefix; - client->RPC("sendhitWINDOW",(const char*)&window_hit, (int)sizeof(EV_S_WINDOWHIT)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void send_miss(EV_S_MISS * SMiss) { - - EV_S_MISS shot_miss; + EV_S_MISS shot_miss; memcpy( &shot_miss , SMiss, sizeof( EV_S_MISS )); - if(SMiss->ubAttackerID <20)shot_miss.ubAttackerID = SMiss->ubAttackerID+ubID_prefix; + + if(SMiss->ubAttackerID <20) + shot_miss.ubAttackerID = SMiss->ubAttackerID+ubID_prefix; - client->RPC("sendMISS",(const char*)&shot_miss, (int)sizeof(EV_S_MISS)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recievehitSTRUCT (RPCParameters *rpcParameters) { EV_S_STRUCTUREHIT* struct_hit = (EV_S_STRUCTUREHIT*)rpcParameters->input; - //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"recieved structure hit"); - SOLDIERTYPE *pSoldier = MercPtrs[ struct_hit->ubAttackerID ]; - INT8 bTeam=pSoldier->bTeam; - INT32 iBullet = bTable[bTeam][struct_hit->iBullet].local_id; + SOLDIERTYPE *pSoldier = MercPtrs[ struct_hit->ubAttackerID ]; + INT8 bTeam=pSoldier->bTeam; + INT32 iBullet = bTable[bTeam][struct_hit->iBullet].local_id; + if(struct_hit->fStopped) + StopBullet( iBullet ); - if(struct_hit->fStopped)StopBullet( iBullet );//, ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"bullet stopped"); StructureHit( iBullet, struct_hit->usWeaponIndex, struct_hit->bWeaponStatus, struct_hit->ubAttackerID, struct_hit->sXPos, struct_hit->sYPos, struct_hit->sZPos, struct_hit->usStructureID, struct_hit->iImpact, struct_hit->fStopped ); - if(struct_hit->fStopped)RemoveBullet(iBullet);//, ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"bullet removed"); - //else ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"bullet left"); + if(struct_hit->fStopped) + RemoveBullet(iBullet); } + void recievehitWINDOW (RPCParameters *rpcParameters) { EV_S_WINDOWHIT* window_hit = (EV_S_WINDOWHIT*)rpcParameters->input; - - - WindowHit( window_hit->sGridNo, window_hit->usStructureID, window_hit->fBlowWindowSouth, window_hit->fLargeForce ); - - //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"recieved window hit"); } + void recieveMISS (RPCParameters *rpcParameters) { EV_S_MISS* shot_miss = (EV_S_MISS*)rpcParameters->input; - SOLDIERTYPE *pSoldier = MercPtrs[ shot_miss->ubAttackerID ]; - INT8 bTeam=pSoldier->bTeam; - INT32 iBullet = bTable[bTeam][shot_miss->iBullet].local_id; - + SOLDIERTYPE *pSoldier = MercPtrs[ shot_miss->ubAttackerID ]; + INT8 bTeam=pSoldier->bTeam; + INT32 iBullet = bTable[bTeam][shot_miss->iBullet].local_id; ShotMiss( shot_miss->ubAttackerID, iBullet ); - //ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"recieved shot miss"); -} - -void cheat_func(void) -{ - if(TESTING) - { - ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, L"gTacticalStatus.uiFlags |= SHOW_ALL_MERCS"); - gTacticalStatus.uiFlags |= SHOW_ALL_MERCS; - } } BOOLEAN check_status (void)// any 'enemies' and clients left to fight ?? @@ -4321,19 +3911,20 @@ BOOLEAN check_status (void)// any 'enemies' and clients left to fight ?? soldiers++; } } + if(soldiers>0) { gTacticalStatus.Team[ x ].bTeamActive=1; gTacticalStatus.Team[ x ].bMenInSector=soldiers; - if (PLAYER_BSIDE==1 && (x==0 || x>5)) + if (cGameType==MP_TYPE_TEAMDEATMATCH && (x==0 || x>5)) { // store the number of active DM teams, and number of players per team still alive int cl_num = CLIENT_NUM; // 1 based if (x>5) cl_num = x - 5; dm_teams[ client_teams[ cl_num - 1 ] ]++; } - else if (PLAYER_BSIDE != 1) + else if (cGameType != MP_TYPE_TEAMDEATMATCH) { // count number of active teams numActiveSides++; @@ -4345,29 +3936,31 @@ BOOLEAN check_status (void)// any 'enemies' and clients left to fight ?? gTacticalStatus.Team[x].bMenInSector=0; } } + if( (gTacticalStatus.Team[ 0 ].bTeamActive == 0) && wiped==0)//server's team has been knocked out { wiped=1; ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[40] ); - if(!DISABLE_SPEC_MODE) + if(!cDisableSpectatorMode) { gTacticalStatus.uiFlags |= SHOW_ALL_MERCS;//hayden ScreenMsg( FONT_YELLOW, MSG_MPSYSTEM, MPClientMessage[41] ); } else - ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"spectator mode disabled"); + { + ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPClientMessage[73]); + } teamwiped(); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[42] ); } - if (PLAYER_BSIDE == 0) + if (cGameType == MP_TYPE_DEATHMATCH) { // check game end for DeathMatch return (numActiveSides > 1); } - else if (PLAYER_BSIDE == 1) + else if (cGameType == MP_TYPE_TEAMDEATMATCH) { // check game end for Team Deathmatch // count how many active deathmatch teams are alive (two players could be alive but might be on the same TEAM) @@ -4381,7 +3974,7 @@ BOOLEAN check_status (void)// any 'enemies' and clients left to fight ?? return (numActiveSides > 1); } - else if (PLAYER_BSIDE == 2) + else if (cGameType == MP_TYPE_COOP) { // check for game end for CO-OP // If any player team is alive && the number of enemies > 0 then continue game (true), else quit (false) @@ -4394,9 +3987,9 @@ BOOLEAN check_status (void)// any 'enemies' and clients left to fight ?? void UpdateSoldierToNetwork ( SOLDIERTYPE *pSoldier ) { - //this send stats to other clients at intervals - UINT8 id = pSoldier->ubID; - UINT32 time = GetJA2Clock(); + //this send stats to other clients at intervals + UINT8 id = pSoldier->ubID; + UINT32 time = GetJA2Clock(); if(id < 20 || (is_server && id <120)) { @@ -4407,13 +4000,13 @@ void UpdateSoldierToNetwork ( SOLDIERTYPE *pSoldier ) if((time - (pSoldier->usLastUpdateTime)) > 2000 && pSoldier->stats.bLife!=0) { pSoldier->usLastUpdateTime = time; - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"update: %d ",time ); - EV_S_UPDATENETWORKSOLDIER SUpdateNetworkSoldier; SUpdateNetworkSoldier.usSoldierID=pSoldier->ubID; - if(pSoldier->ubID < 20)SUpdateNetworkSoldier.usSoldierID=pSoldier->ubID+ubID_prefix; + + if(pSoldier->ubID < 20) + SUpdateNetworkSoldier.usSoldierID=pSoldier->ubID+ubID_prefix; SUpdateNetworkSoldier.sAtGridNo=pSoldier->sGridNo; SUpdateNetworkSoldier.bBreath=pSoldier->bBreath; @@ -4423,7 +4016,6 @@ void UpdateSoldierToNetwork ( SOLDIERTYPE *pSoldier ) SUpdateNetworkSoldier.bBleeding=pSoldier->bBleeding; SUpdateNetworkSoldier.ubNewStance= gAnimControl[ pSoldier->usAnimState ].ubEndHeight; - if((gTacticalStatus.ubTopMessageType == PLAYER_TURN_MESSAGE || gTacticalStatus.ubTopMessageType == PLAYER_INTERRUPT_MESSAGE || ((gTacticalStatus.ubTopMessageType == COMPUTER_INTERRUPT_MESSAGE || gTacticalStatus.ubTopMessageType == COMPUTER_TURN_MESSAGE )&& is_server)) && (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT))//update progress bar, not supporting coop yet... { SUpdateNetworkSoldier.usTactialTurnLimitCounter = gTacticalStatus.usTactialTurnLimitCounter; @@ -4432,9 +4024,7 @@ void UpdateSoldierToNetwork ( SOLDIERTYPE *pSoldier ) else SUpdateNetworkSoldier.usTactialTurnLimitCounter = 9999; - client->RPC("updatenetworksoldier",(const char*)&SUpdateNetworkSoldier, (int)sizeof(EV_S_UPDATENETWORKSOLDIER)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } } } @@ -4447,38 +4037,30 @@ void UpdateSoldierFromNetwork (RPCParameters *rpcParameters) pSoldier->bBreath=SUpdateNetworkSoldier->bBreath; pSoldier->stats.bLife=SUpdateNetworkSoldier->bLife; + INT16 sCellX, sCellY; + sCellX = CenterX( SUpdateNetworkSoldier->sAtGridNo ); + sCellY = CenterY( SUpdateNetworkSoldier->sAtGridNo ); + if( pSoldier->sGridNo != SUpdateNetworkSoldier->sAtGridNo) + { + pSoldier->EVENT_InternalSetSoldierPosition( sCellX, sCellY ,FALSE, FALSE, FALSE );//new syncing call to correct network lag/drift + } - - INT16 sCellX, sCellY; - sCellX = CenterX( SUpdateNetworkSoldier->sAtGridNo ); - sCellY = CenterY( SUpdateNetworkSoldier->sAtGridNo ); - - if( pSoldier->sGridNo != SUpdateNetworkSoldier->sAtGridNo) - { - pSoldier->EVENT_InternalSetSoldierPosition( sCellX, sCellY ,FALSE, FALSE, FALSE );//new syncing call to correct network lag/drift - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"sync ubid:%d grid %d to %d",pSoldier->ubID,pSoldier->sGridNo,SUpdateNetworkSoldier->sAtGridNo ); - } - - if(pSoldier->ubDirection != SUpdateNetworkSoldier->ubDirection) - { - pSoldier->EVENT_SetSoldierDesiredDirection( SUpdateNetworkSoldier->ubDirection ); - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"sync ubid:%d dir %d to %d",pSoldier->ubID, pSoldier->ubDirection, SUpdateNetworkSoldier->ubDirection ); - } - if(gAnimControl[ pSoldier->usAnimState ].ubEndHeight != SUpdateNetworkSoldier->ubNewStance && pSoldier->bCollapsed != TRUE) - { - pSoldier->ChangeSoldierStance( SUpdateNetworkSoldier->ubNewStance ); - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"update stance"); - } + if(pSoldier->ubDirection != SUpdateNetworkSoldier->ubDirection) + { + pSoldier->EVENT_SetSoldierDesiredDirection( SUpdateNetworkSoldier->ubDirection ); + } + if(gAnimControl[ pSoldier->usAnimState ].ubEndHeight != SUpdateNetworkSoldier->ubNewStance && pSoldier->bCollapsed != TRUE) + { + pSoldier->ChangeSoldierStance( SUpdateNetworkSoldier->ubNewStance ); + } - pSoldier->bBleeding=SUpdateNetworkSoldier->bBleeding; if( (SUpdateNetworkSoldier->usTactialTurnLimitCounter != 9999) && (gTacticalStatus.ubTopMessageType != PLAYER_TURN_MESSAGE) && (gTacticalStatus.ubTopMessageType != PLAYER_INTERRUPT_MESSAGE)) { gTacticalStatus.usTactialTurnLimitCounter = SUpdateNetworkSoldier->usTactialTurnLimitCounter; gTacticalStatus.usTactialTurnLimitMax = SUpdateNetworkSoldier->usTactialTurnLimitMax; - } } @@ -4487,25 +4069,23 @@ void kick_player (void) { if(is_server) { - //manual overide command for server - const STR16 msg = L"Choose Client Number to Kick:"; - - SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; - DoMessageBox( MSG_BOX_BASIC_STYLE, msg, guiCurrentScreen, MSG_BOX_FLAG_FOUR_NUMBERED_BUTTONS | MSG_BOX_FLAG_USE_CENTERING_RECT, kick_callback, &CenterRect ); + //manual overide command for server + const STR16 msg = MPClientMessage[74]; + SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; + DoMessageBox( MSG_BOX_BASIC_STYLE, msg, guiCurrentScreen, MSG_BOX_FLAG_FOUR_NUMBERED_BUTTONS | MSG_BOX_FLAG_USE_CENTERING_RECT, kick_callback, &CenterRect ); } - else ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[22] ); + else + ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[22] ); } + void kick_callback (UINT8 ubResult) -{ - +{ kickR kick; kick.ubResult=ubResult+5; - //ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"kicking client " ); client->RPC("Snull_team",(const char*)&kick, (int)sizeof(kickR)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } void null_team (RPCParameters *rpcParameters) @@ -4514,125 +4094,111 @@ void null_team (RPCParameters *rpcParameters) ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[29],(kick->ubResult-5),client_names[kick->ubResult-6] ); int fID = gTacticalStatus.Team[ kick->ubResult ].bFirstID; int lID = gTacticalStatus.Team[ kick->ubResult ].bLastID; - - if(kick->ubResult==netbTeam)fID=0,lID=19; + + if(kick->ubResult==netbTeam) + fID=0,lID=19; + int cnt; for ( cnt=fID ; cnt <= lID; cnt++ ) { TacticalRemoveSoldier( cnt ); } - } void overide_turn (void) { if(is_server) { - //manual overide command for server - //const STR16 msg = MPClientMessage[30]; + //manual overide command for server CHAR16 Cmsg[255]; swprintf(Cmsg, MPClientMessage[30], client_names[0],client_names[1],client_names[2],client_names[3]); - - - SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; - DoMessageBox( MSG_BOX_BASIC_STYLE, Cmsg, guiCurrentScreen, MSG_BOX_FLAG_FOUR_NUMBERED_BUTTONS | MSG_BOX_FLAG_USE_CENTERING_RECT, turn_callback, &CenterRect ); - + SGPRect CenterRect = { 100, 100, SCREEN_WIDTH - 100, 300 }; + DoMessageBox( MSG_BOX_BASIC_STYLE, Cmsg, guiCurrentScreen, MSG_BOX_FLAG_FOUR_NUMBERED_BUTTONS | MSG_BOX_FLAG_USE_CENTERING_RECT, turn_callback, &CenterRect ); } - else ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[22] ); - + else + ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[22] ); } void turn_callback (UINT8 ubResult) { - if(is_server) { ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[31],ubResult ); - if(!( gTacticalStatus.uiFlags & INCOMBAT )) - { - gTacticalStatus.uiFlags |= INCOMBAT; - } - if(ubResult ==1)EndTurn( 0 ); - else EndTurn( ubResult+5 ); + if(!( gTacticalStatus.uiFlags & INCOMBAT )) + { + gTacticalStatus.uiFlags |= INCOMBAT; + } + + if(ubResult ==1) + EndTurn( 0 ); + else + EndTurn( ubResult+5 ); } } void send_fireweapon (EV_S_FIREWEAPON *SFireWeapon) { - EV_S_FIREWEAPON sFire; - //sFire.usSoldierID=SFireWeapon->usSoldierID; + EV_S_FIREWEAPON sFire; - if(SFireWeapon->usSoldierID < 20) - sFire.usSoldierID = (SFireWeapon->usSoldierID)+ubID_prefix; - else - sFire.usSoldierID = SFireWeapon->usSoldierID; + if(SFireWeapon->usSoldierID < 20) + sFire.usSoldierID = (SFireWeapon->usSoldierID)+ubID_prefix; + else + sFire.usSoldierID = SFireWeapon->usSoldierID; - sFire.sTargetGridNo=SFireWeapon->sTargetGridNo; - sFire.bTargetCubeLevel=SFireWeapon->bTargetCubeLevel; - sFire.bTargetLevel=SFireWeapon->bTargetLevel; - - client->RPC("sendFIREW",(const char*)&sFire, (int)sizeof(EV_S_FIREWEAPON)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + sFire.sTargetGridNo=SFireWeapon->sTargetGridNo; + sFire.bTargetCubeLevel=SFireWeapon->bTargetCubeLevel; + sFire.bTargetLevel=SFireWeapon->bTargetLevel; + client->RPC("sendFIREW",(const char*)&sFire, (int)sizeof(EV_S_FIREWEAPON)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void recieve_fireweapon (RPCParameters *rpcParameters) { - EV_S_FIREWEAPON* SFireWeapon = (EV_S_FIREWEAPON*)rpcParameters->input; - //ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"recieve_fireweapon" ); - //SFireWeapon.usSoldierID = pSoldier->ubID; - ////SFireWeapon.uiUniqueId = pSoldier->uiUniqueSoldierIdValue; - //SFireWeapon.sTargetGridNo = pSoldier->sTargetGridNo; - //SFireWeapon.bTargetLevel = pSoldier->bTargetLevel; - //SFireWeapon.bTargetCubeLevel= pSoldier->bTargetCubeLevel; - //AddGameEvent( S_FIREWEAPON, 0, &SFireWeapon ); + EV_S_FIREWEAPON* SFireWeapon = (EV_S_FIREWEAPON*)rpcParameters->input; SOLDIERTYPE *pSoldier = MercPtrs[ SFireWeapon->usSoldierID ]; - pSoldier->sTargetGridNo = SFireWeapon->sTargetGridNo; - pSoldier->bTargetLevel = SFireWeapon->bTargetLevel; - pSoldier->bTargetCubeLevel = SFireWeapon->bTargetCubeLevel; - FireWeapon( pSoldier, SFireWeapon->sTargetGridNo ); - + pSoldier->sTargetGridNo = SFireWeapon->sTargetGridNo; + pSoldier->bTargetLevel = SFireWeapon->bTargetLevel; + pSoldier->bTargetCubeLevel = SFireWeapon->bTargetCubeLevel; + FireWeapon( pSoldier, SFireWeapon->sTargetGridNo ); } void send_door ( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fNoAnimations ) { -if((is_server && pSoldier->ubID<120) || (!is_server && is_client && pSoldier->ubID<20) || (!is_server && !is_client) ) -{ + if((is_server && pSoldier->ubID<120) || (!is_server && is_client && pSoldier->ubID<20) || (!is_server && !is_client) ) + { doors sDoor; sDoor.ubID=pSoldier->ubID; sDoor.sGridNo=sGridNo; sDoor.fNoAnimations=fNoAnimations; - + client->RPC("sendDOOR",(const char*)&sDoor, (int)sizeof(doors)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); -} + } } void recieve_door (RPCParameters *rpcParameters) { - doors* sDoor = (doors*)rpcParameters->input; SOLDIERTYPE *pSoldier = MercPtrs[ sDoor->ubID ]; BOOLEAN fNoAnimations = FALSE; - if ( !AllMercsLookForDoor( sDoor->sGridNo, FALSE ) )//check for los - { - fNoAnimations = TRUE; - } - + if ( !AllMercsLookForDoor( sDoor->sGridNo, FALSE ) )//check for los + { + fNoAnimations = TRUE; + } HandleDoorChangeFromGridNo( pSoldier, sDoor->sGridNo, fNoAnimations ); - } void recieveCHATMSG(RPCParameters* rpcParameters) { chat_msg* cmsg = (chat_msg*)rpcParameters->input; - if (PLAYER_BSIDE==1 && cmsg->bToAll == false) + if (cGameType==MP_TYPE_TEAMDEATMATCH && cmsg->bToAll == false) { // If Team deathmatch && msg is allies only if (client_teams[cmsg->client_num-1] == TEAM) @@ -4703,7 +4269,6 @@ void recieveDISCONNECT(RPCParameters* rpcParameters) if(gTacticalStatus.ubCurrentTeam==iNetbTeam)EndTurn( iNetbTeam+1 ); } } - } // OJW - 20090507 @@ -4758,7 +4323,6 @@ void disconnected_callback(UINT8 ubResult) // else dont clean "everything" but still exit to main menu SetPendingNewScreen(MAINMENU_SCREEN); } - } // Gracefully handle self-disconnection of the client by Dropout @@ -4792,7 +4356,6 @@ void HandleClientConnectionLost() // Tell the score screen it can continue gfMPSScoreScreenCanContinue = TRUE; } - } void sendRT(void) @@ -4806,7 +4369,6 @@ void sendRT(void) client->RPC("sendREAL",(const char*)&rData, (int)sizeof(real_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } - } void gotoRT(RPCParameters *rpcParameters) @@ -4819,31 +4381,28 @@ void gotoRT(RPCParameters *rpcParameters) ExitCombatMode(); fInterfacePanelDirty = DIRTYLEVEL2; - - if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[34] ); - - } else { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, MPClientMessage[33] ); } -getReal=false; + getReal=false; } void startCombat(UINT8 ubStartingTeam) { - sc_struct data; - if(ubStartingTeam==0) - ubStartingTeam=netbTeam; - data.ubStartingTeam=ubStartingTeam; - client->RPC("startCOMBAT",(const char*)&data, (int)sizeof(sc_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - + sc_struct data; + if(ubStartingTeam==0) + ubStartingTeam=netbTeam; + + data.ubStartingTeam=ubStartingTeam; + + client->RPC("startCOMBAT",(const char*)&data, (int)sizeof(sc_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } void teamwiped ( void ) @@ -4858,30 +4417,29 @@ void teamwiped ( void ) if (is_server) { // end the co-op game if all player teams have wiped - if (PLAYER_BSIDE==MP_TYPE_COOP) + if (cGameType==MP_TYPE_COOP) { iTeamsWiped++; - if (iTeamsWiped >= MAX_CLIENTS) + if (iTeamsWiped >= cMaxClients) game_over(); } } } void recieve_wipe (RPCParameters *rpcParameters) - { sc_struct* data = (sc_struct*)rpcParameters->input; - ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"Team #%d is wiped out.", data->ubStartingTeam ); + ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, MPClientMessage[75], data->ubStartingTeam ); if(is_server) { if(gTacticalStatus.ubCurrentTeam==data->ubStartingTeam)EndTurn( data->ubStartingTeam+1 ); // end the co-op game if all player teams have wiped - if (PLAYER_BSIDE==MP_TYPE_COOP) + if (cGameType==MP_TYPE_COOP) { iTeamsWiped++; - if (iTeamsWiped >= MAX_CLIENTS) + if (iTeamsWiped >= cMaxClients) game_over(); } } @@ -4894,36 +4452,38 @@ void send_heal (SOLDIERTYPE *pSoldier ) data.bLife=pSoldier->stats.bLife; data.bBleeding=pSoldier->bBleeding; - client->RPC("sendHEAL",(const char*)&data, (int)sizeof(heal)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } void recieve_heal (RPCParameters *rpcParameters) { heal* data = (heal*)rpcParameters->input; - UINT16 healed; - if((data->ubID >= ubID_prefix) && (data->ubID < (ubID_prefix+6))) - healed = (data->ubID - ubID_prefix); - else - healed = data->ubID; + + if((data->ubID >= ubID_prefix) && (data->ubID < (ubID_prefix+6))) + healed = (data->ubID - ubID_prefix); + else + healed = data->ubID; SOLDIERTYPE *pSoldier = MercPtrs[ healed ]; pSoldier->bBleeding=data->bBleeding; pSoldier->stats.bLife=data->bLife; + +#if BETAVERSION ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"healing..." ); - +#endif } - void requestAIint(SOLDIERTYPE *pSoldier ) { AIint data; data.ubID=pSoldier->ubID; data.bteam=netbTeam; + +#ifdef BETAVERSION ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"interrupt requested" ); +#endif client->RPC("rINT",(const char*)&data, (int)sizeof(AIint)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } @@ -4934,17 +4494,17 @@ void awardINT (RPCParameters *rpcParameters) SOLDIERTYPE *pSoldier = MercPtrs[ data->ubID ]; - StartInterrupt(); - //send_EndTurn(netbTeam); + StartInterrupt(); +#ifdef BETAVERSION ScreenMsg( FONT_LTGREEN, MSG_INTERFACE, L"interrupt awarded" ); +#endif } void game_over() { // wait 3 seconds then notify all clients - // reset isOwnTeamWipedOut = false; @@ -4983,312 +4543,198 @@ void recieveGAMEOVER(RPCParameters *rpcParameters) StartScoreScreen(); } - //*************************** //*** client connection***** //************************* void connect_client ( void ) { - - if(!is_client) - { - ScreenMsg( FONT_BEIGE, MSG_MPSYSTEM, MPClientMessage[0] ); - + if(!is_client) + { + ScreenMsg( FONT_BEIGE, MSG_MPSYSTEM, MPClientMessage[0] ); - + client = RakNetworkFactory::GetRakPeerInterface(); + bool b = client->Startup(1,30,&SocketDescriptor(), 1); + + //RPC's + REGISTER_STATIC_RPC(client, recievePATH); + REGISTER_STATIC_RPC(client, recieveSTANCE); + REGISTER_STATIC_RPC(client, recieveDIR); + REGISTER_STATIC_RPC(client, recieveFIRE); + REGISTER_STATIC_RPC(client, recieveHIT); + REGISTER_STATIC_RPC(client, recieveHIRE); + REGISTER_STATIC_RPC(client, recieveDISMISS); + REGISTER_STATIC_RPC(client, recieveguiPOS); + REGISTER_STATIC_RPC(client, recieveguiDIR); + REGISTER_STATIC_RPC(client, recieveEndTurn); + REGISTER_STATIC_RPC(client, recieveAI); + REGISTER_STATIC_RPC(client, recieveSTOP); + REGISTER_STATIC_RPC(client, recieveINTERRUPT); + REGISTER_STATIC_RPC(client, recieveREADY); + REGISTER_STATIC_RPC(client, recieveGUI); + REGISTER_STATIC_RPC(client, recieveSETTINGS); + REGISTER_STATIC_RPC(client, recieveDOWNLOADSTATUS); + REGISTER_STATIC_RPC(client, recieveFILE_TRANSFER_SETTINGS); + REGISTER_STATIC_RPC(client, recieveTEAMCHANGE); + REGISTER_STATIC_RPC(client, recieveEDGECHANGE); + REGISTER_STATIC_RPC(client, recieveMAPCHANGE); + REGISTER_STATIC_RPC(client, recieveBULLET); + REGISTER_STATIC_RPC(client, recieveGRENADE); + REGISTER_STATIC_RPC(client, recieveGRENADERESULT); + REGISTER_STATIC_RPC(client, recievePLANTEXPLOSIVE); + REGISTER_STATIC_RPC(client, recieveDETONATEEXPLOSIVE); + REGISTER_STATIC_RPC(client, recieveDISARMEXPLOSIVE); + REGISTER_STATIC_RPC(client, recieveSPREADEFFECT); + REGISTER_STATIC_RPC(client, recieveNEWSMOKEEFFECT); + REGISTER_STATIC_RPC(client, recieveEXPLOSIONDAMAGE); + REGISTER_STATIC_RPC(client, recieveSTATE); + REGISTER_STATIC_RPC(client, recieveDEATH); + REGISTER_STATIC_RPC(client, recievehitSTRUCT); + REGISTER_STATIC_RPC(client, recievehitWINDOW); + REGISTER_STATIC_RPC(client, recieveMISS); + REGISTER_STATIC_RPC(client, resume_turn); + REGISTER_STATIC_RPC(client, UpdateSoldierFromNetwork); + REGISTER_STATIC_RPC(client, recieve_fireweapon); + REGISTER_STATIC_RPC(client, recieve_door); + REGISTER_STATIC_RPC(client, null_team); + REGISTER_STATIC_RPC(client, gotoRT); + REGISTER_STATIC_RPC(client, recieve_wipe); + REGISTER_STATIC_RPC(client, recieve_heal); + REGISTER_STATIC_RPC(client, awardINT); + REGISTER_STATIC_RPC(client, recieveGAMEOVER); + REGISTER_STATIC_RPC(client, recieveDISCONNECT); + REGISTER_STATIC_RPC(client, recieveCHATMSG); + REGISTER_STATIC_RPC(client, requestSETID); + REGISTER_STATIC_RPC(client, recieveDISCONNECTREASON); + //*** - client=RakNetworkFactory::GetRakPeerInterface(); - bool b = client->Startup(1,30,&SocketDescriptor(), 1); - - //RPC's - REGISTER_STATIC_RPC(client, recievePATH); - REGISTER_STATIC_RPC(client, recieveSTANCE); - REGISTER_STATIC_RPC(client, recieveDIR); - REGISTER_STATIC_RPC(client, recieveFIRE); - REGISTER_STATIC_RPC(client, recieveHIT); - REGISTER_STATIC_RPC(client, recieveHIRE); - REGISTER_STATIC_RPC(client, recieveDISMISS); - REGISTER_STATIC_RPC(client, recieveguiPOS); - REGISTER_STATIC_RPC(client, recieveguiDIR); - REGISTER_STATIC_RPC(client, recieveEndTurn); - REGISTER_STATIC_RPC(client, recieveAI); - REGISTER_STATIC_RPC(client, recieveSTOP); - REGISTER_STATIC_RPC(client, recieveINTERRUPT); - REGISTER_STATIC_RPC(client, recieveREADY); - REGISTER_STATIC_RPC(client, recieveGUI); - REGISTER_STATIC_RPC(client, recieveSETTINGS); - REGISTER_STATIC_RPC(client, recieveDOWNLOADSTATUS); - REGISTER_STATIC_RPC(client, recieveFILE_TRANSFER_SETTINGS); - REGISTER_STATIC_RPC(client, recieveTEAMCHANGE); - REGISTER_STATIC_RPC(client, recieveEDGECHANGE); - REGISTER_STATIC_RPC(client, recieveMAPCHANGE); - REGISTER_STATIC_RPC(client, recieveBULLET); - REGISTER_STATIC_RPC(client, recieveGRENADE); - REGISTER_STATIC_RPC(client, recieveGRENADERESULT); - REGISTER_STATIC_RPC(client, recievePLANTEXPLOSIVE); - REGISTER_STATIC_RPC(client, recieveDETONATEEXPLOSIVE); - REGISTER_STATIC_RPC(client, recieveDISARMEXPLOSIVE); - REGISTER_STATIC_RPC(client, recieveSPREADEFFECT); - REGISTER_STATIC_RPC(client, recieveNEWSMOKEEFFECT); - REGISTER_STATIC_RPC(client, recieveEXPLOSIONDAMAGE); - REGISTER_STATIC_RPC(client, recieveSTATE); - REGISTER_STATIC_RPC(client, recieveDEATH); - REGISTER_STATIC_RPC(client, recievehitSTRUCT); - REGISTER_STATIC_RPC(client, recievehitWINDOW); - REGISTER_STATIC_RPC(client, recieveMISS); - REGISTER_STATIC_RPC(client, resume_turn); - REGISTER_STATIC_RPC(client, UpdateSoldierFromNetwork); - REGISTER_STATIC_RPC(client, recieve_fireweapon); - REGISTER_STATIC_RPC(client, recieve_door); - REGISTER_STATIC_RPC(client, null_team); - REGISTER_STATIC_RPC(client, gotoRT); - REGISTER_STATIC_RPC(client, recieve_wipe); - REGISTER_STATIC_RPC(client, recieve_heal); - REGISTER_STATIC_RPC(client, awardINT); - REGISTER_STATIC_RPC(client, recieveGAMEOVER); - REGISTER_STATIC_RPC(client, recieveDISCONNECT); - REGISTER_STATIC_RPC(client, recieveCHATMSG); - REGISTER_STATIC_RPC(client, requestSETID); - REGISTER_STATIC_RPC(client, recieveDISCONNECTREASON); - //*** - if (b) { - //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"Client started, waiting for connections..."); is_client=true; } else { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"Client failed to start. Terminating."); - + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[76]); } is_connected=false; - + } + //reconnect/connect + if( !is_connected && !is_connecting) + { + gTacticalStatus.uiFlags&= (~SHOW_ALL_MERCS ); + + memset( &readyteamreg , 0 , sizeof (int) * 10); + //OJW - 20081204 + memset ( &client_names,NULL,sizeof(int)*4); + memset ( &client_ready,0,sizeof(int)*4); + memset ( &client_teams,0,sizeof(int)*4); + + if (!gRandomStartingEdge) + memset ( &client_edges,0,sizeof(int)*5); + + if (gRandomMercs) + memset (random_mercs,0,sizeof(int)*7); + + memset( gMPPlayerStats,0,sizeof(player_stats)*5); + memset ( &client_downloading,0,sizeof(int)*4); + memset ( &client_progress,0,sizeof(int)*4); + memset( &gszDisconnectReason,0,sizeof(CHAR16)*255); + + // ---------------------------- + // Read from ja2_mp.ini + // ---------------------------- + char serverIP[30]; + + CIniReader iniReader(JA2MP_INI_FILENAME); + strncpy(serverIP, iniReader.ReadString(JA2MP_INI_INITIAL_SECTION,JA2MP_SERVER_IP, ""), 30); + strncpy(cClientName, iniReader.ReadString(JA2MP_INI_INITIAL_SECTION,JA2MP_CLIENT_NAME, ""), 30); + strncpy(cGameDataSyncDirectory, iniReader.ReadString(JA2MP_INI_INITIAL_SECTION,JA2MP_FILE_TRANSFER_DIRECTORY, "MULTIPLAYER/Servers/My Server"), 100); + + vfs::PropertyContainer props; + props.initFromIniFile(JA2MP_INI_FILENAME); + UINT16 serverPort = (UINT16)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_SERVER_PORT, 60005); + + // ---------------------------- + // Save to global values + // ---------------------------- + recieved_settings=0; + recieved_transfer_settings=0; + goahead = 0; + numready = 0; + readystage = 0; + status = 0; + is_game_started = false; + TEAM = 0; + isOwnTeamWipedOut = false; + wiped=0; + //disable cheating + gubCheatLevel = 0; + cMaxClients = 0; //reset server only set settings. + cDamageMultiplier=0; + cSameMercAllowed=0; + cDisableSpectatorMode=0; + + if(is_server) + strcpy(serverIP, "127.0.0.1" ); + + //********************** + //here some nifty little tweaks + + LaptopSaveInfo.guiNumberOfMercPaymentsInDays += 20; + LaptopSaveInfo.gubLastMercIndex = LAST_MERC_ID; + LaptopSaveInfo.ubLastMercAvailableId = 7; + gGameExternalOptions.fEnableSlayForever = 1; + LaptopSaveInfo.gubPlayersMercAccountStatus = 4; - - - - } + // Set fast loading of WWW sites + gfTemporaryDisablingOfLoadPendingFlag = TRUE; + + //********************** + + // WANNE: FILE TRANSFER: Build the absolut file transfer directory path for the client + GetExecutableDirectory(client_executableDir); + + strcpy(client_fileTransferDirectoryPath, client_executableDir); + strcat(client_fileTransferDirectoryPath, "\\"); + strcat(client_fileTransferDirectoryPath, cGameDataSyncDirectory); + + // WANNE: FILE TRANSFER + client->AttachPlugin(&fltClient); + client->SetSplitMessageProgressInterval(1); - //reconnect/connect - if( !is_connected && !is_connecting) - { - - - recieved_settings=0; - recieved_transfer_settings=0; - goahead = 0; - numready = 0; - readystage = 0; - status = 0; - is_game_started = false; - gTacticalStatus.uiFlags&= (~SHOW_ALL_MERCS ); - memset( &readyteamreg , 0 , sizeof (int) * 10); - //OJW - 20081204 - memset ( &client_names,NULL,sizeof(int)*4); - memset ( &client_ready,0,sizeof(int)*4); - memset ( &client_teams,0,sizeof(int)*4); - if (!RANDOM_SPAWN) - memset ( &client_edges,0,sizeof(int)*5); - if (RANDOM_MERCS) - memset (random_mercs,0,sizeof(int)*7); - memset( gMPPlayerStats,0,sizeof(player_stats)*5); - memset ( &client_downloading,0,sizeof(int)*4); - memset ( &client_progress,0,sizeof(int)*4); - memset( &gszDisconnectReason,0,sizeof(CHAR16)*255); - - - //retrieve settings from Ja2_mp.ini - char ip[30]; - char port[30]; -// char client_number[30]; - char sector_edge[30]; - - isOwnTeamWipedOut = false; - wiped=0; - - //disable cheating - gubCheatLevel = 0; - - //char c_x[30]; - - - char clname[30]; - - MAX_CLIENTS=0;//reset server only set settings. - //INTERRUPTS=0; - DAMAGE_MULTIPLIER=0; - SAME_MERC=0; - DISABLE_SPEC_MODE=0; -#ifndef USE_VFS - CIniReader iniReader("..\\Ja2_mp.ini"); -#else - CIniReader iniReader("Ja2_mp.ini"); -#endif - -#ifndef USE_VFS - GetPrivateProfileString( "Ja2_mp Settings","SERVER_IP", "", ip, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","SERVER_PORT", "", port, MAX_PATH, "..\\Ja2_mp.ini" ); - // GetPrivateProfileString( "Ja2_mp Settings","CLIENT_NUM", "", client_number, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","SECTOR_EDGE", "", sector_edge, MAX_PATH, "..\\Ja2_mp.ini" ); -#else - strncpy(ip, iniReader.ReadString("Ja2_mp Settings","SERVER_IP", ""), 30); - strncpy(port, iniReader.ReadString("Ja2_mp Settings","SERVER_PORT", ""), 30); - // strcpy(client_number, iniReader.ReadString("Ja2_mp Settings","CLIENT_NUM", "")); - strncpy(sector_edge, iniReader.ReadString("Ja2_mp Settings","SECTOR_EDGE", ""), 30); -#endif - - //GetPrivateProfileString( "Ja2_mp Settings","CRATE_X", "", c_x, MAX_PATH, "..\\Ja2_mp.ini" ); - -#ifndef USE_VFS - GetPrivateProfileString( "Ja2_mp Settings","CLIENT_NAME", "", clname, MAX_PATH, "..\\Ja2_mp.ini" ); - - GetPrivateProfileString( "Ja2_mp Settings","FILE_TRANSFER_DIRECTORY", "Data-MP", FILE_TRANSFER_DIRECTORY_CLIENT, MAX_PATH, "..\\Ja2_mp.ini" ); - - gGameOptions.ubInventorySystem = GetPrivateProfileInt( "Ja2_mp Settings","INVENTORY_MODE", INVENTORY_OLD, "..\\Ja2_mp.ini" ); -#else - strncpy(clname, iniReader.ReadString("Ja2_mp Settings","CLIENT_NAME", ""), 30); - - strncpy(FILE_TRANSFER_DIRECTORY_CLIENT, iniReader.ReadString("Ja2_mp Settings","FILE_TRANSFER_DIRECTORY", "Data-MP"), 100); - - gGameOptions.ubInventorySystem = iniReader.ReadInteger("Ja2_mp Settings","INVENTORY_MODE", INVENTORY_OLD); -#endif - - - char op1[30]; - //char op2[30]; - //char op3[30]; - //char op4[30]; -#ifndef USE_VFS - GetPrivateProfileString( "Ja2_mp Settings","TEAM","0", op1, MAX_PATH, "..\\Ja2_mp.ini" ); - //GetPrivateProfileString( "Ja2_mp Settings","OP_TEAM_2", "", op2, MAX_PATH, "..\\Ja2_mp.ini" ); - //GetPrivateProfileString( "Ja2_mp Settings","OP_TEAM_3", "", op3, MAX_PATH, "..\\Ja2_mp.ini" ); - //GetPrivateProfileString( "Ja2_mp Settings","OP_TEAM_4", "", op4, MAX_PATH, "..\\Ja2_mp.ini" ); - /*char stt[30]; - GetPrivateProfileString( "Ja2_mp Settings","START_TEAM_TURN", "", stt, MAX_PATH, "..\\Ja2_mp.ini" );*/ -#else - strncpy(op1, iniReader.ReadString("Ja2_mp Settings","TEAM", ""), 30); - //GetPrivateProfileString( "Ja2_mp Settings","OP_TEAM_2", "", op2, MAX_PATH, "..\\Ja2_mp.ini" ); - //GetPrivateProfileString( "Ja2_mp Settings","OP_TEAM_3", "", op3, MAX_PATH, "..\\Ja2_mp.ini" ); - //GetPrivateProfileString( "Ja2_mp Settings","OP_TEAM_4", "", op4, MAX_PATH, "..\\Ja2_mp.ini" ); - /*char stt[30]; - GetPrivateProfileString( "Ja2_mp Settings","START_TEAM_TURN", "", stt, MAX_PATH, "..\\Ja2_mp.ini" );*/ -#endif - - TEAM=atoi(op1); - //OP_TEAM_2=atoi(op2); - // OP_TEAM_3=atoi(op3); - // OP_TEAM_4=atoi(op4); - - strcpy( CLIENT_NAME, clname); - - - if(is_server)strcpy( SERVER_IP , "127.0.0.1" ); - else strcpy( SERVER_IP , ip ); - - strcpy( SERVER_PORT, port ); - - /*if (is_server) strcpy( CLIENT_NUM, "1" ); - else strcpy( CLIENT_NUM, client_number );*/ - - strcpy( SECT_EDGE, sector_edge); - - //START_TEAM_TURN=atoi(stt); - //crate_sGridX = atoi(c_x); -// crate_sGridY = atoi(c_y); - - /*netbTeam = (CLIENT_NUM)+5; - ubID_prefix = gTacticalStatus.Team[ netbTeam ].bFirstID;*/ - - - - - //********************** - //here some nifty little tweaks - - LaptopSaveInfo.guiNumberOfMercPaymentsInDays += 20; - LaptopSaveInfo.gubLastMercIndex = LAST_MERC_ID; - - LaptopSaveInfo.ubLastMercAvailableId = 7; - gGameExternalOptions.fEnableSlayForever =1; - LaptopSaveInfo.gubPlayersMercAccountStatus = 4; - - // Set fast loading of WWW sites - gfTemporaryDisablingOfLoadPendingFlag = TRUE; - - gMercProfiles[ 57 ].sSalary = 2000; - gMercProfiles[ 58 ].sSalary = 1500; - gMercProfiles[ 59 ].sSalary = 600; - gMercProfiles[ 60 ].sSalary = 500; - gMercProfiles[ 64 ].sSalary = 1500; - gMercProfiles[ 72 ].sSalary = 1000; - gMercProfiles[ 148 ].sSalary = 100; - gMercProfiles[ 68 ].sSalary = 2200; //iggy; - - - //********************** - - // WANNE: FILE TRANSFER: Build the absolut file transfer directory path for the client - GetExecutableDirectory(client_executableDir); - - strcpy(client_fileTransferDirectoryPath, client_executableDir); - strcat(client_fileTransferDirectoryPath, "\\"); - strcat(client_fileTransferDirectoryPath, FILE_TRANSFER_DIRECTORY_CLIENT); - - // WANNE: FILE TRANSFER - //fClientReceivedAllFiles = FALSE; - client->AttachPlugin(&fltClient); - client->SetSplitMessageProgressInterval(1); - - CHAR16 tmpMessage[512]; - swprintf( tmpMessage, MPClientMessage[1],SERVER_IP ); - ScreenMsg( FONT_BEIGE, MSG_MPSYSTEM, tmpMessage); // we are connecting - SetConnectScreenSubMessageW( tmpMessage ); - - - client->Connect(SERVER_IP, atoi(SERVER_PORT), 0,0); - is_connecting=true; - -#ifdef JA2BETAVERSION - MPDebugMsg( String ( "connect_client()\n" ) ); -#endif - - - - } - - else if (is_connecting) - { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[4] ); - } - else if (is_connected) - { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[3] ); - } + CHAR16 tmpMessage[512]; + swprintf( tmpMessage, MPClientMessage[1],serverIP ); + ScreenMsg( FONT_BEIGE, MSG_MPSYSTEM, tmpMessage); // we are connecting + SetConnectScreenSubMessageW( tmpMessage ); + client->Connect(serverIP, serverPort, 0,0); + is_connecting = true; + } + else if (is_connecting) + { + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[4] ); + } + else if (is_connected) + { + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[3] ); + } } void client_packet ( void ) { - Packet* p; - if (is_client) { - p = client->Receive(); while(p) { - //continue; // Didn't get any packets - // We got a packet, get the identifier with our handy function packetIdentifier = GetPacketIdentifier(p); - //ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"packet recieved"); + // Check if this is a network message packet switch (packetIdentifier) { @@ -5406,6 +4852,7 @@ void client_packet ( void ) } } } + // Copied from Multiplayer.cpp // If the first byte is ID_TIMESTAMP, then we want the 5th byte // Otherwise we want the 1st byte @@ -5436,14 +4883,13 @@ void client_disconnect (void) is_connecting=false; fileTransferProgress = 0; - - allowlaptop=false; + TEAM=0; + // Reset fast loading of WWW pages gfTemporaryDisablingOfLoadPendingFlag = FALSE; - // clear local client cache memset(client_names,0,sizeof(char)*4*30); memset(client_edges,0,sizeof(int)*5); @@ -5452,15 +4898,11 @@ void client_disconnect (void) memset(gMPPlayerStats,0,sizeof(player_stats)*5); memset(random_mercs,0,sizeof(int)*7); memset ( &client_downloading,0,sizeof(int)*4); - memset ( &client_progress,0,sizeof(int)*4); - TEAM=0; - - - + memset ( &client_progress,0,sizeof(int)*4); // We're done with the network RakNetworkFactory::DestroyRakPeerInterface(client); - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"client disconnected and shutdown"); + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[77]); #ifdef JA2BETAVERSION MPDebugMsg( "client_disconnect()\n" ); @@ -5468,7 +4910,7 @@ void client_disconnect (void) } else { - ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, L"client is not running"); + ScreenMsg( FONT_LTGREEN, MSG_MPSYSTEM, MPClientMessage[78]); } } @@ -5489,9 +4931,7 @@ void send_edgechange(int newedge) fDrawCharacterList = true; fTeamPanelDirty = true; client_edges[CLIENT_NUM-1] =newedge; - // store the setting locally - _itoa(newedge,SECT_EDGE,10); - + cStartingSectorEdge = newedge; } else { @@ -5501,7 +4941,7 @@ void send_edgechange(int newedge) bool can_edgechange() { - return (is_game_started != 1 && client_ready[CLIENT_NUM-1] == 0 && !allowlaptop && !RANDOM_SPAWN); + return (is_game_started != 1 && client_ready[CLIENT_NUM-1] == 0 && !allowlaptop && !gRandomStartingEdge); } //OJW - 20081204 - send a starting team change to all the clients @@ -5522,7 +4962,6 @@ void send_teamchange(int newteam) fTeamPanelDirty = true; client_teams[lan.client_num-1] = lan.newteam; TEAM = newteam; - } else { @@ -5534,7 +4973,7 @@ bool can_teamchange() { bool isGeneralTeamchangeValid = (is_game_started != 1 && client_ready[CLIENT_NUM-1] == 0 && !allowlaptop); - if (isGeneralTeamchangeValid && PLAYER_BSIDE == MP_TYPE_TEAMDEATMATCH) + if (isGeneralTeamchangeValid && cGameType == MP_TYPE_TEAMDEATMATCH) return TRUE; else return FALSE; @@ -5556,10 +4995,10 @@ void ChatCallback( UINT8 ubResult ) chat_msg cmsg; wchar_t szPlayerName[30]; memset(szPlayerName,0,30*sizeof(wchar_t)); - mbstowcs( szPlayerName,CLIENT_NAME,30); + mbstowcs( szPlayerName,cClientName,30); cmsg.bToAll = gbChatSendToAll; - if (PLAYER_BSIDE==1 && !cmsg.bToAll) + if (cGameType==MP_TYPE_TEAMDEATMATCH && !cmsg.bToAll) swprintf(cmsg.msg,MPClientMessage[56], szPlayerName, gszChatBoxInputString); else swprintf(cmsg.msg,MPClientMessage[52], szPlayerName, gszChatBoxInputString); @@ -5575,5 +5014,4 @@ void ChatCallback( UINT8 ubResult ) void OpenChatMsgBox( void ) { DoChatBox((guiCurrentScreen == GAME_SCREEN? true : false),gzMPChatboxText[1],guiCurrentScreen,ChatCallback,NULL); -} - +} \ No newline at end of file diff --git a/Multiplayer/connect.h b/Multiplayer/connect.h index 73fda315..629a1a64 100644 --- a/Multiplayer/connect.h +++ b/Multiplayer/connect.h @@ -4,6 +4,7 @@ #include "Soldier Init List.h" #include "Merc Hiring.h" #include "event pump.h" +#include "Bullets.h" extern bool isOwnTeamWipedOut; @@ -20,34 +21,32 @@ extern bool recieved_transfer_settings; extern INT16 serverSyncClientsDirectory; extern int PLAYER_TEAM_TIMER_SEC_PER_TICKS; - -//extern char CLIENT_NUM[30]; extern int CLIENT_NUM; -extern int ENEMY_ENABLED; -extern int CREATURE_ENABLED; -extern int MILITIA_ENABLED; -extern int CIV_ENABLED; +extern UINT8 gEnemyEnabled; +extern UINT8 gCreatureEnabled; +extern UINT8 gMilitiaEnabled; +extern UINT8 gCivEnabled; -extern int MAX_CLIENTS; -extern int SAME_MERC; -extern int PLAYER_BSIDE; +extern UINT8 cMaxClients; +extern UINT8 cSameMercAllowed; +extern UINT8 cGameType; extern bool allowlaptop; extern UINT8 netbTeam; extern UINT8 ubID_prefix; -extern FLOAT DAMAGE_MULTIPLIER; +extern FLOAT cDamageMultiplier; //OJW - 20081218 -extern int RANDOM_SPAWN; -extern int RANDOM_MERCS; +extern UINT8 gRandomStartingEdge; +extern UINT8 gRandomMercs; //OJW - 20090317 extern bool is_game_started; //OJW - 20090403 -extern int OVERRIDE_MAX_AI; +extern UINT8 gMaxEnemiesEnabled; //OJW - 20090405 extern STRING512 gCurrentTransferFilename; @@ -58,17 +57,15 @@ extern UINT32 crate_usMapPos; //extern int INTERRUPTS; -extern int ALLOW_EQUIP; +extern UINT8 cAllowMercEquipment; -extern INT32 MAX_MERCS; +extern UINT8 cMaxMercs; void lockui (bool unlock); void start_battle ( void ); void DropOffItemsInSector( UINT8 ubOrderNum ); -void test_func2 ( void ); - void mp_help (void); void mp_help2 (void); void grid_display ( void); @@ -97,7 +94,7 @@ void send_stance ( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance ); void send_dir ( SOLDIERTYPE *pSoldier, UINT16 usDesiredDirection ); void send_fire( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ); void send_hit( EV_S_WEAPONHIT *SWeaponHit ); - +void send_bullet( BULLET * pBullet, UINT16 usHandItem); void send_hire( UINT8 iNewIndex, UINT8 ubCurrentSoldier, INT16 iTotalContractLength, BOOLEAN fCopyProfileItemsOver); void send_dismiss( UINT8 ubCurrentSoldier); @@ -125,6 +122,8 @@ void send_disarm_explosive(UINT32 sGridNo, UINT32 uiWorldIndex, UINT8 ubID); void OpenChatMsgBox(void); +INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ); + void reapplySETTINGS(); BOOLEAN CheckConditionsForBattle( GROUP *pGroup ); // this comes from strategic movement.cpp @@ -140,10 +139,11 @@ extern int client_edges[5]; extern int client_downloading[4]; extern int client_progress[4]; -extern char SERVER_NAME[30]; +extern char cServerName[30]; //OJW - 20081224 #define MAX_CONNECT_RETRIES 5 +#define ENABLE_COLLISION (is_server && pBullet->pFirer->ubID<120) || (!is_server && is_client && pBullet->pFirer->ubID<20) || (!is_server && !is_client) extern bool auto_retry; extern int giNumTries; diff --git a/Multiplayer/fresh_header.h b/Multiplayer/fresh_header.h index e60fc41f..353b3543 100644 --- a/Multiplayer/fresh_header.h +++ b/Multiplayer/fresh_header.h @@ -1,9 +1,7 @@ #pragma once //time for a new header :) - extern int readyteamreg[10]; - extern bool NOGEAR; typedef struct @@ -23,70 +21,49 @@ typedef struct typedef struct { -UINT16 ubID; -INT8 bLife; -INT8 bBleeding; + UINT16 ubID; + INT8 bLife; + INT8 bBleeding; }heal; typedef struct { UINT16 ubID; INT8 bteam; - }AIint; +extern BOOLEAN gfUIInterfaceSetBusy; +extern int numreadyteams;//for realtime +extern bool requested; +extern bool getReal; +extern UINT8 gubCheatLevel; + +// Client variables +extern UINT8 cWeaponReadyBonus; +extern UINT8 cDisableSpectatorMode; +extern UINT8 cDisableMorale; + BOOLEAN DisplayMercsInventory(UINT8 ubMercID); void send_door ( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fNoAnimations ); - void send_changestate (EV_S_CHANGESTATE * SChangeState); - void send_death( SOLDIERTYPE *pSoldier); - void send_hitstruct(EV_S_STRUCTUREHIT * SStructureHit); void send_hitwindow(EV_S_WINDOWHIT * SWindowHit); -void send_miss(EV_S_MISS * SMiss); - -void cheat_func(void); -//void start_tt(void); +void send_miss(EV_S_MISS * SMiss); void unlock (void); - void UpdateSoldierToNetwork ( SOLDIERTYPE *pSoldier ); - -extern BOOLEAN gfUIInterfaceSetBusy; void TrashAllSoldiers( ); - void kick_player (void); void overide_turn (void); - -extern bool DISABLE_MORALE; - void send_fireweapon ( EV_S_FIREWEAPON * SFireWeapon); - void end_interrupt ( BOOLEAN fMarkInterruptOccurred ); void EndInterrupt( BOOLEAN fMarkInterruptOccurred ); void sendRT (void); - -extern int numreadyteams;//for realtime - -extern bool requested; -extern bool getReal; - -extern UINT8 gubCheatLevel; - void startCombat(UINT8 ubStartingTeam); - -extern int WEAPON_READIED_BONUS; - void intAI (SOLDIERTYPE *pSoldier ); - void teamwiped (void); - BOOLEAN check_status (void); extern UINT8 NumEnemyInSector( ); extern INT8 NumActiveAndConsciousTeamMembers( UINT8 ubTeam ); - void send_heal (SOLDIERTYPE *pSoldier ); - -extern int DISABLE_SPEC_MODE; - void requestAIint(SOLDIERTYPE *pSoldier ); \ No newline at end of file diff --git a/Multiplayer/network.h b/Multiplayer/network.h index 955160e3..c801e157 100644 --- a/Multiplayer/network.h +++ b/Multiplayer/network.h @@ -3,17 +3,43 @@ #include "random.h" //this one just for structs, variables and functions used between the client and server scripts... - -extern char CLIENT_NAME[30]; -extern char SERVER_NAME[30]; +extern char cClientName[30]; +extern char cServerName[30]; extern bool Sawarded; - -//extern char *fileToSend; extern unsigned int setID; -//extern char *fileToSendCopy; +// ja2_mp.ini: File +#define JA2MP_INI_FILENAME "ja2_mp.ini" +// "ja2_mp.ini: Sections +#define JA2MP_INI_INITIAL_SECTION "JA2 Multiplayer Initial Settings" +#define JA2MP_INI_SERVER_SECTION "JA2 Multiplayer Servers" +// ja2_mp.ini: Properties +#define JA2MP_ALLOW_CUSTOM_NIV "INVENTORY_ATTACHMENTS" +#define JA2MP_CIV_ENABLED "ENABLE_CIVILIANS_IN_COOP" +#define JA2MP_CLIENT_NAME "PLAYER_NAME" +#define JA2MP_DAMAGE_MULTIPLIER "WEAPON_DAMAGE" +#define JA2MP_DIFFICULT_LEVEL "DIFFICULTY_LEVEL" +#define JA2MP_DISABLE_BOBBY_RAYS "BOBBY_RAYS" +#define JA2MP_FILE_TRANSFER_DIRECTORY "GAME_DATA_SYNC_DIRECTORY" +#define JA2MP_GAME_MODE "GAME_TYPE" +#define JA2MP_KIT_BAG "KIT_BAG" +#define JA2MP_MAX_CLIENTS "MAX_PLAYERS" +#define JA2MP_MAX_MERCS "MAX_MERCS" +#define JA2MP_OVERRIDE_MAX_AI "MAX_ENEMIES_IN_COOP" +#define JA2MP_RANDOM_EDGES "STARTING_SECTOR_EDGE" +#define JA2MP_RANDOM_MERCS "HIRE_MERCS_METHOD" +#define JA2MP_REPORT_NAME "REPORT_HIRED_MERC_NAME" +#define JA2MP_SAME_MERC "SAME_MERC_ALLOWED" +#define JA2MP_SERVER_IP "SERVER_IP" +#define JA2MP_SERVER_NAME "SERVER_NAME" +#define JA2MP_SERVER_PORT "SERVER_PORT" +#define JA2MP_STARTING_BALANCE "STARTING_CASH" +#define JA2MP_SYNC_CLIENTS_MP_DIR "SYNC_GAME_DIRECTORY" +#define JA2MP_TIMED_TURN_SECS_PER_TICK "TIMED_TURNS" +#define JA2MP_TIME "STARTING_TIME" +#define JA2MP_NEW_TRAITS "SKILL_TRAITS" typedef struct { @@ -26,60 +52,56 @@ typedef struct typedef struct { - int max_clients; - int same_merc; - float damage_multiplier; - INT16 gsMercArriveSectorX; - INT16 gsMercArriveSectorY; - int ENEMY_ENABLED; - int CREATURE_ENABLED; - int MILITIA_ENABLED; - int CIV_ENABLED; - int gsPLAYER_BSIDE; - INT32 secs_per_tick; - INT32 starting_balance; - bool soDis_Bobby; - bool soDis_Equip; + UINT8 maxClients; + UINT8 sameMercAllowed; + float damageMultiplier; + INT16 gsMercArriveSectorX; + INT16 gsMercArriveSectorY; + UINT8 enemyEnabled; + UINT8 creatureEnabled; + UINT8 militiaEnabled; + UINT8 civEnabled; + UINT8 gameType; + INT32 secondsPerTick; + INT32 startingCash; + UINT8 disableBobbyRay; + UINT8 disableMercEquipment; BOOLEAN sofGunNut; UINT8 soubGameStyle; UINT8 soubDifficultyLevel; + UINT8 soubSkillTraits; BOOLEAN sofTurnTimeLimit; BOOLEAN sofIronManMode; - UINT8 soubBobbyRay; - BOOLEAN sofNewInv; - INT32 gsMAX_MERCS; - UINT8 client_num; - char client_name[30]; - char client_names[4][30]; - // OJW - added 20081204 - int client_edges[5]; - int client_teams[4]; - char server_name[30]; - //int cl_ops[4]; - int team; - int TESTING; - char kitbag[100]; - bool emorale; - int gsREPORT_NAME; - int cl_edge; - float TIME; - int WEAPON_READIED_BONUS; - int ALLOW_CUSTOM_NIV; - int DISABLE_SPEC_MODE; + UINT8 soubBobbyRay; + UINT8 maxMercs; + UINT8 client_num; + char client_name[30]; + char client_names[4][30]; + int client_edges[5]; + int client_teams[4]; + char server_name[30]; + int team; + char kitBag[100]; + UINT8 disableMorale; + UINT8 reportHiredMerc; + UINT8 startingSectorEdge; + float startingTime; + UINT8 weaponReadyBonus; + UINT8 inventoryAttachment; + UINT8 disableSpectatorMode; // OJW - added 20081220 - int RANDOM_SPAWN; - int RANDOM_MERCS; - int random_mercs[7]; - char server_version[30]; + UINT8 randomStartingEdge; + UINT8 randomMercs; + int random_mercs[7]; + char server_version[30]; // OJW - added 20091024 - UINT32 random_table[MAX_PREGENERATED_NUMS]; + UINT32 random_table[MAX_PREGENERATED_NUMS]; } settings_struct; // WANNE: FILE TRANSFER typedef struct { - STRING512 fileTransferDirectory; - //char fileTransferDirectory[600]; // The file transfer directory path from the server + STRING512 fileTransferDirectory; int syncClientsDirectory; // Does the server want to sync files to the clients char serverName[30]; // The name of the server. This is used on the client side as a folder inside the client transfer directory long totalTransferBytes; @@ -90,7 +112,7 @@ typedef struct { INT16 gsMercArriveSectorX; INT16 gsMercArriveSectorY; - float TIME; + float startingTime; } mapchange_struct; typedef struct @@ -112,18 +134,6 @@ typedef struct UINT8 downloading; } progress_struct; -//typedef struct -//{ -// int clnum; -// UINT8 ubid; -//}ovh_struct; -// -//typedef struct -//{ -// UINT8 ubid; -//}adv; - - typedef struct { BOOLEAN fMarkInterruptOccurred; @@ -142,3 +152,10 @@ typedef struct UINT8 ubStartingTeam; }sc_struct; +namespace ja2 +{ + namespace mp + { + void InitializeMultiplayerProfile(vfs::Path const& profileRoot); + } +} \ No newline at end of file diff --git a/Multiplayer/server.cpp b/Multiplayer/server.cpp index ebb8e42e..70503b4a 100644 --- a/Multiplayer/server.cpp +++ b/Multiplayer/server.cpp @@ -1,18 +1,14 @@ - #include "MessageIdentifiers.h" #include "RakNetworkFactory.h" #include "RakPeerInterface.h" #include "RakNetStatistics.h" #include "RakNetTypes.h" - - #include "FileListTransfer.h" #include "FileListTransferCBInterface.h" #include "FileOperations.h" #include "SuperFastHash.h" #include "RakAssert.h" #include "IncrementalReadInterface.h" - #include "BitStream.h" #include "RakSleep.h" #include @@ -23,29 +19,22 @@ #include #include #include - #include "connect.h" - #include "types.h" #include "gamesettings.h" #include "message.h" #include "FileMan.h" - #include "IniReader.h" -#include "VFS/vfs.h" -#include "VFS/Tools/ParserTools.h" +#include +#include "transfer_rules.h" #include "MPJoinScreen.h" - #include "game init.h" - #include "text.h" #include "network.h" - #include "message.h" #include "overhead.h" #include "fresh_header.h" #include "Debug Control.h" - #include "MPXmlTeams.hpp" extern CHAR16 gzFileTransferDirectory[100]; @@ -80,51 +69,41 @@ class ServerFileListProgress : public FileListProgress } } serverFileListProgress; - - -char kbag[100]; -char net_div[30]; -INT32 gsMAX_MERCS; -bool gsMORALE; -int gsREPORT_NAME; - +// ------------------------------ +// Global Server Variables from ja2_mp.ini +// ------------------------------ +char gKitBag[100]; +UINT8 gMaxMercs; +UINT8 gDisableMorale; +UINT8 gReportHiredMerc; +UINT8 gDisableBobbyRay; +UINT8 gDisableMercEquipment; +UINT8 gSameMercAllowed; +float gDamageMultiplier; +UINT8 gMaxClients ; +UINT8 gGameType; +UINT8 gDifficultyLevel; +UINT8 gSkillTraits; +UINT8 gSyncGameDirectory; +INT32 gSecondsPerTick; +INT32 gStartingCash; +float gStartingTime; +UINT8 gWeaponReadyBonus; +UINT8 gInventoryAttachment; +UINT8 gDisableSpectatorMode; +UINT8 gMaxEnemiesEnabled; +// ------------------------------ UINT16 nc; //number of open connection UINT16 ncr; //number of ready confirmed connections //something keep record of ready connections .. int mercs_ready[255]; -bool gsDis_Bobby; -bool gsDis_Equip; - -int gsSAME_MERC; -float gsDAMAGE_MULTIPLIER; -int gsINTERRUPTS ; -int gsMAX_CLIENTS ; -int gsPLAYER_BSIDE; -int gsTESTING; -int gsDIFFICULT_LEVEL; -char gsFILE_TRANSFER_DIRECTORY_SERVER[100]; - -int gsSYNC_CLIENTS_MP_DIR; - -INT32 gssecs_per_tick; -INT32 gsstarting_balance; -float TIME; -int sWEAPON_READIED_BONUS; -int sALLOW_CUSTOM_NIV; -int sDISABLE_SPEC_MODE; - -// OJW - 20090403 - override max enemies for co-op -int OVERRIDE_MAX_AI; - unsigned char SGetPacketIdentifier(Packet *p); unsigned char SpacketIdentifier; RakPeerInterface *server; - - // WANNE: FILE TRANSFER FileListTransfer fltServer; // flt1 IncrementalReadInterface incrementalReadInterface; @@ -132,8 +111,6 @@ FileList fileList; // OJW - 20090405 long fileListTotalBytes=0; - - int numreadyteams; int readyteamreg[10]; @@ -149,21 +126,6 @@ typedef struct }client_data; client_data client_d[4]; - -// OJW - 20081223 -// Random Merc teams -// First attempt at "balanced" teams -// moved to mpxmlteams.cpp -/* -int random_merc_teams[4][7] = -{ - { 16, 10, 19, 25, 4 , 11, 39 } , // Gus , Shadow, Spider , Raven , Vicki , Red , Meltdown - { 29, 36, 28, 2 , 22, 8 , 32 } , // Magic , Scope, Danny , Lynx , Hitman , Steroid , Malice - { 12, 5 , 20, 23, 48, 34, 17 } , // Reaper , Trevor, Cliff , Buzz , Cougar , Nails , Buns - { 31, 7 , 33, 35, 27, 37, 1 } // Scully , Ivan , Dr Q , Thor , Len , Wolf , Blood -}; -*/ - int client_mercteam[4] = { 0 , 1 , 2 , 3 }; // random index of random_merc_teams per player bool inline can_joingame(); @@ -535,27 +497,6 @@ void receiveSETID(RPCParameters *rpcParameters) fltServer.Send(&fileList,server,rpcParameters->sender,setID,MEDIUM_PRIORITY,0,false, &incrementalReadInterface, 5000); } -//void sendALLFILESRECEIVED(RPCParameters *rpcParameters) -//{ -// ScreenMsg( FONT_BCOLOR_ORANGE, MSG_MPSYSTEM, L"%S", rpcParameters->input); -//} - - -// -//void rINT(RPCParameters *rpcParameters)//who is first -//{ -// -// AIint* data = (AIint*)rpcParameters->input; -// -// if( !Sawarded ) -// { -// PauseAITemporarily(); -// Sawarded=true; -// //send back to sender -// server->RPC("awardINT",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, rpcParameters->sender, false, 0, UNASSIGNED_NETWORK_ID,0); -// } -//} - void startCOMBAT(RPCParameters *rpcParameters) { if(!( gTacticalStatus.uiFlags & INCOMBAT )) @@ -570,43 +511,38 @@ void startCOMBAT(RPCParameters *rpcParameters) } - - - - void sendREAL(RPCParameters *rpcParameters) { real_struct* rData = (real_struct*)rpcParameters->input; - - - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"netbTeam %d is ready for realtime",rData->bteam );//diabled unless testing as cheats if(readyteamreg[rData->bteam]==0) { readyteamreg[rData->bteam]=1;//register vote, to prevent double voting ;p~ //hayden numreadyteams++; - int numactiveteams=0; - int b; - for(int i=6;i<=LAST_TEAM;i++) - { - if(i==6)b=0; - else b=i; + int numactiveteams=0; + int b; + for(int i=6;i<=LAST_TEAM;i++) + { + if(i==6) + b=0; + else + b=i; - if(gTacticalStatus.Team[ b ].bTeamActive)numactiveteams++; + if(gTacticalStatus.Team[ b ].bTeamActive) + numactiveteams++; + } - }//same - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPServerMessage[5], numreadyteams, numactiveteams ); - //check # clients ready for realtime - if (numreadyteams >= numactiveteams) - { - //if all send notification for realtime changeover - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"Switching to realtime..." ); - numreadyteams=0; - memset( &readyteamreg , 0 , sizeof (int) * 10); + //check # clients ready for realtime + if (numreadyteams >= numactiveteams) + { + //if all send notification for realtime changeover + //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"Switching to realtime..." ); + numreadyteams=0; + memset( &readyteamreg , 0 , sizeof (int) * 10); - server->RPC("gotoRT",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } + server->RPC("gotoRT",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); + } } } @@ -623,9 +559,6 @@ void sendCHATMSG(RPCParameters *rpcParameters) server->RPC("recieveCHATMSG",(const char*)rpcParameters->input, (*rpcParameters).numberOfBitsOfData, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } - - - // OJW - 20081223 // fix client disconnecting mid game, allowing the game to proceed void HandleDisconnect(SystemAddress sender) @@ -666,7 +599,7 @@ void rSortArray(int* arr, int len) { int iRandPos = rand() % tmpList.size(); for(Iter = tmpList.begin(); iRandPos>0; iRandPos--, Iter++); - //Iter += iRandPos; + shuffledList.push_front(*Iter); tmpList.erase(Iter); } @@ -683,37 +616,18 @@ void rSortArray(int* arr, int len) void requestFILE_TRANSFER_SETTINGS(RPCParameters *rpcParameters) { SystemAddress sender = rpcParameters->sender;//get senders address -#ifndef USE_VFS - STRING512 executableDir; - GetExecutableDirectory(executableDir); - STRING512 fileTransferDir; - strcpy(fileTransferDir, executableDir); - strcat(fileTransferDir, "\\"); - strcat(fileTransferDir, gsFILE_TRANSFER_DIRECTORY_SERVER); - - // Replace all "/" with "\" from the server path - char* correctFileTransferDir = ReplaceCharactersInString_Server(fileTransferDir, "/", "\\"); - filetransfersettings_struct fts; - fts.syncClientsDirectory = gsSYNC_CLIENTS_MP_DIR; - strcpy(fts.fileTransferDirectory, correctFileTransferDir); - strcpy(fts.serverName, SERVER_NAME); - fts.totalTransferBytes = fileListTotalBytes; -#else - filetransfersettings_struct fts; - - fts.syncClientsDirectory = gsSYNC_CLIENTS_MP_DIR; + fts.syncClientsDirectory = gSyncGameDirectory; strcpy(fts.fileTransferDirectory, s_ServerId.getServerId(vfs::Path(gzFileTransferDirectory)).utf8().c_str()); - strcpy(fts.serverName, SERVER_NAME); + strcpy(fts.serverName, cServerName); fts.totalTransferBytes = fileListTotalBytes; -#endif + // OJW - 200907819 - Only send to the client that asked for it server->RPC("recieveFILE_TRANSFER_SETTINGS",(const char*)&fts, (int)sizeof(filetransfersettings_struct)*8, HIGH_PRIORITY, RELIABLE, 0, sender, false, 0, UNASSIGNED_NETWORK_ID,0); } - //************************* //UNASSIGNED_SYSTEM_ADDRESS //START INTERNAL SERVER //************************* @@ -741,11 +655,7 @@ void requestSETTINGS(RPCParameters *rpcParameters ) server->CloseConnection(rpcParameters->sender, true); return; } - - // WANNE: FILE TRANSFER: A client connected -> start the file transfer! - if (gsSYNC_CLIENTS_MP_DIR) - requestSETID(rpcParameters->sender); - + //server assigned client numbers - hayden. SystemAddress sender = rpcParameters->sender;//get senders address int bslot = f_rec_num(0,blank);//get empty record slot @@ -753,105 +663,107 @@ void requestSETTINGS(RPCParameters *rpcParameters ) int new_cl_num = bslot+1;//client number to assign client_d[bslot].cl_number=new_cl_num; //record clients number - settings_struct lan; - - //lan.client_num = clinf->client_num;//old client assigned number + lan.client_num = new_cl_num; //new server assigned number strcpy(lan.client_name , clinf->client_name); - lan.RANDOM_SPAWN = RANDOM_SPAWN; - lan.RANDOM_MERCS = RANDOM_MERCS; + lan.randomStartingEdge = gRandomStartingEdge; + lan.randomMercs = gRandomMercs; - lan.max_clients = gsMAX_CLIENTS; - memcpy(lan.kitbag , kbag,sizeof (char)*100); - lan.damage_multiplier = gsDAMAGE_MULTIPLIER; + lan.maxClients = gMaxClients; + memcpy(lan.kitBag , gKitBag,sizeof (char)*100); + lan.damageMultiplier = gDamageMultiplier; - lan.same_merc = gsSAME_MERC; + lan.sameMercAllowed = gSameMercAllowed; lan.gsMercArriveSectorX=gsMercArriveSectorX; lan.gsMercArriveSectorY=gsMercArriveSectorY; - lan.ENEMY_ENABLED=ENEMY_ENABLED; - lan.CREATURE_ENABLED=CREATURE_ENABLED; - lan.MILITIA_ENABLED=MILITIA_ENABLED; - lan.CIV_ENABLED=CIV_ENABLED; + lan.enemyEnabled = gEnemyEnabled; + lan.creatureEnabled = gCreatureEnabled; + lan.militiaEnabled = gMilitiaEnabled; + lan.civEnabled = gCivEnabled; - lan.gsPLAYER_BSIDE=gsPLAYER_BSIDE; + lan.gameType=gGameType; - lan.emorale=gsMORALE; - lan.gsREPORT_NAME=gsREPORT_NAME; -//something new - lan.secs_per_tick=gssecs_per_tick; + lan.disableMorale=gDisableMorale; + lan.reportHiredMerc=gReportHiredMerc; + lan.secondsPerTick = gSecondsPerTick; lan.soubBobbyRay=gGameOptions.ubBobbyRay; lan.sofGunNut=gGameOptions.fGunNut; lan.soubGameStyle=gGameOptions.ubGameStyle; - lan.soubDifficultyLevel=gsDIFFICULT_LEVEL; + lan.soubDifficultyLevel=gDifficultyLevel; + lan.soubSkillTraits=gSkillTraits; lan.sofTurnTimeLimit=gGameOptions.fTurnTimeLimit; lan.sofIronManMode=gGameOptions.fIronManMode; - lan.starting_balance=gsstarting_balance; - - // OJW - 20090319 - Changing allow custom NIV to force NIV on all clients - // as with the new join screen setup, no way for the individual client to choose - // whether or not to use NIV. If this is wrong, its easily fixed... - // just change description text for the toggle option on the host screen to - // "Allow custom inventory" and delete this if statement. - if (sALLOW_CUSTOM_NIV==1 && IsNIVModeValid(true)) - gGameOptions.ubInventorySystem = INVENTORY_NEW; - else - gGameOptions.ubInventorySystem = INVENTORY_OLD; + lan.startingCash = gStartingCash; - lan.sofNewInv=gGameOptions.ubInventorySystem; + // Old/Old + if (gInventoryAttachment == INVENTORY_OLD) + { + lan.inventoryAttachment = 0; + } + else + { + // New/Old + if (gGameOptions.ubAttachmentSystem == ATTACHMENT_OLD) + { + lan.inventoryAttachment = 1; // New/Old + } + // New/New + else + { + lan.inventoryAttachment = 2; // New/New + } + } + + lan.disableBobbyRay=gDisableBobbyRay; + lan.disableMercEquipment=gDisableMercEquipment; - lan.soDis_Bobby=gsDis_Bobby; - lan.soDis_Equip=gsDis_Equip; - - lan.gsMAX_MERCS=gsMAX_MERCS; + lan.maxMercs = gMaxMercs; memcpy( lan.client_names , client_names, sizeof( char ) * 4 * 30 ); lan.team=clinf->team; // OJW - 20090530 - fix teams not initialised properly client_teams[ lan.client_num - 1 ] = lan.team; - - lan.TESTING=gsTESTING; - + // OJW - 20081218 - if (RANDOM_SPAWN) + if (gRandomStartingEdge) { // Get the edge from the randomized "client_edges" - lan.cl_edge = client_edges[lan.client_num-1]; + lan.startingSectorEdge = client_edges[lan.client_num-1]; } else { // WANNE: on DM, each client should get a unique starting edge per default - if (gsPLAYER_BSIDE == MP_TYPE_DEATHMATCH || gsPLAYER_BSIDE == MP_TYPE_TEAMDEATMATCH) + if (gGameType == MP_TYPE_DEATHMATCH || gGameType == MP_TYPE_TEAMDEATMATCH) { client_edges[0] = MP_EDGE_NORTH; // client 1 client_edges[1] = MP_EDGE_SOUTH; // client 2 client_edges[2] = MP_EDGE_EAST; // client 3 client_edges[3] = MP_EDGE_WEST; // client 4 - lan.cl_edge = client_edges[lan.client_num-1]; + lan.startingSectorEdge = client_edges[lan.client_num-1]; } else { - lan.cl_edge=clinf->cl_edge; + lan.startingSectorEdge=clinf->cl_edge; } } // OJW - 20081223 - if (RANDOM_MERCS) - { - //memcpy(lan.random_mercs, random_merc_teams[client_mercteam[lan.client_num - 1]], sizeof(int) * 7); + if (gRandomMercs) + { mpTeams.SerializeProfiles(lan.random_mercs); } - lan.TIME=TIME; - lan.WEAPON_READIED_BONUS=sWEAPON_READIED_BONUS; - lan.ALLOW_CUSTOM_NIV=sALLOW_CUSTOM_NIV; - lan.DISABLE_SPEC_MODE=sDISABLE_SPEC_MODE; + lan.startingTime = gStartingTime; + lan.weaponReadyBonus = gWeaponReadyBonus; + lan.inventoryAttachment = gInventoryAttachment; + lan.disableSpectatorMode = gDisableSpectatorMode; // OJW - 20081204 - strcpy(lan.server_name , SERVER_NAME); + strcpy(lan.server_name , cServerName); memcpy(lan.client_edges,client_edges,sizeof(int)*5); memcpy(lan.client_teams,client_teams,sizeof(int)*4); @@ -864,7 +776,10 @@ void requestSETTINGS(RPCParameters *rpcParameters ) server->RPC("recieveSETTINGS",(const char*)&lan, (int)sizeof(settings_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); - } // end if(can_joingame) + // WANNE: FILE TRANSFER: A client connected -> start the file transfer! + if (gSyncGameDirectory) + requestSETID(rpcParameters->sender); + } } // added 081201 by Owen , allow the server to change the map while its still not in laptop mode @@ -876,7 +791,7 @@ void send_mapchange(void) lan.gsMercArriveSectorX=gsMercArriveSectorX; lan.gsMercArriveSectorY=gsMercArriveSectorY; - lan.TIME=TIME; + lan.startingTime = gStartingTime; server->RPC("recieveMAPCHANGE",(const char*)&lan, (int)sizeof(mapchange_struct)*8, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID,0); } @@ -909,53 +824,6 @@ void CheckIncomingConnection(Packet* p) void AddFilesToSendList() { -#ifndef USE_VFS - STRING512 executableDir; - GetExecutableDirectory(executableDir); - - HANDLE hFileIn; - HCONTAINER hStack = CreateStack( 100000, 600 ); - WIN32_FIND_DATA find, inFind; - - find.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY; - inFind.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY; - - STRING512 fileTransferDir; - strcpy(fileTransferDir, executableDir); - - // WANNE: Build the complete file transfer directory for the server - strcat(fileTransferDir, "\\"); - strcat(fileTransferDir, gsFILE_TRANSFER_DIRECTORY_SERVER); - - char* correctFileTransferDir = ReplaceCharactersInString_Server(fileTransferDir, "/", "\\"); - if (DirectoryExists(correctFileTransferDir)) - { - strcat(correctFileTransferDir, "\\*.*"); - - hFileIn = FindFirstFile( correctFileTransferDir, &inFind ); - - // Get all files (recursive) inside the folder "cSubDir" == FILE_TRANSFER_DIR_SERVER - INT32 iNumFiles = GetFilesInDirectory( hStack, correctFileTransferDir, hFileIn, &inFind ); - - CHAR filename[600]; - INT32 i; - for ( i=0 ; igetProfileStack(); @@ -969,7 +837,7 @@ void AddFilesToSendList() CTransferRules transferRules; transferRules.initFromTxtFile("transfer_rules.txt"); vfs::IBaseLocation* loc = prof->getLocation(""); - THROWIFFALSE(loc != NULL, "MP profile was successfully created, but the root directory is not included"); + SGP_THROW_IFFALSE(loc != NULL, "MP profile was successfully created, but the root directory is not included"); vfs::IBaseLocation::Iterator it = loc->begin(); int i=0; for(; !it.end(); it.next(), i++) @@ -990,269 +858,167 @@ void AddFilesToSendList() std::vector data(fsize,0); rfile->read(&data[0], fsize); rfile->close(); - fileList.AddFile(utf8string::as_utf8(valid_path()).c_str(),&data[0], fsize,fsize,FileListNodeContext(0,0), false); + fileList.AddFile(vfs::String::as_utf8(valid_path()).c_str(),&data[0], fsize,fsize,FileListNodeContext(0,0), false); } } - } - if(i == 0) - { - // no files? - //char* outputTransferDir = ReplaceCharactersInString_Server(correctFileTransferDir, "\\*.*", ""); - //ScreenMsg( FONT_RED, MSG_MPSYSTEM, L"The Sync. MP Directory '%S' does not exist on the server. Cannot send any files to the clients!", outputTransferDir); - } -#endif + } } void start_server (void) { if(!is_server) { -#ifndef USE_VFS - CIniReader iniReader("..\\Ja2_mp.ini"); -#else - CIniReader iniReader("Ja2_mp.ini"); -#endif - //retrieve settings from .ini - - f_rec_num(1,blank);//wipe clean - //char maxclients[30]; - char port[30]; - char SERVER_PORT[30]; - //char MAX_CLIENTS[30] ; -#ifndef USE_VFS - // GetPrivateProfileString( "Ja2_mp Settings","MAX_CLIENTS", "4", maxclients, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","SERVER_PORT", "60005", port, MAX_PATH, "..\\Ja2_mp.ini" ); - // strcpy( MAX_CLIENTS , maxclients ); - strcpy( SERVER_PORT, port ); -#else - // GetPrivateProfileString( "Ja2_mp Settings","MAX_CLIENTS", "", maxclients, MAX_PATH, "..\\Ja2_mp.ini" ); - strcpy(port, iniReader.ReadString("Ja2_mp Settings","SERVER_PORT", "60005")); - // strcpy( MAX_CLIENTS , maxclients ); - strcpy( SERVER_PORT, port ); -#endif - - char ints[30]; - char maxclients[30]; - - char hire_same_merc[30]; - char bteam1_enabled[30]; - //char bteam2_enabled[30]; - char bteam3_enabled[30]; - char bteam4_enabled[30]; - - char player_bside[30]; - char difficult_level[30]; - - char sBalance[30]; - char time_div[30]; - char mor[30]; - - char sRandomMercs[30]; - char sRandomEdges[30]; - - // OJW - 20081204 -#ifndef USE_VFS - GetPrivateProfileString( "Ja2_mp Settings","SERVER_NAME", "Server Name", SERVER_NAME, MAX_PATH, "..\\Ja2_mp.ini" ); - - GetPrivateProfileString( "Ja2_mp Settings","SAME_MERC", "1", hire_same_merc, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","DISABLE_MORALE", "0", mor, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","MAX_CLIENTS", "4", maxclients, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","DAMAGE_MULTIPLIER", "0.7", net_div, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","RANDOM_MERCS", "0", sRandomMercs, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","RANDOM_EDGES", "0", sRandomEdges, MAX_PATH, "..\\Ja2_mp.ini" ); - - GetPrivateProfileString( "Ja2_mp Settings","ENEMY_ENABLED", "0", bteam1_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); - //GetPrivateProfileString( "Ja2_mp Settings","CREATURE_ENABLED", "0", bteam2_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","MILITIA_ENABLED", "0", bteam3_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","CIV_ENABLED", "0", bteam4_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); - - GetPrivateProfileString( "Ja2_mp Settings","GAME_MODE", "0", player_bside, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","DIFFICULT_LEVEL", "3", difficult_level, MAX_PATH, "..\\Ja2_mp.ini" ); - - // OJW - 20090304 - override max number of ai's in co-op - char sOverrideMaxAI[30]; - OVERRIDE_MAX_AI = 0; - GetPrivateProfileString( "Ja2_mp Settings","OVERRIDE_MAX_AI", "0", sOverrideMaxAI, MAX_PATH, "..\\Ja2_mp.ini" ); - - // WANNE: FILE TRANSFER - GetPrivateProfileString( "Ja2_mp Settings", "FILE_TRANSFER_DIRECTORY", "Data-MP", gsFILE_TRANSFER_DIRECTORY_SERVER, MAX_PATH, "..\\Ja2_mp.ini" ); - - char sendFiles[30]; - GetPrivateProfileString( "Ja2_mp Settings", "SYNC_CLIENTS_MP_DIR", "1", sendFiles, MAX_PATH, "..\\Ja2_mp.ini" ); - gsSYNC_CLIENTS_MP_DIR = atoi(sendFiles); -#else - strncpy(SERVER_NAME, iniReader.ReadString("Ja2_mp Settings","SERVER_NAME", "Server Name"), 30); - - strncpy(hire_same_merc, iniReader.ReadString("Ja2_mp Settings","SAME_MERC", "1"), 30); - strncpy(mor, iniReader.ReadString("Ja2_mp Settings","DISABLE_MORALE", "0"), 30); - strncpy(maxclients, iniReader.ReadString("Ja2_mp Settings","MAX_CLIENTS", "4"), 30); - strncpy(net_div, iniReader.ReadString("Ja2_mp Settings","DAMAGE_MULTIPLIER", "0.7"), 30); - strncpy(sRandomMercs, iniReader.ReadString("Ja2_mp Settings","RANDOM_MERCS", "0"), 30); - strncpy(sRandomEdges, iniReader.ReadString("Ja2_mp Settings","RANDOM_EDGES", "0"), 30); - - strncpy(bteam1_enabled, iniReader.ReadString("Ja2_mp Settings","ENEMY_ENABLED", "0"), 30); - //GetPrivateProfileString( "Ja2_mp Settings","CREATURE_ENABLED", "", bteam2_enabled, MAX_PATH, "..\\Ja2_mp.ini" ); - strncpy(bteam3_enabled, iniReader.ReadString("Ja2_mp Settings","MILITIA_ENABLED", "0"), 30); - strncpy(bteam4_enabled, iniReader.ReadString("Ja2_mp Settings","CIV_ENABLED", "0"), 30); - - strncpy(player_bside, iniReader.ReadString( "Ja2_mp Settings","GAME_MODE", "0"), 30); - strncpy(difficult_level, iniReader.ReadString( "Ja2_mp Settings", "DIFFICULT_LEVEL", "3"), 30); - - // OJW - 20090304 - override max number of ai's in co-op - char sOverrideMaxAI[30]; - OVERRIDE_MAX_AI = 0; - strncpy(sOverrideMaxAI, iniReader.ReadString("Ja2_mp Settings","OVERRIDE_MAX_AI", "0"), 30); - - // WANNE: FILE TRANSFER - strncpy(gsFILE_TRANSFER_DIRECTORY_SERVER, iniReader.ReadString("Ja2_mp Settings", "FILE_TRANSFER_DIRECTORY", "Data-MP"), 100 ); - - char sendFiles[30]; - strncpy(sendFiles, iniReader.ReadString( "Ja2_mp Settings", "SYNC_CLIENTS_MP_DIR", "1"), 30 ); - gsSYNC_CLIENTS_MP_DIR = atoi(sendFiles); - -#endif - gsSYNC_CLIENTS_MP_DIR = atoi(sendFiles); - -//something new - gsMORALE=0; - if(atoi(mor)==1)gsMORALE=1; - -#ifndef USE_VFS - GetPrivateProfileString( "Ja2_mp Settings","KIT_BAG", "[201,214,243]", kbag, MAX_PATH, "..\\Ja2_mp.ini" ); - - char rpn[30]; - GetPrivateProfileString( "Ja2_mp Settings","REPORT_NAME", "1", rpn, MAX_PATH, "..\\Ja2_mp.ini" ); - gsREPORT_NAME=atoi(rpn); - - GetPrivateProfileString( "Ja2_mp Settings","STARTING_BALANCE", "25000", sBalance, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","TIMED_TURN_SECS_PER_TICK", "13.50", time_div, MAX_PATH, "..\\Ja2_mp.ini" ); - - char dis_bob[30]; - char dis_equip[30]; - char max_merc[30]; - char test[30]; - GetPrivateProfileString( "Ja2_mp Settings","DISABLE_BOBBY_RAYS", "", dis_bob, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","DISABLE_AIM_AND_MERC_EQUIP", "", dis_equip, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","MAX_MERCS", "5", max_merc, MAX_PATH, "..\\Ja2_mp.ini" ); - GetPrivateProfileString( "Ja2_mp Settings","TESTING", "0", test, MAX_PATH, "..\\Ja2_mp.ini" ); - gsDis_Bobby=false; - gsDis_Equip=false; -#else - strncpy(kbag, iniReader.ReadString("Ja2_mp Settings","KIT_BAG", "[201,214,243]"), 100); - - char rpn[30]; - strncpy(rpn, iniReader.ReadString("Ja2_mp Settings","REPORT_NAME", "1"), 30); - gsREPORT_NAME=atoi(rpn); - - strncpy(sBalance, iniReader.ReadString("Ja2_mp Settings","STARTING_BALANCE", "25000"), 30); - strncpy(time_div, iniReader.ReadString("Ja2_mp Settings","TIMED_TURN_SECS_PER_TICK", "25"), 30); - - char dis_bob[30]; - char dis_equip[30]; - char max_merc[30]; - char test[30]; - strncpy(dis_bob, iniReader.ReadString("Ja2_mp Settings","DISABLE_BOBBY_RAYS", "0"), 30); - strncpy(dis_equip, iniReader.ReadString("Ja2_mp Settings","DISABLE_AIM_AND_MERC_EQUIP", "0"), 30); - strncpy(max_merc, iniReader.ReadString("Ja2_mp Settings","MAX_MERCS", "5"), 30); - strncpy(test, iniReader.ReadString("Ja2_mp Settings","TESTING", "0"), 30); - gsDis_Bobby=false; - gsDis_Equip=false; -#endif - - if(atoi(dis_bob)==1)gsDis_Bobby=true; - if(atoi(dis_equip)==1)gsDis_Equip=true; - - gsMAX_MERCS=atoi(max_merc); - gsTESTING = atoi(test); - - gsPLAYER_BSIDE = atoi(player_bside); - - gsDIFFICULT_LEVEL = atoi(difficult_level); - ENEMY_ENABLED=0; - CREATURE_ENABLED=0; - MILITIA_ENABLED=0; - CIV_ENABLED=0; - - RANDOM_MERCS = atoi(sRandomMercs); - RANDOM_SPAWN = atoi(sRandomEdges); - - if (RANDOM_SPAWN) - { - // create random starting edges - int spawns[5] = { 0 , 1 , 2 , 3, 9 }; + f_rec_num(1,blank);//wipe clean - // Randomize spawns - rSortArray(spawns,5); - memcpy(client_edges,spawns,sizeof(int)*5); - } + // ---------------------------- + // Read from ja2_mp.ini + // ---------------------------- - if (RANDOM_MERCS) - { - // randomly sort team indexes to give client - // one of four random merc teams - rSortArray(client_mercteam,4); - mpTeams.HandleServerStarted(); - } + CIniReader iniReader(JA2MP_INI_FILENAME); // Wird nur fr Strings gebraucht + strncpy(cServerName, iniReader.ReadString(JA2MP_INI_INITIAL_SECTION, JA2MP_SERVER_NAME, "My JA2 Server"), 30 ); + strncpy(gKitBag, iniReader.ReadString(JA2MP_INI_INITIAL_SECTION,JA2MP_KIT_BAG, ""), 100); + + vfs::PropertyContainer props; + props.initFromIniFile(JA2MP_INI_FILENAME); + UINT16 serverPort = (UINT16)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_SERVER_PORT, 60005); + UINT8 maxClients = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_MAX_CLIENTS, 4); + UINT8 sameMercAllowed = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_SAME_MERC, 1); + UINT8 civEnabled = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_CIV_ENABLED, 0); + UINT8 gameType = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_GAME_MODE, 0); + UINT8 difficultyLevel = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_DIFFICULT_LEVEL, 3); + UINT8 skillTraits = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_NEW_TRAITS, 0); + UINT8 randomMercs = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION,JA2MP_RANDOM_MERCS, 0); + UINT8 randomStartingEdge = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_RANDOM_EDGES, 0); + UINT8 damageSelection = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_DAMAGE_MULTIPLIER, 1); + UINT8 maxEnemiesEnabled = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_OVERRIDE_MAX_AI, 0); + UINT8 syncGameDirectory = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_SYNC_CLIENTS_MP_DIR, 1); + UINT8 reportHiredMerc = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_REPORT_NAME, 1); + UINT8 startingCashSelection = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_STARTING_BALANCE, 25000); + UINT8 timeTurnsSelection = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_TIMED_TURN_SECS_PER_TICK, 2); + UINT8 disableBobbyRay = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_DISABLE_BOBBY_RAYS, 0); + UINT8 maxMercs = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_MAX_MERCS, 6); + UINT8 timeSelection = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_TIME, 1); + UINT8 inventoryAttachment = (UINT8)props.getIntProperty(JA2MP_INI_INITIAL_SECTION, JA2MP_ALLOW_CUSTOM_NIV, 0); - if(gsPLAYER_BSIDE==2)//only enable ai during coop - { - ENEMY_ENABLED = 1; // always enable enemies in co-op - MILITIA_ENABLED = atoi(bteam3_enabled); - CIV_ENABLED = atoi(bteam4_enabled); - // OJW - 20090403 - override max ais - if (atoi(sOverrideMaxAI)==1) - OVERRIDE_MAX_AI = 1; - } + // ---------------------------- + // Save to global values + // ---------------------------- + gMaxClients = maxClients; + gMaxEnemiesEnabled = 0; + gDisableMorale = 0; + gSyncGameDirectory = syncGameDirectory; + gReportHiredMerc = reportHiredMerc; + gDisableBobbyRay = disableBobbyRay; + gDisableMercEquipment = 0; // Disable AIM and MERC equipment + gMaxMercs = maxMercs; + gGameType = gameType; + gDifficultyLevel = difficultyLevel; + gSkillTraits = skillTraits; + gEnemyEnabled = 0; + gCreatureEnabled = 0; + gMilitiaEnabled = 0; + gCivEnabled = 0; + gRandomMercs = randomMercs; + gRandomStartingEdge = randomStartingEdge; + gWeaponReadyBonus = 0; + gDisableSpectatorMode = 0; + gInventoryAttachment = inventoryAttachment; - // random_mercs implies same_merc - gsSAME_MERC = RANDOM_MERCS ? 1 : atoi(hire_same_merc); - gsDAMAGE_MULTIPLIER =(FLOAT)atof(net_div); - gsINTERRUPTS = atoi(ints); - gsMAX_CLIENTS = atoi(maxclients); + if (gRandomStartingEdge) + { + // create random starting edges + int spawns[5] = { 0 , 1 , 2 , 3, 9 }; // 9 == Center + + // Randomize spawns + rSortArray(spawns,5); + memcpy(client_edges,spawns,sizeof(int)*5); + } - gssecs_per_tick=atoi(time_div) ; - gsstarting_balance=atoi(sBalance); -#ifndef USE_VFS - char time[30]; - GetPrivateProfileString( "Ja2_mp Settings","TIME", "", time, MAX_PATH, "..\\Ja2_mp.ini" ); - TIME=(FLOAT)atof(time); + if (gRandomMercs) + { + // randomly sort team indexes to give client + // one of four random merc teams + rSortArray(client_mercteam,4); + mpTeams.HandleServerStarted(); + } - char wpr[30]; - GetPrivateProfileString( "Ja2_mp Settings","WEAPON_READIED_BONUS", "", wpr, MAX_PATH, "..\\Ja2_mp.ini" ); - sWEAPON_READIED_BONUS=atoi(wpr); + if(gGameType == MP_TYPE_COOP)//only enable ai during coop + { + gEnemyEnabled = 1; // always enable enemies in co-op + gMilitiaEnabled = 0; // always disable militia + gCivEnabled = civEnabled; + gMaxEnemiesEnabled = maxEnemiesEnabled; + } - char acniv[30]; - GetPrivateProfileString( "Ja2_mp Settings","ALLOW_CUSTOM_NIV", "", acniv, MAX_PATH, "..\\Ja2_mp.ini" ); - sALLOW_CUSTOM_NIV=atoi(acniv); + // random_mercs implies same_merc + gSameMercAllowed = gRandomMercs ? 1 : sameMercAllowed; + + switch (damageSelection) + { + case 0: // Very Low + gDamageMultiplier = 0.2f; + break; + case 1: // Low + gDamageMultiplier = 0.7f; + break; + case 2: // Normal + gDamageMultiplier = 1.0f; + break; + } - char dspec[30]; - GetPrivateProfileString( "Ja2_mp Settings","DISABLE_SPEC_MODE", "", dspec, MAX_PATH, "..\\Ja2_mp.ini" ); - sDISABLE_SPEC_MODE=atoi(dspec); -#else - char time[30]; - strncpy(time, iniReader.ReadString("Ja2_mp Settings","TIME", "0"), 30); - TIME=(FLOAT)atof(time); + switch (timeTurnsSelection) + { + case 0: // Never + gSecondsPerTick = 0; + break; + case 1: // Slow + gSecondsPerTick = 5; + break; + case 2: // Medium + gSecondsPerTick = 100; + break; + case 3: // Fast + gSecondsPerTick = 400; + break; + } - char wpr[30]; - strncpy(wpr, iniReader.ReadString("Ja2_mp Settings","WEAPON_READIED_BONUS", "0"), 30); - sWEAPON_READIED_BONUS=atoi(wpr); - - char acniv[30]; - strncpy(acniv, iniReader.ReadString("Ja2_mp Settings","ALLOW_CUSTOM_NIV", "0"), 30); - sALLOW_CUSTOM_NIV=atoi(acniv); - - char dspec[30]; - strncpy(dspec, iniReader.ReadString("Ja2_mp Settings","DISABLE_SPEC_MODE", "0"), 30); - sDISABLE_SPEC_MODE=atoi(dspec); -#endif - //********************** + switch (startingCashSelection) + { + case 0: // Low + gStartingCash = 5000; + break; + case 1: // Medium + gStartingCash = 50000; + break; + case 2: // High + gStartingCash = 100000; + break; + case 3: // Unlimited + gStartingCash = 999999999; + break; + } + + switch (timeSelection) + { + case 0: // Morning + gStartingTime = 7.00f; + break; + case 1: // Afternoon + gStartingTime = 13.00f; + break; + case 2: // Night + gStartingTime = 2.00; + break; + } + + //********************** ScreenMsg( FONT_ORANGE, MSG_MPSYSTEM, MPServerMessage[0] ); server=RakNetworkFactory::GetRakPeerInterface(); - bool b = server->Startup(gsMAX_CLIENTS, 30, &SocketDescriptor(atoi(SERVER_PORT),0), 1); + bool b = server->Startup(gMaxClients, 30, &SocketDescriptor(serverPort,0), 1); - server->SetMaximumIncomingConnections((gsMAX_CLIENTS)); + server->SetMaximumIncomingConnections((gMaxClients)); //RPC's REGISTER_STATIC_RPC(server, sendPATH); @@ -1286,9 +1052,7 @@ void start_server (void) REGISTER_STATIC_RPC(server, sendDEATH); REGISTER_STATIC_RPC(server, sendhitSTRUCT); REGISTER_STATIC_RPC(server, sendhitWINDOW); - REGISTER_STATIC_RPC(server, sendMISS); - //REGISTER_STATIC_RPC(server, rOVH); - + REGISTER_STATIC_RPC(server, sendMISS); REGISTER_STATIC_RPC(server, updatenetworksoldier); REGISTER_STATIC_RPC(server, Snull_team); REGISTER_STATIC_RPC(server, sendFIREW); @@ -1302,25 +1066,20 @@ void start_server (void) REGISTER_STATIC_RPC(server, sendTEAMCHANGE); REGISTER_STATIC_RPC(server, sendGAMEOVER); REGISTER_STATIC_RPC(server, sendCHATMSG); - REGISTER_STATIC_RPC(server, receiveSETID); - //REGISTER_STATIC_RPC(server, sendALLFILESRECEIVED); - //REGISTER_STATIC_RPC(server, rINT); - // + REGISTER_STATIC_RPC(server, receiveSETID); if (b) { - ScreenMsg( FONT_ORANGE, MSG_MPSYSTEM, MPServerMessage[1]); - //ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, MPServerMessage[2]); + ScreenMsg( FONT_ORANGE, MSG_MPSYSTEM, MPServerMessage[1]); is_server = true; - // WANNE: FILE TRANSFER server->AttachPlugin(&fltServer); server->SetSplitMessageProgressInterval(1); fltServer.SetCallback(&serverFileListProgress); fileListTotalBytes=0; - if (gsSYNC_CLIENTS_MP_DIR == 1) + if (gSyncGameDirectory == 1) { AddFilesToSendList(); } @@ -1339,7 +1098,6 @@ void start_server (void) } - // recieve and process server info packets void server_packet ( void ) diff --git a/Multiplayer/transfer_rules.cpp b/Multiplayer/transfer_rules.cpp new file mode 100644 index 00000000..aac4e2fb --- /dev/null +++ b/Multiplayer/transfer_rules.cpp @@ -0,0 +1,126 @@ +#include "transfer_rules.h" +#include "Debug.h" +#include +#include +#include +#include +#include + +CTransferRules::CTransferRules() +: m_eDefaultAction(ACCEPT) +{}; + + +bool CTransferRules::initFromTxtFile(vfs::Path const& sPath) +{ + // try to open via VirtualFileSystem + if(getVFS()->fileExists(sPath)) + { + return initFromTxtFile(getVFS()->getReadFile(sPath)); + } + else + { + // file doesn't exist or VFS not initialized yet + vfs::IBaseFile* pFile = new vfs::CFile(sPath); + if(pFile) + { + bool success = initFromTxtFile(vfs::tReadableFile::cast(pFile)); + delete pFile; + return success; + } + } + return false; +} + +bool CTransferRules::initFromTxtFile(vfs::tReadableFile* pFile) +{ + if(pFile && pFile->openRead()) + { + vfs::COpenReadFile rfile(pFile); + std::string sBuffer; + vfs::UInt32 line_counter = 0; + vfs::CReadLine rl(*pFile); + while(rl.getLine(sBuffer)) + { + line_counter++; + // very simple parsing : key = value + if(!sBuffer.empty()) + { + // remove leading white spaces + ::size_t iStart = sBuffer.find_first_not_of(" \t",0); + char first = sBuffer.at(iStart); + switch(first) + { + case '!': + case ';': + case '#': + // comment -> do nothing + break; + default: + ::size_t iEnd = sBuffer.find_first_of(" \t", iStart); + if(iEnd != std::string::npos) + { + SRule rule; + std::string action = sBuffer.substr(iStart, iEnd - iStart); + if( vfs::StrCmp::Equal(action, "deny") ) + { + rule.action = CTransferRules::DENY; + } + else if( vfs::StrCmp::Equal(action, "accept") ) + { + rule.action = CTransferRules::ACCEPT; + } + else + { + std::wstring trybuffer = L"Invalid UTF-8 character in string"; + VFS_IGNOREEXCEPTION( trybuffer = vfs::String(sBuffer).c_wcs(), "" ); /* just make sure we don't break off when string conversion fails */ + std::wstringstream wss; + wss << L"Unknown action in file \"" << pFile->getPath().c_wcs() + << L", line " << line_counter << " : " << vfs::String(sBuffer).c_wcs(); + SGP_THROW(wss.str().c_str()); + } + try + { + rule.pattern = vfs::Path(vfs::trimString(sBuffer, iEnd, sBuffer.length())); + } + catch(vfs::Exception& ex) + { + std::wstringstream wss; + wss << L"Could not convert string, invalid utf8 encoding in file \"" << pFile->getPath().c_wcs() + << L"\", line " << line_counter; + SGP_RETHROW(wss.str().c_str(), ex); + } + m_listRules.push_back(rule); + } + break; + }; // end switch + } // end if (empty) + } // end while(!eof) + return true; + } + return false; +} + +void CTransferRules::setDefaultAction(CTransferRules::EAction act) +{ + m_eDefaultAction = act; +} + +CTransferRules::EAction CTransferRules::getDefaultAction() +{ + return m_eDefaultAction; +} + +CTransferRules::EAction CTransferRules::applyRule(vfs::String const& sStr) +{ + tPatternList::iterator sit = m_listRules.begin(); + for(; sit != m_listRules.end(); ++sit) + { + if(matchPattern(sit->pattern(), sStr)) + { + return sit->action; + } + } + return m_eDefaultAction; +} + diff --git a/Multiplayer/transfer_rules.h b/Multiplayer/transfer_rules.h new file mode 100644 index 00000000..11c0a516 --- /dev/null +++ b/Multiplayer/transfer_rules.h @@ -0,0 +1,39 @@ +#ifndef _TRANSFER_RULES_H_ +#define _TRANSFER_RULES_H_ + +#include +#include + +#include + +class CTransferRules +{ +public: + enum EAction + { + DENY, + ACCEPT, + }; +public: + CTransferRules(); + + bool initFromTxtFile(vfs::Path const& sPath); + bool initFromTxtFile(vfs::tReadableFile* pFile); + + void setDefaultAction(EAction act); + EAction getDefaultAction(); + + EAction applyRule(vfs::String const& sStr); +private: + struct SRule + { + EAction action; + vfs::Path pattern; + }; + typedef std::list tPatternList; + tPatternList m_listRules; + EAction m_eDefaultAction; +}; + + +#endif // _TRANSFER_RULES_H_ diff --git a/SaveLoadGame.cpp b/SaveLoadGame.cpp index b5ba248a..32db5250 100644 --- a/SaveLoadGame.cpp +++ b/SaveLoadGame.cpp @@ -112,6 +112,7 @@ #include "Facilities.h" // HEADROCK HAM 3.6: Yet another include, goddammit #include "Town Militia.h" + #include "Items.h" #endif #include "BobbyR.h" @@ -124,8 +125,11 @@ #include "BobbyRMailOrder.h" #include "Mercs.h" #include "INIReader.h" +#include "mercs.h" +#include "soldier Profile.h" +#include "LuaInitNPCs.h" -#include "VFS/vfs.h" +#include //rain #include "Rain.h" //end rain @@ -139,6 +143,7 @@ // ///////////////////////////////////////////////////// +#include "LuaInitNPCs.h" void GetBestPossibleSectorXYZValues( INT16 *psSectorX, INT16 *psSectorY, INT8 *pbSectorZ ); extern void NextLoopCheckForEnoughFreeHardDriveSpace(); @@ -218,6 +223,7 @@ typedef struct BOOLEAN fShowTeamFlag; BOOLEAN fShowMineFlag; BOOLEAN fShowAircraftFlag; + BOOLEAN fShowMobileRestrictionsFlag; // HEADROCK HAM 4: Showing Manual Mobile Restrictions // is the helicopter available to player? BOOLEAN fHelicopterAvailable; @@ -406,8 +412,12 @@ typedef struct // HEADROCK HAM 3.6: Global variable keeping track of Militia Upkeep Costs at last midnight. UINT32 uiTotalUpkeepForMilitia; - // HEADROCK HAM 3.6: Removed 16 fillers (16 bytes) to accomodate the above new variables. - UINT8 ubFiller[534]; //This structure should be 1024 bytes + // HEADROCK HAM 4: Added manual restrictions + UINT8 ubManualRestrictMilitia[256]; + + BOOLEAN HiddenNames[500]; //legion by Jazz + + UINT8 ubFiller[278]; //This structure should be 1588 bytes } GENERAL_SAVE_INFO; @@ -433,6 +443,7 @@ extern EmailPtr pEmailList; extern UINT32 guiCurrentUniqueSoldierId; extern BOOLEAN gfHavePurchasedItemsFromTony; +INT32 ReadFieldByField(HWFILE hFile, PTR pDest, UINT32 uiFieldSize, UINT32 uiElementSize, UINT32 uiCurByteCount); ///////////////////////////////////////////////////// // @@ -1158,17 +1169,181 @@ BOOLEAN SOLDIERCREATE_STRUCT::Load(HWFILE hFile, int versionToLoad, bool loadChe //BOOLEAN MERCPROFILESTRUCT::Load(HWFILE hFile, bool forceLoadOldVersion) BOOLEAN MERCPROFILESTRUCT::Load(HWFILE hFile, bool forceLoadOldVersion, bool forceLoadOldEncryption, bool wasSavedWithEncryption) { - UINT32 uiNumBytesRead; + UINT32 uiNumBytesRead; + INT32 numBytesRead = 0; this->initialize(); //if we are at the most current version, then fine if ( guiCurrentSaveGameVersion >= NIV_SAVEGAME_DATATYPE_CHANGE && forceLoadOldVersion == false) { // WANNE - BMP: DONE! - if ( !FileRead( hFile, this, SIZEOF_MERCPROFILESTRUCT_POD, &uiNumBytesRead ) ) - { - return(FALSE); +// if ( !FileRead( hFile, this, SIZEOF_MERCPROFILESTRUCT_POD, &uiNumBytesRead ) ) +// { +// return(FALSE); +// } + FileRead( hFile, this->zName, sizeof(this->zName), &uiNumBytesRead); + numBytesRead += uiNumBytesRead; + numBytesRead = ReadFieldByField( hFile, this->zNickname, sizeof(this->zNickname), sizeof(CHAR16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiAttnSound, sizeof(this->uiAttnSound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiCurseSound, sizeof(this->uiCurseSound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiDieSound, sizeof(this->uiDieSound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiGoodSound, sizeof(this->uiGoodSound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiGruntSound, sizeof(this->uiGruntSound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiGrunt2Sound, sizeof(this->uiGrunt2Sound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiOkSound, sizeof(this->uiOkSound), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubFaceIndex, sizeof(this->ubFaceIndex), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->PANTS, sizeof(this->PANTS), sizeof(CHAR8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->VEST, sizeof(this->VEST), sizeof(CHAR8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->SKIN, sizeof(this->SKIN), sizeof(CHAR8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->HAIR, sizeof(this->HAIR), sizeof(CHAR8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bSex, sizeof(this->bSex), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bArmourAttractiveness, sizeof(this->bArmourAttractiveness), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubMiscFlags2, sizeof(this->ubMiscFlags2), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bEvolution, sizeof(this->bEvolution), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubMiscFlags, sizeof(this->ubMiscFlags), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bSexist, sizeof(this->bSexist), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLearnToHate, sizeof(this->bLearnToHate), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bStealRate, sizeof(this->bStealRate), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bVocalVolume, sizeof(this->bVocalVolume), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubQuoteRecord, sizeof(this->ubQuoteRecord), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bDeathRate, sizeof(this->bDeathRate), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bScientific, sizeof(this->bScientific), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sExpLevelGain, sizeof(this->sExpLevelGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sLifeGain, sizeof(this->sLifeGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sAgilityGain, sizeof(this->sAgilityGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sDexterityGain, sizeof(this->sDexterityGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sWisdomGain, sizeof(this->sWisdomGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sMarksmanshipGain, sizeof(this->sMarksmanshipGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sMedicalGain, sizeof(this->sMedicalGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sMechanicGain, sizeof(this->sMechanicGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sExplosivesGain, sizeof(this->sExplosivesGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubBodyType, sizeof(this->ubBodyType), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMedical, sizeof(this->bMedical), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usEyesX, sizeof(this->usEyesX), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usEyesY, sizeof(this->usEyesY), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usMouthX, sizeof(this->usMouthX), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usMouthY, sizeof(this->usMouthY), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiEyeDelay, sizeof(this->uiEyeDelay), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiMouthDelay, sizeof(this->uiMouthDelay), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiBlinkFrequency, sizeof(this->uiBlinkFrequency), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiExpressionFrequency, sizeof(this->uiExpressionFrequency), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sSectorX, sizeof(this->sSectorX), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sSectorY, sizeof(this->sSectorY), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiDayBecomesAvailable, sizeof(this->uiDayBecomesAvailable), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bStrength, sizeof(this->bStrength), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLifeMax, sizeof(this->bLifeMax), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bExpLevelDelta, sizeof(this->bExpLevelDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLifeDelta, sizeof(this->bLifeDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bAgilityDelta, sizeof(this->bAgilityDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bDexterityDelta, sizeof(this->bDexterityDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bWisdomDelta, sizeof(this->bWisdomDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMarksmanshipDelta, sizeof(this->bMarksmanshipDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMedicalDelta, sizeof(this->bMedicalDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMechanicDelta, sizeof(this->bMechanicDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bExplosivesDelta, sizeof(this->bExplosivesDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bStrengthDelta, sizeof(this->bStrengthDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLeadershipDelta, sizeof(this->bLeadershipDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usTotalDaysServed, sizeof(this->usTotalDaysServed), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sLeadershipGain, sizeof(this->sLeadershipGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sStrengthGain, sizeof(this->sStrengthGain), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiBodyTypeSubFlags, sizeof(this->uiBodyTypeSubFlags), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sSalary, sizeof(this->sSalary), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLife, sizeof(this->bLife), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bDexterity, sizeof(this->bDexterity), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bDisability, sizeof(this->bDisability), sizeof(INT8), numBytesRead); + if(guiCurrentSaveGameVersion >= STOMP12_SAVEGAME_DATATYPE_CHANGE2) + numBytesRead = ReadFieldByField( hFile, this->bSkillTraits, sizeof(this->bSkillTraits), sizeof(INT8), numBytesRead); + else //CHRISL: Prior to STOMP12_SAVEGAME_DATATYPE_CHANGE2, bSkillTraits was only a single INT8 value + numBytesRead = ReadFieldByField( hFile, this->bSkillTraits, sizeof(INT8), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bReputationTolerance, sizeof(this->bReputationTolerance), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bExplosive, sizeof(this->bExplosive), sizeof(INT8), numBytesRead); + if(guiCurrentSaveGameVersion < STOMP12_SAVEGAME_DATATYPE_CHANGE2) + { //CHRISL: These two variables no longer exist but we should read them into bSKillTraits[1] and [2] + numBytesRead = ReadFieldByField( hFile, &this->bSkillTraits[1], sizeof(INT8), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bSkillTraits[2], sizeof(INT8), sizeof(INT8), numBytesRead); } + numBytesRead = ReadFieldByField( hFile, &this->bLeadership, sizeof(this->bLeadership), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->bBuddy, sizeof(this->bBuddy), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->bHated, sizeof(this->bHated), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bExpLevel, sizeof(this->bExpLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMarksmanship, sizeof(this->bMarksmanship), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMinService, sizeof(this->bMinService), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bWisdom, sizeof(this->bWisdom), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bResigned, sizeof(this->bResigned), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bActive, sizeof(this->bActive), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->usApproachFactor, sizeof(this->usApproachFactor), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMainGunAttractiveness, sizeof(this->bMainGunAttractiveness), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bAgility, sizeof(this->bAgility), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->fUseProfileInsertionInfo, sizeof(this->fUseProfileInsertionInfo), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->_old_sGridNo, sizeof(this->_old_sGridNo), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubQuoteActionID, sizeof(this->ubQuoteActionID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMechanical, sizeof(this->bMechanical), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubInvUndroppable, sizeof(this->ubInvUndroppable), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->ubRoomRangeStart, sizeof(this->ubRoomRangeStart), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->bMercTownReputation, sizeof(this->bMercTownReputation), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->usStatChangeChances, sizeof(this->usStatChangeChances), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->usStatChangeSuccesses, sizeof(this->usStatChangeSuccesses), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubStrategicInsertionCode, sizeof(this->ubStrategicInsertionCode), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->ubRoomRangeEnd, sizeof(this->ubRoomRangeEnd), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubLastQuoteSaid, sizeof(this->ubLastQuoteSaid), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bRace, sizeof(this->bRace), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bNationality, sizeof(this->bNationality), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bAppearance, sizeof(this->bAppearance), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bAppearanceCareLevel, sizeof(this->bAppearanceCareLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bRefinement, sizeof(this->bRefinement), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bRefinementCareLevel, sizeof(this->bRefinementCareLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bHatedNationality, sizeof(this->bHatedNationality), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bHatedNationalityCareLevel, sizeof(this->bHatedNationalityCareLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bRacist, sizeof(this->bRacist), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiWeeklySalary, sizeof(this->uiWeeklySalary), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiBiWeeklySalary, sizeof(this->uiBiWeeklySalary), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMedicalDeposit, sizeof(this->bMedicalDeposit), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bAttitude, sizeof(this->bAttitude), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bCharacterTrait, sizeof(this->bCharacterTrait), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bBaseMorale, sizeof(this->bBaseMorale), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sMedicalDepositAmount, sizeof(this->sMedicalDepositAmount), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLearnToLike, sizeof(this->bLearnToLike), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->ubApproachVal, sizeof(this->ubApproachVal), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->ubApproachMod, sizeof(this->ubApproachMod), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bTown, sizeof(this->bTown), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bTownAttachment, sizeof(this->bTownAttachment), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usOptionalGearCost, sizeof(this->usOptionalGearCost), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->bMercOpinion, sizeof(this->bMercOpinion), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bApproached, sizeof(this->bApproached), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bMercStatus, sizeof(this->bMercStatus), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->bHatedTime, sizeof(this->bHatedTime), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLearnToLikeTime, sizeof(this->bLearnToLikeTime), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLearnToHateTime, sizeof(this->bLearnToHateTime), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, this->bHatedCount, sizeof(this->bHatedCount), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLearnToLikeCount, sizeof(this->bLearnToLikeCount), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLearnToHateCount, sizeof(this->bLearnToHateCount), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubLastDateSpokenTo, sizeof(this->ubLastDateSpokenTo), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bLastQuoteSaidWasSpecial, sizeof(this->bLastQuoteSaidWasSpecial), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bSectorZ, sizeof(this->bSectorZ), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->usStrategicInsertionData, sizeof(this->usStrategicInsertionData), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bFriendlyOrDirectDefaultResponseUsedRecently, sizeof(this->bFriendlyOrDirectDefaultResponseUsedRecently), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bRecruitDefaultResponseUsedRecently, sizeof(this->bRecruitDefaultResponseUsedRecently), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bThreatenDefaultResponseUsedRecently, sizeof(this->bThreatenDefaultResponseUsedRecently), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bNPCData, sizeof(this->bNPCData), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->iBalance, sizeof(this->iBalance), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sTrueSalary, sizeof(this->sTrueSalary), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubCivilianGroup, sizeof(this->ubCivilianGroup), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubNeedForSleep, sizeof(this->ubNeedForSleep), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiMoney, sizeof(this->uiMoney), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->bNPCData2, sizeof(this->bNPCData2), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubMiscFlags3, sizeof(this->ubMiscFlags3), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubDaysOfMoraleHangover, sizeof(this->ubDaysOfMoraleHangover), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubNumTimesDrugUseInLifetime, sizeof(this->ubNumTimesDrugUseInLifetime), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiPrecedentQuoteSaid, sizeof(this->uiPrecedentQuoteSaid), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiProfileChecksum, sizeof(this->uiProfileChecksum), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->_old_sPreCombatGridNo, sizeof(this->_old_sPreCombatGridNo), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubTimeTillNextHatedComplaint, sizeof(this->ubTimeTillNextHatedComplaint), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->ubSuspiciousDeath, sizeof(this->ubSuspiciousDeath), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->iMercMercContractLength, sizeof(this->iMercMercContractLength), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->uiTotalCostToDate, sizeof(this->uiTotalCostToDate), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sGridNo, sizeof(this->sGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField( hFile, &this->sPreCombatGridNo, sizeof(this->sPreCombatGridNo), sizeof(INT32), numBytesRead); + //numBytesRead = ReadFieldByField( hFile, &this->endOfPOD, sizeof(this->endOfPOD), sizeof(char), numBytesRead); int size; if ( !FileRead( hFile, &size, sizeof(int), &uiNumBytesRead ) ) { @@ -1197,6 +1372,11 @@ BOOLEAN MERCPROFILESTRUCT::Load(HWFILE hFile, bool forceLoadOldVersion, bool for bInvStatus[x] = status; bInvNumber[x] = number; } + // SANDRO - read records + if ( !FileRead( hFile, &this->records, sizeof(STRUCT_Records), &uiNumBytesRead ) ) + { + return(FALSE); + } if ( this->uiProfileChecksum != this->GetChecksum() ) { return( FALSE ); @@ -1269,6 +1449,11 @@ BOOLEAN MERCPROFILESTRUCT::Save(HWFILE hFile) return(FALSE); } } + // SANDRO - save records + if ( !FileWrite( hFile, &this->records, sizeof(STRUCT_Records), &uiNumBytesWritten ) ) + { + return(FALSE); + } return TRUE; } @@ -1318,7 +1503,10 @@ BOOLEAN SOLDIERTYPE::Save(HWFILE hFile) } return TRUE; } - +/*CHRISL: This function is designed to allow reading the save game file one field at a time. We currently save structures by saving a block of memory, +but variables are stored in memory so that they fit neatly into a WORD resulting in the program automatically adding some padding. This padding is saved +during the save game process and this function is designed to calculate where that padding is so that we can account for it during the load process. The +use of this function should allow changes to be made to various structures within the designated "POD", while still allowing for save game continuity.*/ INT32 ReadFieldByField(HWFILE hFile, PTR pDest, UINT32 uiFieldSize, UINT32 uiElementSize, UINT32 uiCurByteCount) { UINT32 uiNumBytesRead; @@ -1345,14 +1533,336 @@ INT32 ReadFieldByField(HWFILE hFile, PTR pDest, UINT32 uiFieldSize, UINT32 uiEle BOOLEAN SOLDIERTYPE::Load(HWFILE hFile) { UINT32 uiNumBytesRead; - INT32 numBytesRead = 0; + INT32 numBytesRead = 0, temp = 0; char padding[10]; //if we are at the most current version, then fine if ( guiCurrentSaveGameVersion >= NIV_SAVEGAME_DATATYPE_CHANGE ) { //the soldier type info has changed at version 102 - //CHRISL: It was further changed at version 104 to allow for 16bit action points for the 100AP system + //CHRISL: To accomodate future changes to this structure, we'll load each value field by field + numBytesRead = 0; + FileRead( hFile, this, (offsetof(SOLDIERTYPE, ubBodyType)+sizeof(ubBodyType)), &uiNumBytesRead ); + numBytesRead += uiNumBytesRead; + if(guiCurrentSaveGameVersion >= AP100_SAVEGAME_DATATYPE_CHANGE) + { //CHRISL: It was changed at version 104 to allow for 16bit action points for the 100AP system + numBytesRead = ReadFieldByField(hFile, &this->bActionPoints, sizeof(bActionPoints), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bInitialActionPoints, sizeof(bInitialActionPoints), sizeof(INT16), numBytesRead); + } + else + { + numBytesRead = ReadFieldByField(hFile, &this->bActionPoints, sizeof(bActionPoints), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bInitialActionPoints, sizeof(bInitialActionPoints), sizeof(INT8), numBytesRead); + } + numBytesRead = ReadFieldByField(hFile, &this->bOldLife, sizeof(bOldLife), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bVisible, sizeof(bVisible), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bActive, sizeof(bActive), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTeam, sizeof(bTeam), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pTempObject, sizeof(pTempObject), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pKeyRing, sizeof(pKeyRing), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bInSector, sizeof(bInSector), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bFlashPortraitFrame, sizeof(bFlashPortraitFrame), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sFractLife, sizeof(sFractLife), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBleeding, sizeof(bBleeding), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBreath, sizeof(bBreath), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBreathMax, sizeof(bBreathMax), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bStealthMode, sizeof(bStealthMode), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sBreathRed, sizeof(sBreathRed), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubWaitActionToDo, sizeof(ubWaitActionToDo), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubInsertionDirection, sizeof(ubInsertionDirection), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bGunType, sizeof(bGunType), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubOppNum, sizeof(ubOppNum), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bLastRenderVisibleValue, sizeof(bLastRenderVisibleValue), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubAttackingHand, sizeof(ubAttackingHand), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sWeightCarriedAtTurnStart, sizeof(sWeightCarriedAtTurnStart), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iHealableInjury, sizeof(iHealableInjury), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->fDoingSurgery, sizeof(fDoingSurgery), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->lUnregainableBreath, sizeof(lUnregainableBreath), sizeof(signed long), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubCriticalStatDamage, sizeof(ubCriticalStatDamage), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubGroupID, sizeof(ubGroupID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubMovementNoiseHeard, sizeof(ubMovementNoiseHeard), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->dXPos, sizeof(dXPos), sizeof(FLOAT), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->dYPos, sizeof(dYPos), sizeof(FLOAT), numBytesRead); + if(guiCurrentSaveGameVersion >= NCTH_DATATYPE_CHANGE){ + numBytesRead = ReadFieldByField(hFile, &this->sOldXPos, sizeof(sOldXPos), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sOldYPos, sizeof(sOldYPos), sizeof(INT16), numBytesRead); + } else { + //CHRISL: These used to be floats but we've reduced them to INT16 + numBytesRead = ReadFieldByField(hFile, &this->sOldXPos, sizeof(sOldXPos), sizeof(INT16), numBytesRead); + temp = ReadFieldByField(hFile, &padding, sizeof(INT16), sizeof(INT16), temp); + numBytesRead = ReadFieldByField(hFile, &this->sOldYPos, sizeof(sOldYPos), sizeof(INT16), numBytesRead); + temp = ReadFieldByField(hFile, &padding, sizeof(INT16), sizeof(INT16), temp); + } + numBytesRead = ReadFieldByField(hFile, &this->sInitialGridNo, sizeof(sInitialGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sGridNo, sizeof(sGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDirection, sizeof(ubDirection), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sHeightAdjustment, sizeof(sHeightAdjustment), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sDesiredHeight, sizeof(sDesiredHeight), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sTempNewGridNo, sizeof(sTempNewGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sRoomNo, sizeof(sRoomNo), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bOverTerrainType, sizeof(bOverTerrainType), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bOldOverTerrainType, sizeof(bOldOverTerrainType), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bCollapsed, sizeof(bCollapsed), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBreathCollapsed, sizeof(bBreathCollapsed), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDesiredHeight, sizeof(ubDesiredHeight), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usPendingAnimation, sizeof(usPendingAnimation), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubPendingStanceChange, sizeof(ubPendingStanceChange), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usAnimState, sizeof(usAnimState), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiAIDelay, sizeof(uiAIDelay), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sReloadDelay, sizeof(sReloadDelay), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubAttackerID, sizeof(ubAttackerID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubPreviousAttackerID, sizeof(ubPreviousAttackerID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sInsertionGridNo, sizeof(sInsertionGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->AnimCache, sizeof(AnimCache), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bSide, sizeof(bSide), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bViewRange, sizeof(bViewRange), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bNewOppCnt, sizeof(bNewOppCnt), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bService, sizeof(bService), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usAniCode, sizeof(usAniCode), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usAniFrame, sizeof(usAniFrame), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sAniDelay, sizeof(sAniDelay), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDelayedMovementCauseMerc, sizeof(ubDelayedMovementCauseMerc), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sDelayedMovementCauseGridNo, sizeof(sDelayedMovementCauseGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sReservedMovementGridNo, sizeof(sReservedMovementGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sTargetGridNo, sizeof(sTargetGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTargetLevel, sizeof(bTargetLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTargetCubeLevel, sizeof(bTargetCubeLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sLastTarget, sizeof(sLastTarget), sizeof(INT32), numBytesRead); + if(guiCurrentSaveGameVersion >= NCTH_DATATYPE_CHANGE){ + numBytesRead = ReadFieldByField(hFile, &this->dPrevMuzzleOffsetX, sizeof(dPrevMuzzleOffsetX), sizeof(FLOAT), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->dPrevMuzzleOffsetY, sizeof(dPrevMuzzleOffsetY), sizeof(FLOAT), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->dPrevCounterForceX, sizeof(dPrevCounterForceX), sizeof(FLOAT), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->dPrevCounterForceY, sizeof(dPrevCounterForceY), sizeof(FLOAT), numBytesRead); + } else { + numBytesRead += sizeof(FLOAT); + numBytesRead += sizeof(FLOAT); + numBytesRead += sizeof(FLOAT); + numBytesRead += sizeof(FLOAT); + } + numBytesRead = ReadFieldByField(hFile, &this->bTilesMoved, sizeof(bTilesMoved), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->dNextBleed, sizeof(dNextBleed), sizeof(FLOAT), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubTilesMovedPerRTBreathUpdate, sizeof(ubTilesMovedPerRTBreathUpdate), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usLastMovementAnimPerRTBreathUpdate, sizeof(usLastMovementAnimPerRTBreathUpdate), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sLocatorFrame, sizeof(sLocatorFrame), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iFaceIndex, sizeof(iFaceIndex), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usFrontArcFullTileList, sizeof(usFrontArcFullTileList), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usFrontArcFullTileGridNos, sizeof(usFrontArcFullTileGridNos), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->HeadPal, sizeof(HeadPal), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->PantsPal, sizeof(PantsPal), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->VestPal, sizeof(VestPal), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->SkinPal, sizeof(SkinPal), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->MiscPal, sizeof(MiscPal), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->p8BPPPalette, sizeof(p8BPPPalette), sizeof(SGPPaletteEntry), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->p16BPPPalette, sizeof(p16BPPPalette), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pShades, sizeof(pShades), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pGlowShades, sizeof(pGlowShades), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pCurrentShade, sizeof(pCurrentShade), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubFadeLevel, sizeof(ubFadeLevel), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubServiceCount, sizeof(ubServiceCount), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubServicePartner, sizeof(ubServicePartner), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pThrowParams, sizeof(pThrowParams), 4, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bReverse, sizeof(bReverse), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pLevelNode, sizeof(pLevelNode), 4, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pExternShadowLevelNode, sizeof(pExternShadowLevelNode), 4, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pRoofUILevelNode, sizeof(pRoofUILevelNode), 4, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pBackGround, sizeof(pBackGround), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pZBackground, sizeof(pZBackground), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usUnblitX, sizeof(usUnblitX), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usUnblitY, sizeof(usUnblitY), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usUnblitWidth, sizeof(usUnblitWidth), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usUnblitHeight, sizeof(usUnblitHeight), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubStrategicInsertionCode, sizeof(ubStrategicInsertionCode), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usStrategicInsertionData, sizeof(usStrategicInsertionData), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iLight, sizeof(iLight), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iMuzFlash, sizeof(iMuzFlash), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bMuzFlashCount, sizeof(bMuzFlashCount), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sX, sizeof(sX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sY, sizeof(sY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usOldAniState, sizeof(usOldAniState), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sOldAniCode, sizeof(sOldAniCode), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBulletsLeft, sizeof(bBulletsLeft), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubSuppressionPoints, sizeof(ubSuppressionPoints), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiTimeOfLastRandomAction, sizeof(uiTimeOfLastRandomAction), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usLastRandomAnim, sizeof(usLastRandomAnim), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usAnimSurface, sizeof(usAnimSurface), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sZLevel, sizeof(sZLevel), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sWalkToAttackGridNo, sizeof(sWalkToAttackGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sWalkToAttackWalkToCost, sizeof(sWalkToAttackWalkToCost), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sLocatorOffX, sizeof(sLocatorOffX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sLocatorOffY, sizeof(sLocatorOffY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pForcedShade, sizeof(pForcedShade), 4, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bDisplayDamageCount, sizeof(bDisplayDamageCount), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sDamage, sizeof(sDamage), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sDamageX, sizeof(sDamageX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sDamageY, sizeof(sDamageY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bDamageDir, sizeof(bDamageDir), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bDoBurst, sizeof(bDoBurst), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usUIMovementMode, sizeof(usUIMovementMode), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bUIInterfaceLevel, sizeof(bUIInterfaceLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubProfile, sizeof(ubProfile), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubQuoteRecord, sizeof(ubQuoteRecord), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubQuoteActionID, sizeof(ubQuoteActionID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubBattleSoundID, sizeof(ubBattleSoundID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubClosePanelFrame, sizeof(ubClosePanelFrame), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDeadPanelFrame, sizeof(ubDeadPanelFrame), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bOpenPanelFrame, sizeof(bOpenPanelFrame), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sPanelFaceX, sizeof(sPanelFaceX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sPanelFaceY, sizeof(sPanelFaceY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bNumHitsThisTurn, sizeof(bNumHitsThisTurn), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usQuoteSaidFlags, sizeof(usQuoteSaidFlags), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bLastSkillCheck, sizeof(bLastSkillCheck), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubSkillCheckAttempts, sizeof(ubSkillCheckAttempts), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bVocalVolume, sizeof(bVocalVolume), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bStartFallDir, sizeof(bStartFallDir), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubPendingDirection, sizeof(ubPendingDirection), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiAnimSubFlags, sizeof(uiAnimSubFlags), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bAimShotLocation, sizeof(bAimShotLocation), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubHitLocation, sizeof(ubHitLocation), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pEffectShades, sizeof(pEffectShades), 4, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubPlannedUIAPCost, sizeof(ubPlannedUIAPCost), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sPlannedTargetX, sizeof(sPlannedTargetX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sPlannedTargetY, sizeof(sPlannedTargetY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sSpreadLocations, sizeof(sSpreadLocations), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sStartGridNo, sizeof(sStartGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sEndGridNo, sizeof(sEndGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sForcastGridno, sizeof(sForcastGridno), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sZLevelOverride, sizeof(sZLevelOverride), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bMovedPriorToInterrupt, sizeof(bMovedPriorToInterrupt), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iEndofContractTime, sizeof(iEndofContractTime), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iStartContractTime, sizeof(iStartContractTime), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iTotalContractLength, sizeof(iTotalContractLength), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iNextActionSpecialData, sizeof(iNextActionSpecialData), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubWhatKindOfMercAmI, sizeof(ubWhatKindOfMercAmI), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bAssignment, sizeof(bAssignment), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bOldAssignment, sizeof(bOldAssignment), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTrainStat, sizeof(bTrainStat), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sSectorX, sizeof(sSectorX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sSectorY, sizeof(sSectorY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bSectorZ, sizeof(bSectorZ), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iVehicleId, sizeof(iVehicleId), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pMercPath, sizeof(pMercPath), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usMedicalDeposit, sizeof(usMedicalDeposit), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usLifeInsurance, sizeof(usLifeInsurance), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiStartMovementTime, sizeof(uiStartMovementTime), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiOptimumMovementTime, sizeof(uiOptimumMovementTime), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usLastUpdateTime, sizeof(usLastUpdateTime), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiSoldierUpdateNumber, sizeof(uiSoldierUpdateNumber), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubSoldierUpdateType, sizeof(ubSoldierUpdateType), sizeof(BYTE), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sScheduledStop, sizeof(sScheduledStop), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iStartOfInsuranceContract, sizeof(iStartOfInsuranceContract), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiLastAssignmentChangeMin, sizeof(uiLastAssignmentChangeMin), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iTotalLengthOfInsuranceContract, sizeof(iTotalLengthOfInsuranceContract), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubSoldierClass, sizeof(ubSoldierClass), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubAPsLostToSuppression, sizeof(ubAPsLostToSuppression), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubSuppressorID, sizeof(ubSuppressorID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDesiredSquadAssignment, sizeof(ubDesiredSquadAssignment), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubNumTraversalsAllowedToMerge, sizeof(ubNumTraversalsAllowedToMerge), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usPendingAnimation2, sizeof(usPendingAnimation2), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubCivilianGroup, sizeof(ubCivilianGroup), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiUniqueSoldierIdValue, sizeof(uiUniqueSoldierIdValue), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bEndDoorOpenCode, sizeof(bEndDoorOpenCode), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubScheduleID, sizeof(ubScheduleID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sEndDoorOpenCodeData, sizeof(sEndDoorOpenCodeData), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBlockedByAnotherMercDirection, sizeof(bBlockedByAnotherMercDirection), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usAttackingWeapon, sizeof(usAttackingWeapon), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bWeaponMode, sizeof(bWeaponMode), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubTargetID, sizeof(ubTargetID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bAIScheduleProgress, sizeof(bAIScheduleProgress), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sOffWorldGridNo, sizeof(sOffWorldGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pAniTile, sizeof(pAniTile), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bCamo, sizeof(bCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sAbsoluteFinalDestination, sizeof(sAbsoluteFinalDestination), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubHiResDirection, sizeof(ubHiResDirection), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubHiResDesiredDirection, sizeof(ubHiResDesiredDirection), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubLastFootPrintSound, sizeof(ubLastFootPrintSound), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bVehicleID, sizeof(bVehicleID), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bMovementDirection, sizeof(bMovementDirection), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sOldGridNo, sizeof(sOldGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usDontUpdateNewGridNoOnMoveAnimChange, sizeof(usDontUpdateNewGridNoOnMoveAnimChange), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sBoundingBoxWidth, sizeof(sBoundingBoxWidth), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sBoundingBoxHeight, sizeof(sBoundingBoxHeight), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sBoundingBoxOffsetX, sizeof(sBoundingBoxOffsetX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sBoundingBoxOffsetY, sizeof(sBoundingBoxOffsetY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiTimeSameBattleSndDone, sizeof(uiTimeSameBattleSndDone), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bOldBattleSnd, sizeof(bOldBattleSnd), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iBurstSoundID, sizeof(iBurstSoundID), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bSlotItemTakenFrom, sizeof(bSlotItemTakenFrom), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubAutoBandagingMedic, sizeof(ubAutoBandagingMedic), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubRobotRemoteHolderID, sizeof(ubRobotRemoteHolderID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiTimeOfLastContractUpdate, sizeof(uiTimeOfLastContractUpdate), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTypeOfLastContract, sizeof(bTypeOfLastContract), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTurnsCollapsed, sizeof(bTurnsCollapsed), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bSleepDrugCounter, sizeof(bSleepDrugCounter), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubMilitiaKills, sizeof(ubMilitiaKills), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bBlindedCounter, sizeof(bBlindedCounter), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubHoursOnAssignment, sizeof(ubHoursOnAssignment), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubMercJustFired, sizeof(ubMercJustFired), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubTurnsUntilCanSayHeardNoise, sizeof(ubTurnsUntilCanSayHeardNoise), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usQuoteSaidExtFlags, sizeof(usQuoteSaidExtFlags), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sContPathLocation, sizeof(sContPathLocation), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bGoodContPath, sizeof(bGoodContPath), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubPendingActionInterrupted, sizeof(ubPendingActionInterrupted), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bNoiseLevel, sizeof(bNoiseLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bRegenerationCounter, sizeof(bRegenerationCounter), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bRegenBoostersUsedToday, sizeof(bRegenBoostersUsedToday), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bNumPelletsHitBy, sizeof(bNumPelletsHitBy), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sSkillCheckGridNo, sizeof(sSkillCheckGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubLastEnemyCycledID, sizeof(ubLastEnemyCycledID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubPrevSectorID, sizeof(ubPrevSectorID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubNumTilesMovesSinceLastForget, sizeof(ubNumTilesMovesSinceLastForget), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTurningIncrement, sizeof(bTurningIncrement), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiBattleSoundID, sizeof(uiBattleSoundID), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->usValueGoneUp, sizeof(usValueGoneUp), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubNumLocateCycles, sizeof(ubNumLocateCycles), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDelayedMovementFlags, sizeof(ubDelayedMovementFlags), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubCTGTTargetID, sizeof(ubCTGTTargetID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiMercChecksum, sizeof(uiMercChecksum), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bCurrentCivQuote, sizeof(bCurrentCivQuote), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bCurrentCivQuoteDelta, sizeof(bCurrentCivQuoteDelta), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubMiscSoldierFlags, sizeof(ubMiscSoldierFlags), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubReasonCantFinishMove, sizeof(ubReasonCantFinishMove), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sLocationOfFadeStart, sizeof(sLocationOfFadeStart), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bUseExitGridForReentryDirection, sizeof(bUseExitGridForReentryDirection), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiTimeSinceLastSpoke, sizeof(uiTimeSinceLastSpoke), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubContractRenewalQuoteCode, sizeof(ubContractRenewalQuoteCode), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sPreTraversalGridNo, sizeof(sPreTraversalGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiXRayActivatedTime, sizeof(uiXRayActivatedTime), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bTurningFromUI, sizeof(bTurningFromUI), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bPendingActionData5, sizeof(bPendingActionData5), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bDelayedStrategicMoraleMod, sizeof(bDelayedStrategicMoraleMod), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubDoorOpeningNoise, sizeof(ubDoorOpeningNoise), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->pGroup, sizeof(pGroup), 1, numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubLeaveHistoryCode, sizeof(ubLeaveHistoryCode), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bOverrideMoveSpeed, sizeof(bOverrideMoveSpeed), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiTimeSoldierWillArrive, sizeof(uiTimeSoldierWillArrive), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bVehicleUnderRepairID, sizeof(bVehicleUnderRepairID), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iTimeCanSignElsewhere, sizeof(iTimeCanSignElsewhere), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bHospitalPriceModifier, sizeof(bHospitalPriceModifier), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiStartTimeOfInsuranceContract, sizeof(uiStartTimeOfInsuranceContract), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bCorpseQuoteTolerance, sizeof(bCorpseQuoteTolerance), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bDeafenedCounter, sizeof(bDeafenedCounter), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iPositionSndID, sizeof(iPositionSndID), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->iTuringSoundID, sizeof(iTuringSoundID), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubLastDamageReason, sizeof(ubLastDamageReason), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sLastTwoLocations, sizeof(sLastTwoLocations), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->uiTimeSinceLastBleedGrunt, sizeof(uiTimeSinceLastBleedGrunt), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->ubNextToPreviousAttackerID, sizeof(ubNextToPreviousAttackerID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->bDoAutofire, sizeof(bDoAutofire), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->numFlanks, sizeof(numFlanks), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->lastFlankSpot, sizeof(lastFlankSpot), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sniper, sizeof(sniper), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->origDir, sizeof(origDir), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->wornCamo, sizeof(wornCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->urbanCamo, sizeof(urbanCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->wornUrbanCamo, sizeof(wornUrbanCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->desertCamo, sizeof(desertCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->wornDesertCamo, sizeof(wornDesertCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->snowCamo, sizeof(snowCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->wornSnowCamo, sizeof(wornSnowCamo), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->sFacilityTypeOperated, sizeof(sFacilityTypeOperated), sizeof(INT16), numBytesRead); +// if(numBytesRead != SIZEOF_SOLDIERTYPE_POD) +// return(FALSE); +/* //CHRISL: It was further changed at version 104 to allow for 16bit action points for the 100AP system //first, load the POD if ( guiCurrentSaveGameVersion >= AP100_SAVEGAME_DATATYPE_CHANGE ) { @@ -1381,7 +1891,7 @@ BOOLEAN SOLDIERTYPE::Load(HWFILE hFile) numBytesRead += uiNumBytesRead; if(numBytesRead != SIZEOF_SOLDIERTYPE_POD) return(FALSE); - } + }*/ //load the OO inventory if ( !this->inv.Load(hFile) ) @@ -1491,10 +2001,33 @@ BOOLEAN SOLDIERTYPE::Load(HWFILE hFile) { return(FALSE); } - if ( !FileRead( hFile, &this->stats, sizeof(STRUCT_Statistics), &uiNumBytesRead ) ) + //Load STRUCT_AIData + numBytesRead = 0; + numBytesRead = ReadFieldByField(hFile, &this->stats.bExpLevel, sizeof(stats.bExpLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bLife, sizeof(stats.bLife), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bLifeMax, sizeof(stats.bLifeMax), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bStrength, sizeof(stats.bStrength), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bAgility, sizeof(stats.bAgility), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bDexterity, sizeof(stats.bDexterity), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bWisdom, sizeof(stats.bWisdom), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bLeadership, sizeof(stats.bLeadership), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bMarksmanship, sizeof(stats.bMarksmanship), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bMechanical, sizeof(stats.bMechanical), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bExplosive, sizeof(stats.bExplosive), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bMedical, sizeof(stats.bMedical), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.bScientific, sizeof(stats.bScientific), sizeof(INT8), numBytesRead); + if ( guiCurrentSaveGameVersion >= STOMP12_SAVEGAME_DATATYPE_CHANGE2 ) + numBytesRead = ReadFieldByField(hFile, &this->stats.ubSkillTraits, sizeof(stats.ubSkillTraits), sizeof(UINT8), numBytesRead); + else { - return(FALSE); + numBytesRead = ReadFieldByField(hFile, &this->stats.ubSkillTraits[0], sizeof(UINT8), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.ubSkillTraits[1], sizeof(UINT8), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &this->stats.ubSkillTraits[2], sizeof(UINT8), sizeof(UINT8), numBytesRead); } +// if ( !FileRead( hFile, &this->stats, sizeof(STRUCT_Statistics), &uiNumBytesRead ) ) +// { +// return(FALSE); +// } if ( !FileRead( hFile, &this->pathing, sizeof(STRUCT_Pathing), &uiNumBytesRead ) ) { return(FALSE); @@ -1584,6 +2117,7 @@ BOOLEAN WORLDITEM::Load(INT8** hBuffer, float dMajorMapVersion, UINT8 ubMinorMap } else LOADDATA(this, *hBuffer, SIZEOF_WORLDITEM_POD); + // Load the OO OBJECTTYPE this->object.Load(hBuffer, dMajorMapVersion, ubMinorMapVersion); } @@ -1637,6 +2171,54 @@ BOOLEAN WORLDITEM::Load(HWFILE hFile) return TRUE; } +BOOLEAN WORLDITEM::Load( HWFILE hFile, float dMajorMapVersion, UINT8 ubMinorMapVersion ) +{ + UINT32 uiNumBytesRead; + //if we are at the most current version, then fine + if(dMajorMapVersion >= 6.0 && ubMinorMapVersion > 26) + { + if(dMajorMapVersion < 7.0) + { + _OLD_WORLDITEM oldWorldItem; + + //load the POD + if ( !FileRead( hFile, this, _OLD_SIZEOF_WORLDITEM_POD, &uiNumBytesRead ) ) + { + return(FALSE); + } + *this = oldWorldItem; + } + else + { + //load the POD + if ( !FileRead( hFile, this, SIZEOF_WORLDITEM_POD, &uiNumBytesRead ) ) + { + return(FALSE); + } + } + + //now load the OO OBJECTTYPE + if ( !this->object.Load(hFile) ) + { + return FALSE; + } + } + //if we need to load an older save + else + { + //load the old data into a suitable structure, it's just POD + OLD_WORLDITEM_101 oldWorldItem; + if ( !FileRead( hFile, &oldWorldItem, sizeof(OLD_WORLDITEM_101), &uiNumBytesRead ) ) + { + return(FALSE); + } + + *this = oldWorldItem; + } + + return TRUE; +} + BOOLEAN StackedObjectData::Load( INT8** hBuffer, float dMajorMapVersion, UINT8 ubMinorMapVersion ) { //when this function is called, the file has been loaded into a buffer using FileRead @@ -1696,7 +2278,8 @@ BOOLEAN StackedObjectData::Save( HWFILE hFile, bool fSavingMap ) UINT32 uiNumBytesWritten; int size = 0; for (attachmentList::iterator iter = attachments.begin(); iter != attachments.end(); ++iter) { - if (iter->exists() == true) { + //WarmSteel - In fact, attachments CAN be null now with NAS. + if (iter->exists() == true || UsingNewAttachmentSystem()==true) { ++size; } else { @@ -1714,7 +2297,8 @@ BOOLEAN StackedObjectData::Save( HWFILE hFile, bool fSavingMap ) return(FALSE); } for (attachmentList::iterator iter = attachments.begin(); iter != attachments.end(); ++iter) { - if (iter->exists() == true) { + //WarmSteel - Can be null with NAS, sadly. + if (iter->exists() == true || UsingNewAttachmentSystem()==true) { if (! iter->Save(hFile, fSavingMap)) { return FALSE; } @@ -1785,6 +2369,7 @@ BOOLEAN OBJECTTYPE::Load( HWFILE hFile ) } */ } + RemoveProhibitedAttachments(NULL, this, (*this).usItem); return TRUE; } @@ -1815,6 +2400,7 @@ BOOLEAN OBJECTTYPE::Load( INT8** hBuffer, float dMajorMapVersion, UINT8 ubMinorM LOADDATA( &OldSavedObject101, *hBuffer, sizeof(OLD_OBJECTTYPE_101) ); (*this) = OldSavedObject101; } + RemoveProhibitedAttachments(NULL, this, (*this).usItem); return TRUE; } @@ -1983,11 +2569,11 @@ BOOLEAN InitSaveDir() #else if(is_networked) { - sprintf( gSaveDir, "%s", utf8string::as_utf8(pMessageStrings[ MSG_MPSAVEDIRECTORY ] + 3).c_str() ); + sprintf( gSaveDir, "%s", vfs::String::as_utf8(pMessageStrings[ MSG_MPSAVEDIRECTORY ] + 3).c_str() ); } else { - sprintf( gSaveDir, "%s", utf8string::as_utf8(pMessageStrings[ MSG_SAVEDIRECTORY ] + 3).c_str() ); + sprintf( gSaveDir, "%s", vfs::String::as_utf8(pMessageStrings[ MSG_SAVEDIRECTORY ] + 3).c_str() ); } #endif return TRUE; @@ -2020,7 +2606,7 @@ BOOLEAN SaveGame( int ubSaveGameID, STR16 pGameDesc ) #endif #endif - if( ubSaveGameID >= NUM_SAVE_GAMES && ubSaveGameID < EARLIST_SPECIAL_SAVE ) + if( ubSaveGameID > NUM_SLOT && ubSaveGameID < EARLIST_SPECIAL_SAVE ) return( FALSE ); //ddd alreadySaving = true; @@ -2112,8 +2698,8 @@ BOOLEAN SaveGame( int ubSaveGameID, STR16 pGameDesc ) if(is_networked) { SaveGameHeader.uiDay = CLIENT_NUM; - SaveGameHeader.ubHour = MAX_CLIENTS; - SaveGameHeader.ubMin = MAX_MERCS; + SaveGameHeader.ubHour = cMaxClients; + SaveGameHeader.ubMin = cMaxMercs; } //copy over the initial game options @@ -2144,6 +2730,8 @@ BOOLEAN SaveGame( int ubSaveGameID, STR16 pGameDesc ) // CHRISL: We need to know what inventory system we're using early on SaveGameHeader.ubInventorySystem = gGameOptions.ubInventorySystem; + SaveGameHeader.ubAttachmentSystem = gGameOptions.ubAttachmentSystem; + // // Save the Save Game header file // @@ -2864,8 +3452,36 @@ BOOLEAN SaveGame( int ubSaveGameID, STR16 pGameDesc ) ScreenMsg( FONT_MCOLOR_WHITE, MSG_ERROR, L"ERROR writing mail orders"); goto FAILED_TO_SAVE; } + + //New profiles by Jazz + if( !SaveNewMercsToSaveGameFile( hFile ) ) + { + ScreenMsg( FONT_MCOLOR_WHITE, MSG_ERROR, L"ERROR writing mercs profiles"); + goto FAILED_TO_SAVE; + } + #ifdef JA2BETAVERSION + SaveGameFilePosition( FileGetPos( hFile ), "New Mercs Profiles" ); + #endif + + //New system profiles by Jazz + if( !SaveNewSystemMercsToSaveGameFile( hFile ) ) + { + ScreenMsg( FONT_MCOLOR_WHITE, MSG_ERROR, L"ERROR writing new system mercs profiles"); + goto FAILED_TO_SAVE; + } + #ifdef JA2BETAVERSION + SaveGameFilePosition( FileGetPos( hFile ), "New system Mercs Profiles" ); + #endif - + //save lua global + if( !SaveLuaGlobalToSaveGameFile( hFile ) ) + { + ScreenMsg( FONT_MCOLOR_WHITE, MSG_ERROR, L"ERROR writing lua global"); + goto FAILED_TO_SAVE; + } + #ifdef JA2BETAVERSION + SaveGameFilePosition( FileGetPos( hFile ), "Lua global" ); + #endif //Close the saved game file FileClose( hFile ); @@ -2901,7 +3517,7 @@ BOOLEAN SaveGame( int ubSaveGameID, STR16 pGameDesc ) } //restore the music mode - SetMusicMode( gubMusicMode ); + SetMusicMode( GetMusicMode() ); //Unset the fact that we are saving a game gTacticalStatus.uiFlags &= ~LOADING_SAVED_GAME; @@ -3013,7 +3629,7 @@ BOOLEAN LoadSavedGame( int ubSavedGameID ) #endif //is it a valid save number - if( ubSavedGameID >= NUM_SAVE_GAMES ) + if( ubSavedGameID >= NUM_SLOT ) { if( ubSavedGameID != SAVE__END_TURN_NUM ) return( FALSE ); @@ -3094,9 +3710,10 @@ BOOLEAN LoadSavedGame( int ubSavedGameID ) if(SaveGameHeader.uiSavedGameVersion < NIV_SAVEGAME_DATATYPE_CHANGE) SaveGameHeader.ubInventorySystem = 0; gGameOptions.ubInventorySystem = SaveGameHeader.ubInventorySystem; + if((UsingNewInventorySystem() == true)) { - if(IsNIVModeValid() == FALSE){ + if(IsNIVModeValid(true) == FALSE){ // Only load NewInv in higher screen res FileClose( hFile ); return(FALSE); @@ -3108,11 +3725,16 @@ BOOLEAN LoadSavedGame( int ubSavedGameID ) } else { + if(UsingNewAttachmentSystem()==true) + return(FALSE); + InitInventoryOld(); InitOldInventorySystem(); InitializeSMPanelCoordsOld(); InitializeInvPanelCoordsOld(); } + + gGameOptions.ubAttachmentSystem = SaveGameHeader.ubAttachmentSystem; //if the player is loading up an older version of the game, and the person DOESNT have the cheats on, if( guiCurrentSaveGameVersion < 65 && !CHEATER_CHEAT_LEVEL( ) ) @@ -4200,14 +4822,68 @@ BOOLEAN LoadSavedGame( int ubSavedGameID ) } } + uiRelEndPerc += 1; + SetRelativeStartAndEndPercentage( 0, uiRelStartPerc, uiRelEndPerc, L"Load New Mercs Prfiles..." ); + RenderProgressBar( 0, 100 ); + uiRelStartPerc = uiRelEndPerc; + + + if( guiCurrentSaveGameVersion >= 113 ) + { + if( !LoadNewMercsFromLoadGameFile( hFile ) ) + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("LoadNewMercsFromLoadGameFile failed" ) ); + FileClose( hFile ); + return( FALSE ); + } + } + #ifdef JA2BETAVERSION + LoadGameFilePosition( FileGetPos( hFile ), "Load Mercs Prfiles" ); + #endif + + uiRelEndPerc += 1; + SetRelativeStartAndEndPercentage( 0, uiRelStartPerc, uiRelEndPerc, L"Load New Sytem Mercs Prfiles..." ); + RenderProgressBar( 0, 100 ); + uiRelStartPerc = uiRelEndPerc; + + if( guiCurrentSaveGameVersion >= 113 ) + { + if( !LoadNewSystemMercsToSaveGameFile( hFile ) ) + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("LoadNewSystemMercsToSaveGameFile failed" ) ); + FileClose( hFile ); + return( FALSE ); + } + } + #ifdef JA2BETAVERSION + LoadGameFilePosition( FileGetPos( hFile ), "Load New Sytem Mercs Prfiles" ); + #endif uiRelEndPerc += 1; SetRelativeStartAndEndPercentage( 0, uiRelStartPerc, uiRelEndPerc, L"Final Checks..." ); RenderProgressBar( 0, 100 ); uiRelStartPerc = uiRelEndPerc; + uiRelEndPerc += 1; + SetRelativeStartAndEndPercentage( 0, uiRelStartPerc, uiRelEndPerc, L"Lua Global System..." ); + RenderProgressBar( 0, 100 ); + uiRelStartPerc = uiRelEndPerc; + if( guiCurrentSaveGameVersion >= 114 ) + { + if( !LoadLuaGlobalFromLoadGameFile( hFile ) ) + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("LoadLuaGlobalFromLoadGameFile failed" ) ); + FileClose( hFile ); + return FALSE; + } + } + #ifdef JA2BETAVERSION + LoadGameFilePosition( FileGetPos( hFile ), "Lua Global System" ); + #endif + + // //Close the saved game file // @@ -4499,7 +5175,6 @@ BOOLEAN LoadSavedGame( int ubSavedGameID ) //now change the savegame format so that temp files are saved and loaded correctly guiCurrentSaveGameVersion = SAVE_GAME_VERSION; - return( TRUE ); } @@ -4757,10 +5432,10 @@ BOOLEAN LoadSoldierStructure( HWFILE hFile ) } //if the soldier is an IMP character - if( Menptr[cnt].ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER && Menptr[cnt].bTeam == gbPlayerNum ) - { - ResetIMPCharactersEyesAndMouthOffsets( Menptr[ cnt ].ubProfile ); - } + //if( Menptr[cnt].ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER && Menptr[cnt].bTeam == gbPlayerNum ) + //{ + // ResetIMPCharactersEyesAndMouthOffsets( Menptr[ cnt ].ubProfile ); + //} //if the saved game version is before x, calculate the amount of money paid to mercs if( guiCurrentSaveGameVersion < 83 ) @@ -6003,7 +6678,7 @@ BOOLEAN SaveGeneralInfo( HWFILE hFile ) GENERAL_SAVE_INFO sGeneralInfo; memset( &sGeneralInfo, 0, sizeof( GENERAL_SAVE_INFO ) ); - sGeneralInfo.ubMusicMode = gubMusicMode; + sGeneralInfo.ubMusicMode = GetMusicMode(); sGeneralInfo.uiCurrentUniqueSoldierId = guiCurrentUniqueSoldierId; sGeneralInfo.uiCurrentScreen = guiPreviousOptionScreen; @@ -6018,6 +6693,7 @@ BOOLEAN SaveGeneralInfo( HWFILE hFile ) sGeneralInfo.fShowMineFlag = fShowMineFlag; sGeneralInfo.fShowAircraftFlag = fShowAircraftFlag; sGeneralInfo.fShowTeamFlag = fShowTeamFlag; + sGeneralInfo.fShowMobileRestrictionsFlag = fShowMobileRestrictionsFlag; // HEADROCK HAM 4 sGeneralInfo.fHelicopterAvailable = fHelicopterAvailable; @@ -6216,6 +6892,15 @@ BOOLEAN SaveGeneralInfo( HWFILE hFile ) // HEADROCK HAM 3.6: Save new global variable for militia upkeep sGeneralInfo.uiTotalUpkeepForMilitia = guiTotalUpkeepForMilitia; + // HEADROCK HAM 4: Save global array for Manual Mobile Militia Restrictions + // testing for loop + memcpy(sGeneralInfo.ubManualRestrictMilitia, gubManualRestrictMilitia, sizeof( UINT8 )*256); + + for (int i=0;i<500;i++) + { + sGeneralInfo.HiddenNames[i] = !zHiddenNames[i].Hidden; //legion2 + } + //Setup the //Save the current music mode FileWrite( hFile, &sGeneralInfo, sizeof( GENERAL_SAVE_INFO ), &uiNumBytesWritten ); @@ -6234,15 +6919,145 @@ extern UINT32 guiRainLoop; BOOLEAN LoadGeneralInfo( HWFILE hFile ) { - UINT32 uiNumBytesRead; + //UINT32 uiNumBytesRead; + INT32 numBytesRead = 0; + UINT8 filler = 0; GENERAL_SAVE_INFO sGeneralInfo; memset( &sGeneralInfo, 0, sizeof( GENERAL_SAVE_INFO ) ); - + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiCurrentScreen, sizeof(sGeneralInfo.uiCurrentScreen), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiCurrentUniqueSoldierId, sizeof(sGeneralInfo.uiCurrentUniqueSoldierId), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubMusicMode, sizeof(sGeneralInfo.ubMusicMode), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHavePurchasedItemsFromTony, sizeof(sGeneralInfo.fHavePurchasedItemsFromTony), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.usSelectedSoldier, sizeof(sGeneralInfo.usSelectedSoldier), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sRenderCenterX, sizeof(sGeneralInfo.sRenderCenterX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sRenderCenterY, sizeof(sGeneralInfo.sRenderCenterY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fAtLeastOneMercWasHired, sizeof(sGeneralInfo.fAtLeastOneMercWasHired), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowItemsFlag, sizeof(sGeneralInfo.fShowItemsFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowTownFlag, sizeof(sGeneralInfo.fShowTownFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowTeamFlag, sizeof(sGeneralInfo.fShowTeamFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowMineFlag, sizeof(sGeneralInfo.fShowMineFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowAircraftFlag, sizeof(sGeneralInfo.fShowAircraftFlag), sizeof(BOOLEAN), numBytesRead); + if ( guiCurrentSaveGameVersion >= NEW_GENERAL_SAVE_INFO_DATA ) + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowMobileRestrictionsFlag, sizeof(sGeneralInfo.fShowMobileRestrictionsFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHelicopterAvailable, sizeof(sGeneralInfo.fHelicopterAvailable), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iHelicopterVehicleId, sizeof(sGeneralInfo.iHelicopterVehicleId), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.UNUSEDiTotalHeliDistanceSinceRefuel, sizeof(sGeneralInfo.UNUSEDiTotalHeliDistanceSinceRefuel), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iTotalAccumulatedCostByPlayer, sizeof(sGeneralInfo.iTotalAccumulatedCostByPlayer), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fSkyRiderAvailable, sizeof(sGeneralInfo.fSkyRiderAvailable), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.UNUSEDfSkyriderMonologue, sizeof(sGeneralInfo.UNUSEDfSkyriderMonologue), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.UNUSED, sizeof(sGeneralInfo.UNUSED), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHelicopterIsAirBorne, sizeof(sGeneralInfo.fHelicopterIsAirBorne), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHeliReturnStraightToBase, sizeof(sGeneralInfo.fHeliReturnStraightToBase), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHoveringHelicopter, sizeof(sGeneralInfo.fHoveringHelicopter), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiStartHoverTime, sizeof(sGeneralInfo.uiStartHoverTime), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiHelicopterSkyriderTalkState, sizeof(sGeneralInfo.uiHelicopterSkyriderTalkState), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowEstoniRefuelHighLight, sizeof(sGeneralInfo.fShowEstoniRefuelHighLight), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowOtherSAMHighLight, sizeof(sGeneralInfo.fShowOtherSAMHighLight), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowDrassenSAMHighLight, sizeof(sGeneralInfo.fShowDrassenSAMHighLight), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiEnvWeather, sizeof(sGeneralInfo.uiEnvWeather), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubDefaultButton, sizeof(sGeneralInfo.ubDefaultButton), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fSkyriderEmptyHelpGiven, sizeof(sGeneralInfo.fSkyriderEmptyHelpGiven), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fEnterMapDueToContract, sizeof(sGeneralInfo.fEnterMapDueToContract), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubHelicopterHitsTaken, sizeof(sGeneralInfo.ubHelicopterHitsTaken), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubQuitType, sizeof(sGeneralInfo.ubQuitType), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fSkyriderSaidCongratsOnTakingSAM, sizeof(sGeneralInfo.fSkyriderSaidCongratsOnTakingSAM), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sContractRehireSoldierID, sizeof(sGeneralInfo.sContractRehireSoldierID), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.GameOptions, sizeof(sGeneralInfo.GameOptions), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiSeedNumber, sizeof(sGeneralInfo.uiSeedNumber), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiBaseJA2Clock, sizeof(sGeneralInfo.uiBaseJA2Clock), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sCurInterfacePanel, sizeof(sGeneralInfo.sCurInterfacePanel), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubSMCurrentMercID, sizeof(sGeneralInfo.ubSMCurrentMercID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fFirstTimeInMapScreen, sizeof(sGeneralInfo.fFirstTimeInMapScreen), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fDisableDueToBattleRoster, sizeof(sGeneralInfo.fDisableDueToBattleRoster), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fDisableMapInterfaceDueToBattle, sizeof(sGeneralInfo.fDisableMapInterfaceDueToBattle), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sBoxerGridNo, sizeof(sGeneralInfo.sBoxerGridNo), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubBoxerID, sizeof(sGeneralInfo.ubBoxerID), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fBoxerFought, sizeof(sGeneralInfo.fBoxerFought), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHelicopterDestroyed, sizeof(sGeneralInfo.fHelicopterDestroyed), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowMapScreenHelpText, sizeof(sGeneralInfo.fShowMapScreenHelpText), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iSortStateForMapScreenList, sizeof(sGeneralInfo.iSortStateForMapScreenList), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fFoundTixa, sizeof(sGeneralInfo.fFoundTixa), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiTimeOfLastSkyriderMonologue, sizeof(sGeneralInfo.uiTimeOfLastSkyriderMonologue), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowCambriaHospitalHighLight, sizeof(sGeneralInfo.fShowCambriaHospitalHighLight), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fSkyRiderSetUp, sizeof(sGeneralInfo.fSkyRiderSetUp), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fRefuelingSiteAvailable, sizeof(sGeneralInfo.fRefuelingSiteAvailable), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.gCurrentMeanwhileDef, sizeof(sGeneralInfo.gCurrentMeanwhileDef), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubPlayerProgressSkyriderLastCommentedOn, sizeof(sGeneralInfo.ubPlayerProgressSkyriderLastCommentedOn), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.gfMeanwhileTryingToStart, sizeof(sGeneralInfo.gfMeanwhileTryingToStart), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.gfInMeanwhile, sizeof(sGeneralInfo.gfInMeanwhile), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sDeadMercs, sizeof(sGeneralInfo.sDeadMercs), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.gbPublicNoiseLevel, sizeof(sGeneralInfo.gbPublicNoiseLevel), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.gubScreenCount, sizeof(sGeneralInfo.gubScreenCount), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.usOldMeanWhileFlags, sizeof(sGeneralInfo.usOldMeanWhileFlags), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iPortraitNumber, sizeof(sGeneralInfo.iPortraitNumber), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sWorldSectorLocationOfFirstBattle, sizeof(sGeneralInfo.sWorldSectorLocationOfFirstBattle), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fUnReadMailFlag, sizeof(sGeneralInfo.fUnReadMailFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fNewMailFlag, sizeof(sGeneralInfo.fNewMailFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fOldUnReadFlag, sizeof(sGeneralInfo.fOldUnReadFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fOldNewMailFlag, sizeof(sGeneralInfo.fOldNewMailFlag), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fShowMilitia, sizeof(sGeneralInfo.fShowMilitia), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fNewFilesInFileViewer, sizeof(sGeneralInfo.fNewFilesInFileViewer), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fLastBoxingMatchWonByPlayer, sizeof(sGeneralInfo.fLastBoxingMatchWonByPlayer), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiUNUSED, sizeof(sGeneralInfo.uiUNUSED), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fSamSiteFound, sizeof(sGeneralInfo.fSamSiteFound), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubNumTerrorists, sizeof(sGeneralInfo.ubNumTerrorists), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubCambriaMedicalObjects, sizeof(sGeneralInfo.ubCambriaMedicalObjects), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fDisableTacticalPanelButtons, sizeof(sGeneralInfo.fDisableTacticalPanelButtons), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sSelMapX, sizeof(sGeneralInfo.sSelMapX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sSelMapY, sizeof(sGeneralInfo.sSelMapY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iCurrentMapSectorZ, sizeof(sGeneralInfo.iCurrentMapSectorZ), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.usHasPlayerSeenHelpScreenInCurrentScreen, sizeof(sGeneralInfo.usHasPlayerSeenHelpScreenInCurrentScreen), sizeof(UINT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fHideHelpInAllScreens, sizeof(sGeneralInfo.fHideHelpInAllScreens), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubBoxingMatchesWon, sizeof(sGeneralInfo.ubBoxingMatchesWon), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubBoxersRests, sizeof(sGeneralInfo.ubBoxersRests), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fBoxersResting, sizeof(sGeneralInfo.fBoxersResting), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubDesertTemperature, sizeof(sGeneralInfo.ubDesertTemperature), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubGlobalTemperature, sizeof(sGeneralInfo.ubGlobalTemperature), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sMercArriveSectorX, sizeof(sGeneralInfo.sMercArriveSectorX), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sMercArriveSectorY, sizeof(sGeneralInfo.sMercArriveSectorY), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fCreatureMeanwhileScenePlayed, sizeof(sGeneralInfo.fCreatureMeanwhileScenePlayed), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubPlayerNum, sizeof(sGeneralInfo.ubPlayerNum), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fPersistantPBI, sizeof(sGeneralInfo.fPersistantPBI), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubEnemyEncounterCode, sizeof(sGeneralInfo.ubEnemyEncounterCode), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubExplicitEnemyEncounterCode, sizeof(sGeneralInfo.ubExplicitEnemyEncounterCode), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fBlitBattleSectorLocator, sizeof(sGeneralInfo.fBlitBattleSectorLocator), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubPBSectorX, sizeof(sGeneralInfo.ubPBSectorX), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubPBSectorY, sizeof(sGeneralInfo.ubPBSectorY), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubPBSectorZ, sizeof(sGeneralInfo.ubPBSectorZ), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fCantRetreatInPBI, sizeof(sGeneralInfo.fCantRetreatInPBI), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fExplosionQueueActive, sizeof(sGeneralInfo.fExplosionQueueActive), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubUnused, sizeof(sGeneralInfo.ubUnused), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiMeanWhileFlags, sizeof(sGeneralInfo.uiMeanWhileFlags), sizeof(UINT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.bSelectedInfoChar, sizeof(sGeneralInfo.bSelectedInfoChar), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.bHospitalPriceModifier, sizeof(sGeneralInfo.bHospitalPriceModifier), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.bUnused2, sizeof(sGeneralInfo.bUnused2), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iHospitalTempBalance, sizeof(sGeneralInfo.iHospitalTempBalance), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iHospitalRefund, sizeof(sGeneralInfo.iHospitalRefund), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fPlayerTeamSawJoey, sizeof(sGeneralInfo.fPlayerTeamSawJoey), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fMikeShouldSayHi, sizeof(sGeneralInfo.fMikeShouldSayHi), sizeof(INT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.iTotalOwedForFacilityOperationsToday, sizeof(sGeneralInfo.iTotalOwedForFacilityOperationsToday), sizeof(INT32), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.sSkyriderCostModifier, sizeof(sGeneralInfo.sSkyriderCostModifier), sizeof(INT16), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.fOutstandingFacilityDebt, sizeof(sGeneralInfo.fOutstandingFacilityDebt), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.uiTotalUpkeepForMilitia, sizeof(sGeneralInfo.uiTotalUpkeepForMilitia), sizeof(UINT32), numBytesRead); + if ( guiCurrentSaveGameVersion >= NEW_GENERAL_SAVE_INFO_DATA ){ + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubManualRestrictMilitia, sizeof(sGeneralInfo.ubManualRestrictMilitia), sizeof(UINT8), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.HiddenNames, sizeof(sGeneralInfo.HiddenNames), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubFiller, sizeof(sGeneralInfo.ubFiller), sizeof(UINT8), numBytesRead); + } else { + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.HiddenNames, sizeof(sGeneralInfo.HiddenNames), sizeof(BOOLEAN), numBytesRead); + numBytesRead = ReadFieldByField(hFile, &sGeneralInfo.ubFiller, sizeof(sGeneralInfo.ubFiller), sizeof(UINT8), numBytesRead); + for(UINT32 count = 0; count < sizeof(sGeneralInfo.ubManualRestrictMilitia); count++) + numBytesRead = ReadFieldByField(hFile, &filler, sizeof(filler), sizeof(UINT8), numBytesRead); + } + //CHRISL: GENERAL_SAVE_INFO is only 1586 but we have to read in DWORD lengths so we need to read additional filler bits from the save game file + for(UINT32 count = numBytesRead; count < sizeof( GENERAL_SAVE_INFO ); count++) + numBytesRead = ReadFieldByField(hFile, &filler, sizeof(filler), sizeof(UINT8), numBytesRead); //Load the current music mode - FileRead( hFile, &sGeneralInfo, sizeof( GENERAL_SAVE_INFO ), &uiNumBytesRead ); - if( uiNumBytesRead != sizeof( GENERAL_SAVE_INFO ) ) + //FileRead( hFile, &sGeneralInfo, sizeof( GENERAL_SAVE_INFO ), &uiNumBytesRead ); + //if( uiNumBytesRead != sizeof( GENERAL_SAVE_INFO ) ) + if( numBytesRead != sizeof( GENERAL_SAVE_INFO ) ) { FileClose( hFile ); return( FALSE ); @@ -6271,6 +7086,7 @@ BOOLEAN LoadGeneralInfo( HWFILE hFile ) fShowMineFlag = sGeneralInfo.fShowMineFlag; fShowAircraftFlag = sGeneralInfo.fShowAircraftFlag; fShowTeamFlag = sGeneralInfo.fShowTeamFlag; + fShowMobileRestrictionsFlag = sGeneralInfo.fShowMobileRestrictionsFlag; fHelicopterAvailable = sGeneralInfo.fHelicopterAvailable; @@ -6500,6 +7316,94 @@ BOOLEAN LoadGeneralInfo( HWFILE hFile ) // HEADROCK HAM 3.6: Load new global variable for militia upkeep guiTotalUpkeepForMilitia = sGeneralInfo.uiTotalUpkeepForMilitia; + // HEADROCK HAM 4: Load Manual Mobile Militia Restrictions + memcpy(gubManualRestrictMilitia, sGeneralInfo.ubManualRestrictMilitia, sizeof(UINT8) * 256); + + for (int i=0;i<500;i++) + { + zHiddenNames[i].Hidden = !sGeneralInfo.HiddenNames[i]; + } + + if ( gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + + //Camo Face by Jazz + for (int i=0;i<255;i++) + { + gCamoFace[i].gCamoface = FALSE; + gCamoFace[i].gUrbanCamoface = FALSE; + gCamoFace[i].gDesertCamoface = FALSE; + gCamoFace[i].gSnowCamoface = FALSE; + } + + SOLDIERTYPE * pSoldier; + INT8 bMercID, bLastTeamID; + bMercID = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; + bLastTeamID = gTacticalStatus.Team[ gbPlayerNum ].bLastID; + for ( pSoldier = MercPtrs[ bMercID ]; bMercID <= bLastTeamID; bMercID++,pSoldier++) + { + if ( pSoldier->bCamo > 0 ) + { + gCamoFace[pSoldier->ubProfile].gCamoface = TRUE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + else + { + gCamoFace[pSoldier->ubProfile].gCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + if ( pSoldier->urbanCamo > 0 ) + { + gCamoFace[pSoldier->ubProfile].gUrbanCamoface = TRUE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + else + { + gCamoFace[pSoldier->ubProfile].gUrbanCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + + if ( pSoldier->desertCamo > 0 ) + { + gCamoFace[pSoldier->ubProfile].gDesertCamoface = TRUE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + else + { + gCamoFace[pSoldier->ubProfile].gDesertCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + if ( pSoldier->snowCamo > 0 ) + { + gCamoFace[pSoldier->ubProfile].gSnowCamoface = TRUE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + else + { + gCamoFace[pSoldier->ubProfile].gSnowCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + + if ( pSoldier->snowCamo == 0 && pSoldier->bCamo == 0 && pSoldier->urbanCamo == 0 && pSoldier->desertCamo == 0) + { + gCamoFace[pSoldier->ubProfile].gCamoface = FALSE; + gCamoFace[pSoldier->ubProfile].gUrbanCamoface = FALSE; + gCamoFace[pSoldier->ubProfile].gDesertCamoface = FALSE; + gCamoFace[pSoldier->ubProfile].gSnowCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } + } + return( TRUE ); } diff --git a/SaveLoadGame.h b/SaveLoadGame.h index 26c4b4cb..f1966f0f 100644 --- a/SaveLoadGame.h +++ b/SaveLoadGame.h @@ -21,7 +21,7 @@ class SOLDIERTYPE; // WDS - Automatically try to save when an assertion failure occurs #define SAVE__ASSERTION_FAILURE 97 -#define SAVE__TIMED_AUTOSAVE 11 +#define SAVE__TIMED_AUTOSAVE 19 // WANNE: This slot does not show up in the load/save screen because it is > 18 #define EARLIST_SPECIAL_SAVE 97 @@ -64,9 +64,9 @@ typedef struct UINT8 ubInventorySystem; - UINT8 ubFiller[109]; - + UINT8 ubAttachmentSystem; + UINT8 ubFiller[108]; // WANNE: Changed from 109 to 108 because of ubNewAttachmentSystem integration } SAVED_GAME_HEADER; diff --git a/SaveLoadScreen.cpp b/SaveLoadScreen.cpp index 82ed886f..baf66743 100644 --- a/SaveLoadScreen.cpp +++ b/SaveLoadScreen.cpp @@ -45,6 +45,8 @@ BOOLEAN gfSchedulesHosed = FALSE; extern UINT32 guiBrokenSaveGameVersion; +UINT16 NUM_SLOT; + ////////////////////////////////////////////////////// // // Defines @@ -89,15 +91,13 @@ extern UINT32 guiBrokenSaveGameVersion; #define SLG_UNSELECTED_COLOR FONT_MCOLOR_DKWHITE #define SLG_SAVELOCATION_WIDTH 605 -#define SLG_SAVELOCATION_HEIGHT 30//46 +//#define SLG_SAVELOCATION_HEIGHT 30//46 //legion off #define SLG_FIRST_SAVED_SPOT_X iScreenWidthOffset + 17 #define SLG_FIRST_SAVED_SPOT_Y iScreenHeightOffset + 49 -#define SLG_GAP_BETWEEN_LOCATIONS 35//47 - - +//#define SLG_GAP_BETWEEN_LOCATIONS 35//47 //legion off #define SLG_DATE_OFFSET_X 13 -#define SLG_DATE_OFFSET_Y 11 +//#define SLG_DATE_OFFSET_Y 11 //legion off #define SLG_SECTOR_OFFSET_X 95//105//114 #define SLG_SECTOR_OFFSET_Y SLG_DATE_OFFSET_Y @@ -122,8 +122,8 @@ extern UINT32 guiBrokenSaveGameVersion; #define SLG_SAVE_LOAD_BTN_POS_X iScreenWidthOffset + 123 #define SLG_SAVE_LOAD_BTN_POS_Y iScreenHeightOffset + 438 -#define SLG_SELECTED_SLOT_GRAPHICS_NUMBER 3 -#define SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER 2 +//#define SLG_SELECTED_SLOT_GRAPHICS_NUMBER 3 //legion off +//#define SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER 2 //legion off #define SLG_DOUBLE_CLICK_DELAY 500 @@ -176,6 +176,12 @@ INT8 gbSetSlotToBeSelected=-1; UINT32 guiSlgBackGroundImage; UINT32 guiBackGroundAddOns; +UINT32 guiBackGroundAddOns_New; +UINT32 SLG_SAVELOCATION_HEIGHT; +UINT32 SLG_GAP_BETWEEN_LOCATIONS; +UINT32 SLG_DATE_OFFSET_Y; +UINT32 SLG_SELECTED_SLOT_GRAPHICS_NUMBER; +UINT32 SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER; // The string that will contain the game desc text CHAR16 gzGameDescTextField[ SIZE_OF_SAVE_GAME_DESC ] = {0} ; @@ -194,7 +200,7 @@ BOOLEAN gfLoadedGame = FALSE; //Used to know when a game has been loaded, the f BOOLEAN gfLoadGameUponEntry = FALSE; -BOOLEAN gfHadToMakeBasementLevels = FALSE; +//BOOLEAN gfHadToMakeBasementLevels = FALSE; BOOLEAN gfGettingNameFromSaveLoadScreen = FALSE; @@ -280,6 +286,37 @@ void StartFadeOutForSaveLoadScreen(); // ////////////////////////////////////////////////////// +void LoadSaveGameOldOrNew() +{ + if (gGameExternalOptions.fSaveGameSlot == TRUE) + { + NUM_SLOT = NUM_SAVE_GAMES_NEW; + //SAVE_LOAD_SELECTED_FONT = FONT12ARIAL; + //SAVE_LOAD_NUMBER_FONT = FONT12ARIAL; + //SAVE_LOAD_HIGHLIGHTED_FONT = FONT12ARIAL; + //SAVE_LOAD_NORMAL_FONT = FONT12ARIAL; + SLG_SAVELOCATION_HEIGHT = 15; + SLG_GAP_BETWEEN_LOCATIONS = 20; + SLG_DATE_OFFSET_Y = 5; + SLG_SELECTED_SLOT_GRAPHICS_NUMBER = 1; + SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER = 0; + } + else + { + NUM_SLOT = NUM_SAVE_GAMES_OLD; + //SAVE_LOAD_SELECTED_FONT = FONT12ARIAL; + //SAVE_LOAD_NUMBER_FONT = FONT12ARIAL; + //SAVE_LOAD_HIGHLIGHTED_FONT = FONT12ARIAL; + //SAVE_LOAD_NORMAL_FONT = FONT12ARIAL; + SLG_SAVELOCATION_HEIGHT = 30; + SLG_GAP_BETWEEN_LOCATIONS = 35; + SLG_DATE_OFFSET_Y = 11; + SLG_SELECTED_SLOT_GRAPHICS_NUMBER = 3; + SLG_UNSELECTED_SLOT_GRAPHICS_NUMBER = 2; + } + +} + UINT32 SaveLoadScreenInit() { @@ -466,18 +503,23 @@ BOOLEAN EnterSaveLoadScreen() // if( guiPreviousOptionScreen != MAINMENU_SCREEN ) // gbSetSlotToBeSelected = -1; - // This is a hack to get sector names , but... if the underground sector is NOT loaded - if( !gpUndergroundSectorInfoHead ) - { - BuildUndergroundSectorInfoList(); - gfHadToMakeBasementLevels = TRUE; - } - else - { - gfHadToMakeBasementLevels = FALSE; - } + // In reality, this is not needed, but even screws things up + //// This is a hack to get sector names , but... if the underground sector is NOT loaded + //if( !gpUndergroundSectorInfoHead ) + //{ + // BuildUndergroundSectorInfoList(); + // gfHadToMakeBasementLevels = TRUE; + //} + //else + //{ + // gfHadToMakeBasementLevels = FALSE; + //} + + //guiSaveLoadExitScreen = SAVE_LOAD_SCREEN; + // this is where we came from; if loading of resources fails, this is also where we go next/back + extern UINT32 guiPreviousScreen; + guiSaveLoadExitScreen = guiPreviousScreen; - guiSaveLoadExitScreen = SAVE_LOAD_SCREEN; //init the list InitSaveGameArray(); @@ -510,6 +552,14 @@ BOOLEAN EnterSaveLoadScreen() VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; GetMLGFilename( VObjectDesc.ImageFile, MLG_LOADSAVEHEADER ); CHECKF(AddVideoObject(&VObjectDesc, &guiBackGroundAddOns)); + + if (gGameExternalOptions.fSaveGameSlot == TRUE) + { + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + FilenameForBPP("INTERFACE\\LOADSCREENADDONS_SAVEGAME.sti", VObjectDesc.ImageFile); + CHECKF(AddVideoObject(&VObjectDesc, &guiBackGroundAddOns_New)); + } + guiSlgButtonImage = LoadButtonImage("INTERFACE\\LoadScreenAddOns.sti", -1,6,-1,9,-1 ); @@ -580,7 +630,7 @@ BOOLEAN EnterSaveLoadScreen() usPosX = SLG_FIRST_SAVED_SPOT_X; usPosY = SLG_FIRST_SAVED_SPOT_Y; - for(i=0; i= NUM_SAVE_GAMES || bSaveGameID < 0 ) + if( bSaveGameID >= NUM_SLOT || bSaveGameID < 0 ) { return; } @@ -1164,7 +1221,7 @@ BOOLEAN InitSaveGameArray() SAVED_GAME_HEADER SaveGameHeader; - for( cnt=0; cnt NUM_SAVE_GAMES ) + if( bEntry < 0 || bEntry > NUM_SLOT ) { //memset( &pSaveGameHeader, 0, sizeof( SAVED_GAME_HEADER ) ); memset( pSaveGameHeader, 0, sizeof( SAVED_GAME_HEADER ) ); @@ -1685,7 +1749,7 @@ void SelectedSaveRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) } //Reset the regions - for( i=0; i= 1 && gbSelectedSaveLocation < NUM_SAVE_GAMES-1 ) + if( gbSelectedSaveLocation >= 1 && gbSelectedSaveLocation < NUM_SLOT-1 ) { SetSelection( (UINT8)(gbSelectedSaveLocation + 1) ); } @@ -2542,7 +2606,7 @@ void MoveSelectionUpOrDown( BOOLEAN fUp ) } else { - for( i=gbSelectedSaveLocation+1; i /* #ifdef __cplusplus @@ -217,9 +217,73 @@ extern void _DebugMessage(const char *pSourceFile, unsigned uiLineNum, const cha #define DebugAttackBusy(x) #endif -#include "VFS/vfs_debug.h" +#define SGP_CALLER_LOCATION , int line=0, const char* function=NULL, const char* file=NULL +#define SGP_CALLER_LOCATION_IMPL , int line, const char* function, const char* file +#define SGP_GET_CALLER_LOCATION , __LINE__, __FUNCTION__, __FILE__ +#define SGP_SET_CALLER_LOCATION , line, function, file -void _ExceptionMessage( CBasicException &ex ); +#include +#include + +namespace vfs { class Exception; } +namespace sgp +{ + class WString + { + public: + WString(std::string const& s){ + convert_string(s,str); + } + WString(const char* s) { + convert_string(s,str); + } + WString(std::wstring const& s) : str(s) { + } + WString(const wchar_t* s) : str(s) { + } + public: + std::wstring str; + }; + + class Exception : public std::exception + { + public: + Exception(WString const& msg SGP_CALLER_LOCATION); + + // default exception + Exception(WString const& msg, Exception& ex SGP_CALLER_LOCATION); + + // compatibility with std::exception + Exception(WString const& msg, std::exception& ex SGP_CALLER_LOCATION); + +#if defined(USE_VFS) + // compatibility with vfs::Exception + Exception(WString const& msg, vfs::Exception& ex SGP_CALLER_LOCATION); +#endif + + virtual const char* what() const throw(); + + struct Excp + { + int line; + std::string function, file; + std::wstring msg; + }; + std::list _msg; + }; +} + +#define SGP_THROW(msg) throw sgp::Exception( (msg) SGP_GET_CALLER_LOCATION ) +#define SGP_RETHROW(msg, ex) throw sgp::Exception( (msg), (ex) SGP_GET_CALLER_LOCATION ) +#define SGP_TRYCATCH_RETHROW(expr, msg) try { (expr); } catch(std::exception &ex) { throw sgp::Exception((msg), (ex) SGP_GET_CALLER_LOCATION); } + +#define SGP_THROW_IFFALSE(cond, msg) if((cond) == false) { throw sgp::Exception(msg SGP_GET_CALLER_LOCATION); } +#define SGP_THROW_IFNULL(ptr, msg) if((ptr) == NULL) { throw sgp::Exception(msg SGP_GET_CALLER_LOCATION); } + +#include + +void _ExceptionMessage( sgp::Exception &ex ); +void _ExceptionMessage( vfs::Exception &ex ); /* #ifdef __cplusplus diff --git a/Standard Gaming Platform/DEBUG.cpp b/Standard Gaming Platform/DEBUG.cpp index 8bae2ac5..515cba7f 100644 --- a/Standard Gaming Platform/DEBUG.cpp +++ b/Standard Gaming Platform/DEBUG.cpp @@ -48,9 +48,11 @@ #ifndef _NO_DEBUG_TXT #include "fileman.h" #endif -#include "GameSettings.h" +#include "GameSettings.h" #include "SaveLoadGame.h" +#include "debug_util.h" + #ifdef __cplusplus extern "C" { #endif @@ -402,7 +404,7 @@ void DbgShutdown() {}; extern HVOBJECT FontObjs[25]; - +#include void _FailMessage(const char* message, unsigned lineNum, const char * functionName, const char* sourceFileName) { // This function shouldn't recurse @@ -411,6 +413,8 @@ void _FailMessage(const char* message, unsigned lineNum, const char * functionNa return; alreadyInThisFunction = true; + sgp::dumpStackTrace(message); + std::stringstream basicInformation; basicInformation << "Assertion Failure [Line " << lineNum; if (functionName) { @@ -501,10 +505,26 @@ STR8 String(const STR8 String, ...) } -void _ExceptionMessage( CBasicException &ex ) +void _ExceptionMessage( sgp::Exception &ex ) { g_ExceptionList.clear(); - CBasicException::CALLSTACK::iterator it = ex.m_CallStack.begin(); + std::list::iterator it = ex._msg.begin(); + for(; it!=ex._msg.end(); ++it) + { + SExceptionData exd; + exd.message = (*it).msg; + exd.function = (*it).function; + exd.file = (*it).file; + exd.line = (*it).line; + g_ExceptionList.push_back(exd); + } + _FailMessage("",0,""); +} + +void _ExceptionMessage( vfs::Exception &ex ) +{ + g_ExceptionList.clear(); + vfs::Exception::CALLSTACK::iterator it = ex.m_CallStack.begin(); for(; it!=ex.m_CallStack.end(); ++it) { SExceptionData exd; @@ -517,5 +537,127 @@ void _ExceptionMessage( CBasicException &ex ) _FailMessage("",0,""); } +#include +#include + +sgp::Exception::Exception(sgp::WString const& msg SGP_CALLER_LOCATION_IMPL) +{ + Excp excp; + excp.line = line; + excp.file = file ? file : ""; + excp.function = function ? function : ""; + excp.msg = msg.str; + + _msg.push_back(excp); +} + +sgp::Exception::Exception(sgp::WString const& msg, Exception& ex SGP_CALLER_LOCATION_IMPL) +{ + _msg.insert(_msg.end(), ex._msg.begin(), ex._msg.end()); + + Excp excp; + excp.line = line; + excp.file = file ? file : ""; + excp.function = function ? function : ""; + excp.msg = msg.str; + + _msg.push_back(excp); +} + +#if defined(USE_VFS) +sgp::Exception::Exception(sgp::WString const& msg, vfs::Exception& ex SGP_CALLER_LOCATION_IMPL) +{ + vfs::Exception::CALLSTACK::iterator it = ex.m_CallStack.begin(); + for(; it != ex.m_CallStack.end(); ++it) + { + Excp excp; + excp.file = it->file.utf8(); + excp.function = it->function.utf8(); + excp.line = it->line; + excp.msg = it->message.c_wcs(); + _msg.push_back(excp); + } + + Excp excp; + excp.line = line; + excp.file = file ? file : ""; + excp.function = function ? function : ""; + excp.msg = msg.str; + + _msg.push_back(excp); +} +#endif + +sgp::Exception::Exception(WString const& msg, std::exception& ex SGP_CALLER_LOCATION_IMPL) +{ + if(dynamic_cast(&ex)) + { + sgp::Exception& sgp_ex = *static_cast(&ex); + _msg.insert(_msg.end(), sgp_ex._msg.begin(), sgp_ex._msg.end()); + } + else if(dynamic_cast(&ex)) + { + vfs::Exception& vfs_ex = *static_cast(&ex); + vfs::Exception::CALLSTACK::iterator it = vfs_ex.m_CallStack.begin(); + for(; it != vfs_ex.m_CallStack.end(); ++it) + { + Excp excp; + excp.file = it->file.utf8(); + excp.function = it->function.utf8(); + excp.line = it->line; + excp.msg = it->message.c_wcs(); + _msg.push_back(excp); + } + } + else + { + Excp excp; + excp.file = ""; + excp.function = ""; + excp.line = -1; + convert_string(ex.what(), excp.msg); + _msg.push_back(excp); + } + + Excp excp; + excp.line = line; + excp.file = file ? file : ""; + excp.function = function ? function : ""; + excp.msg = msg.str; + + _msg.push_back(excp); +} + + +#if defined(_WIN32) || defined(WIN64) +# define ENDL "\r\n" +#else +# define ENDL "\n" +#endif + +static std::string gs_exception_string; + +const char* sgp::Exception::what() const +{ + // cannot return pointer local variable + std::stringstream ss; + ss.str(""); + ss.clear(); + + std::list::const_reverse_iterator rit = _msg.rbegin(); + for(; rit != _msg.rend(); ++rit) + { + std::string msg; + convert_string(rit->msg, msg); + //wss << "========== " << rit->time << " =========="ENDL; + ss << "File : " << rit->file << ENDL; + ss << "Line : " << rit->line << ENDL; + ss << "Location : " << rit->function << ENDL; + ss << " " << msg << ENDL; + } + + gs_exception_string = ss.str(); + return gs_exception_string.c_str(); +} diff --git a/Standard Gaming Platform/FileMan.cpp b/Standard Gaming Platform/FileMan.cpp index 0cef6310..1e2d5267 100644 --- a/Standard Gaming Platform/FileMan.cpp +++ b/Standard Gaming Platform/FileMan.cpp @@ -45,18 +45,18 @@ #include "Container.h" #include "LibraryDataBase.h" #include "io.h" - + #include "sgp_logger.h" #endif using namespace std; -#include "VFS/vfs.h" -#include "VFS/os_functions.h" -#include "VFS/vfs_settings.h" +#include +#include +#include #ifdef USE_VFS -#include "VFS/vfs_file_raii.h" +#include #include struct SOperation @@ -410,10 +410,10 @@ HWFILE FileOpen( STR strFilename, UINT32 uiOptions, BOOLEAN fDeleteOnClose ) // sometimes a file is supposed to opened that does not exist (not tested with FileExists()) // this operation can fail with an exception that the calling code doesn't catch // instead we catch it (any exception, not just CBasicException) here and return 0 - catch(CBasicException& ex) { logException(ex); } + catch(vfs::Exception& ex) { SGP_ERROR(ex.what()); } catch(...) { - logException( CBasicException("Caught undefined exception", _FUNCTION_FORMAT_, __LINE__, __FILE__) ); + SGP_ERROR( "Caught undefined exception" ); } return 0; #else @@ -680,25 +680,25 @@ BOOLEAN FileRead( HWFILE hFile, PTR pDest, UINT32 uiBytesToRead, UINT32 *puiByte vfs::tReadableFile *pRF = vfs::tReadableFile::cast(pFile); if(pRF) { - UINT32 uiBytesRead; + UINT32 uiBytesRead = 0; try { uiBytesRead = pRF->read((vfs::Byte*)pDest, uiBytesToRead); } - catch(CBasicException& ex) + catch(std::exception& ex) { pRF->close(); - RETHROWEXCEPTION(L"", &ex); + SGP_RETHROW(L"", ex); } - if(uiBytesToRead != uiBytesRead) - { - return FALSE; - } if(puiBytesRead) { *puiBytesRead = uiBytesRead; } + if(uiBytesToRead != uiBytesRead) + { + return FALSE; + } return TRUE; } } @@ -820,10 +820,10 @@ BOOLEAN FileWrite( HWFILE hFile, PTR pDest, UINT32 uiBytesToWrite, UINT32 *puiBy { uiBytesWritten = pWF->write((vfs::Byte*)pDest, uiBytesToWrite); } - catch(CBasicException& ex) + catch(std::exception& ex) { pWF->close(); - RETHROWEXCEPTION(L"", &ex); + SGP_RETHROW(L"", ex); } if (uiBytesToWrite != uiBytesWritten) @@ -905,7 +905,7 @@ BOOLEAN FileLoad( STR strFilename, PTR pDest, UINT32 uiBytesToRead, UINT32 *puiB if(pFile) { UINT32 uiNumBytesRead; - TRYCATCH_RETHROW(uiNumBytesRead = pFile->read((vfs::Byte*)pDest,uiBytesToRead), L""); + SGP_TRYCATCH_RETHROW(uiNumBytesRead = pFile->read((vfs::Byte*)pDest,uiBytesToRead), L""); if (uiBytesToRead != uiNumBytesRead) { @@ -1073,7 +1073,7 @@ BOOLEAN FileSeek( HWFILE hFile, UINT32 uiDistance, UINT8 uiHow ) vfs::tWritableFile *pWF = vfs::tWritableFile::cast(pFile); if(pWF) { - TRYCATCH_RETHROW(pWF->setWritePosition(iDistance, eSD), L""); + SGP_TRYCATCH_RETHROW(pWF->setWritePosition(iDistance, eSD), L""); return TRUE; } } @@ -1082,13 +1082,13 @@ BOOLEAN FileSeek( HWFILE hFile, UINT32 uiDistance, UINT8 uiHow ) vfs::tReadableFile *pRF = vfs::tReadableFile::cast(pFile); if(pRF) { - TRYCATCH_RETHROW(pRF->setReadPosition(iDistance, eSD), L""); + SGP_TRYCATCH_RETHROW(pRF->setReadPosition(iDistance, eSD), L""); return TRUE; } } else { - THROWEXCEPTION(L"unknown operation"); + SGP_THROW(L"unknown operation"); } } return FALSE; @@ -1604,11 +1604,11 @@ BOOLEAN SetFileManCurrentDirectory( STR pcDirectory ) #else try { - os::setCurrectDirectory(pcDirectory); + vfs::OS::setCurrectDirectory(pcDirectory); } - catch(CBasicException& ex) + catch(vfs::Exception& ex) { - logException(ex); + SGP_ERROR(ex.what()); return FALSE; } return TRUE; @@ -1628,12 +1628,12 @@ BOOLEAN GetFileManCurrentDirectory( STRING512 pcDirectory ) try { vfs::Path sDir; - os::getCurrentDirectory(sDir); + vfs::OS::getCurrentDirectory(sDir); strncpy(pcDirectory, sDir.to_string().c_str(), 512); } - catch(CBasicException& ex) + catch(vfs::Exception& ex) { - logException(ex); + SGP_ERROR(ex.what()); return FALSE; } return TRUE; @@ -1841,7 +1841,7 @@ BOOLEAN GetExecutableDirectory( STRING512 pcDirectory ) { #ifdef USE_VFS vfs::Path exe_dir, exe_file; - os::getExecutablePath(exe_dir, exe_file); + vfs::OS::getExecutablePath(exe_dir, exe_file); strncpy(pcDirectory, exe_dir.to_string().c_str(), 512); return true; #else @@ -2215,7 +2215,7 @@ BOOLEAN FileCheckEndOfFile( HWFILE hFile ) { current_position = pWF->getWritePosition(); max_position = pWF->getSize(); - return current_position < max_position; + return current_position >= max_position; } } else if(pFile && (s_mapFiles[pFile].op == SOperation::READ)) @@ -2225,7 +2225,7 @@ BOOLEAN FileCheckEndOfFile( HWFILE hFile ) { current_position = pRF->getReadPosition(); max_position = pRF->getSize(); - return current_position < max_position; + return current_position >= max_position; } } return FALSE; diff --git a/Standard Gaming Platform/Font.cpp b/Standard Gaming Platform/Font.cpp index a39e02b5..93108ff1 100644 --- a/Standard Gaming Platform/Font.cpp +++ b/Standard Gaming Platform/Font.cpp @@ -132,7 +132,7 @@ UINT32 uiRed, uiGreen, uiBlue; //return; std::wstringstream wss; wss << L"invalid font index ( " << FontDefault << L" )"; - THROWEXCEPTION(wss.str().c_str()); + SGP_THROW(wss.str().c_str()); } FontForeground8=ubForeground; @@ -197,7 +197,7 @@ UINT32 uiRed, uiGreen, uiBlue; //return; std::wstringstream wss; wss << L"invalid color background value ( " << ubBackground << L" )"; - THROWEXCEPTION(wss.str().c_str()); + SGP_THROW(wss.str().c_str()); } FontBackground8=ubBackground; @@ -942,9 +942,9 @@ BOOLEAN SetFont(INT32 iFontIndex) //Assert(iFontIndex >= 0); //Assert(iFontIndex <= MAX_FONTS); //Assert(FontObjs[iFontIndex]!=NULL); - THROWIFFALSE( iFontIndex >= 0 ,"negative font index"); - THROWIFFALSE( iFontIndex <= MAX_FONTS, "font index > MAX_FONTS" ); - THROWIFFALSE( FontObjs[iFontIndex]!=NULL, "font is not initialized" ); + SGP_THROW_IFFALSE( iFontIndex >= 0 ,"negative font index"); + SGP_THROW_IFFALSE( iFontIndex <= MAX_FONTS, "font index > MAX_FONTS" ); + SGP_THROW_IFFALSE( FontObjs[iFontIndex]!=NULL, "font is not initialized" ); #ifdef WINFONTS SET_WINFONT(WinFontMap[iFontIndex]); #endif diff --git a/Standard Gaming Platform/MemMan.cpp b/Standard Gaming Platform/MemMan.cpp index 5d6f0d74..178556ab 100644 --- a/Standard Gaming Platform/MemMan.cpp +++ b/Standard Gaming Platform/MemMan.cpp @@ -31,13 +31,12 @@ #include "MemMan.h" #include "Debug.h" #include + #include "sgp_logger.h" #ifdef _DEBUG #include #endif //#endif -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" #ifdef _DEBUG //#define DEBUG_MEM_LEAKS // turns on tracking of every MemAlloc and MemFree! @@ -231,16 +230,17 @@ void ShutdownMemoryManager( void ) } fclose( fp ); #else - CLog memLeak( L"MemLeakInfo.txt", true); - memLeak.endl().endl(); - memLeak << ">>>>> MEMORY LEAK DETECTED!!! <<<<<" << CLog::ENDL; - memLeak << " " << guiMemAlloced << " bytes memory total was allocated" << CLog::ENDL; - memLeak << "- " << guiMemFreed << " bytes memory total was freed" << CLog::ENDL; - memLeak << "_______________________________________________" << CLog::ENDL; - memLeak << guiMemTotal << " bytes memory total STILL allocated" << CLog::ENDL; - memLeak << MemDebugCounter << " memory blocks still allocated" << CLog::ENDL; - memLeak << "guiScreenExitedFrom = " << gzJA2ScreenNames[ gMsgBox.uiExitScreen ] << CLog::ENDL; - memLeak.endl().endl(); + sgp::Logger_ID log_id = sgp::Logger::instance().createLogger(); + sgp::Logger::LogInstance memLeak = SGP_LOG(log_id); + memLeak << sgp::endl << sgp::endl; + memLeak << ">>>>> MEMORY LEAK DETECTED!!! <<<<<" << sgp::endl; + memLeak << " " << guiMemAlloced << " bytes memory total was allocated" << sgp::endl; + memLeak << "- " << guiMemFreed << " bytes memory total was freed" << sgp::endl; + memLeak << "_______________________________________________" << sgp::endl; + memLeak << guiMemTotal << " bytes memory total STILL allocated" << sgp::endl; + memLeak << MemDebugCounter << " memory blocks still allocated" << sgp::endl; + memLeak << "guiScreenExitedFrom = " << gzJA2ScreenNames[ gMsgBox.uiExitScreen ] << sgp::endl; + memLeak << sgp::endl << sgp::endl; #endif } #endif diff --git a/Standard Gaming Platform/PngLoader.cpp b/Standard Gaming Platform/PngLoader.cpp index 56faefe7..1fce3be5 100644 --- a/Standard Gaming Platform/PngLoader.cpp +++ b/Standard Gaming Platform/PngLoader.cpp @@ -3,21 +3,25 @@ #include "DEBUG.H" #include "vobject.h" #include "STIConvert.h" +#include "MemMan.h" -#include "VFS/vfs.h" -#include "VFS/vfs_file_raii.h" -#include "VFS/Location/vfs_7z_library.h" -#include "VFS/Interface/vfs_location_interface.h" -#include "VFS/File/vfs_memory_file.h" +#include +#include +#include +#include +#include +#include #include "XML_Parser.h" namespace png { -#include +# include } -const utf8string::str_t CONST_DOTPNG(L".png"); -const utf8string::str_t CONST_DOTXML(L".xml"); +#include "sgp_auto_memory.h" + +const vfs::String::str_t CONST_DOTPNG(L".png"); +const vfs::String::str_t CONST_DOTXML(L".xml"); void Load24bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info); void Load32bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info); @@ -26,7 +30,7 @@ void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop in void user_read_data(png::png_structp png_ptr, png::png_bytep data, png::png_size_t length) { - TRYCATCH_RETHROW( static_cast(png_ptr->io_ptr)->read((vfs::Byte*)data,length), + SGP_TRYCATCH_RETHROW( static_cast(png_ptr->io_ptr)->read((vfs::Byte*)data,length), L"error during png file reading"); } @@ -160,7 +164,7 @@ bool IndexedSTIImage::addImage(UINT8 *data, UINT32 data_size, UINT32 image_width subimage.usHeight = image_height; INT32 etrle_size = ETRLECompressSubImage( compressed, RESIZE, data, image_width, image_height, &subimage); - THROWIFFALSE( etrle_size > 0, L"not enough space reserved for ETRLE compression"); + SGP_THROW_IFFALSE( etrle_size > 0, L"not enough space reserved for ETRLE compression"); subimage.sOffsetX = image_offset_x; subimage.sOffsetY = image_offset_y; @@ -247,8 +251,8 @@ static inline void setFlag(UINT8 &flags, char const* sFlag) else { std::wstringstream wss; - wss << L"Unknown flag [" << utf8string::as_utf16(sFlag) << L"]"; - THROWEXCEPTION(wss.str().c_str()); + wss << L"Unknown flag [" << vfs::String::as_utf16(sFlag) << L"]"; + SGP_THROW(wss.str().c_str()); } } @@ -266,7 +270,7 @@ class CAppDataParser : public IXMLParser }; public: CAppDataParser(XML_Parser &parser, IXMLParser* caller=NULL) - : IXMLParser("ImageData", parser, caller), + : IXMLParser("ImageData", &parser, caller), current_state(DO_ELEMENT_NONE), m_hImage(NULL), m_iCurrentIndex(-1) @@ -316,7 +320,7 @@ void CAppDataParser::onStartElement(const XML_Char* name, const XML_Char** atts) else if(current_state == DO_ELEMENT_ImageData && strcmp(name, "SubImage") == 0) { int index = -1; - THROWIFFALSE(getAttributeAsInt("index",atts,index), L"could not read attribute \"index\""); + SGP_THROW_IFFALSE(getAttributeAsInt("index",atts,index), L"could not read attribute \"index\""); m_iCurrentIndex = index; if(index >= (int)m_vAppData.size()) { @@ -414,7 +418,7 @@ void CAppDataParser::onEndElement(const XML_Char* name) { sum_frames += m_vAppData[i].aux.ubNumberOfFrames; } - THROWIFFALSE(sum_frames <= m_vAppData.size(), L"Sum of animation frames doesn't match the total number of frames"); + SGP_THROW_IFFALSE(sum_frames <= m_vAppData.size(), L"Sum of animation frames doesn't match the total number of frames"); int iAppDataSize = m_vAppData.size()*sizeof(AuxObjectData); m_hImage->pAppData = (UINT8*) MemAlloc( iAppDataSize ); for(unsigned int i = 0; i < m_vAppData.size(); ++i) @@ -431,6 +435,7 @@ void CAppDataParser::onEndElement(const XML_Char* name) m_hImage->pETRLEObject[i].sOffsetY = m_vAppData[i].offset.y; } } + m_hImage->fFlags |= IMAGE_APPDATA; current_state = DO_ELEMENT_NONE; } } @@ -456,16 +461,16 @@ bool IndexedSTIImage::readAppDataFromXMLFile(HIMAGE hImage, vfs::tReadableFile* try { vfs::COpenReadFile oFile(pFile); - uiSize = oFile.file().getSize(); + uiSize = oFile->getSize(); vBuffer.resize(uiSize+1); - THROWIFFALSE(uiSize == oFile.file().read(&vBuffer[0],uiSize), L"Could not read XML file"); + SGP_THROW_IFFALSE(uiSize == oFile->read(&vBuffer[0],uiSize), L"Could not read XML file"); vBuffer[uiSize] = 0; - oFile.file().close(); + oFile->close(); } - catch(CBasicException& ex) + catch(std::exception& ex) { - RETHROWEXCEPTION(L"", &ex); + SGP_RETHROW(L"", ex); } XML_Parser parser = XML_ParserCreate(NULL); @@ -480,15 +485,15 @@ bool IndexedSTIImage::readAppDataFromXMLFile(HIMAGE hImage, vfs::tReadableFile* { std::wstringstream wss; wss << L"XML Parser Error in Groups.xml: " - << utf8string(XML_ErrorString(XML_GetErrorCode(parser))).c_wcs() + << vfs::String(XML_ErrorString(XML_GetErrorCode(parser))).c_wcs() << L" at line " << XML_GetCurrentLineNumber(parser); - THROWEXCEPTION(wss.str().c_str()); + SGP_THROW(wss.str().c_str()); } } - catch(CBasicException &ex) + catch(std::exception &ex) { - RETHROWEXCEPTION(L"Could not load xml file", &ex); + SGP_RETHROW(L"Could not load xml file", ex); } return true; } @@ -581,7 +586,7 @@ public: LoadPngFile(vfs::tReadableFile* pFile) : _file(pFile), _struct(NULL), _info(NULL), _row_ptr(NULL) { - THROWIFFALSE(_file, L"file pointer is NULL"); + SGP_THROW_IFFALSE(_file, L"file pointer is NULL"); } bool Load() { @@ -683,7 +688,7 @@ bool LoadPNGFileToImage(HIMAGE hImage, UINT16 fContents) std::wstringstream wss; wss << L"Unknown image datatype : channels = " << (int)(fpng.Info()->channels) << L", bit depth = " << (int)(fpng.Info()->bit_depth); - THROWEXCEPTION(wss.str().c_str()); + SGP_THROW(wss.str().c_str()); } // data was copied to hImage, need to clean up here @@ -698,14 +703,14 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) { return false; } - vfs::CMemoryFile oBuffer(""); + vfs::CBufferFile oBuffer(""); vfs::COpenReadFile oFile(hImage->ImageFile); - TRYCATCH_RETHROW(oBuffer.copyToBuffer(oFile.file()), L"Could not copy file to buffer"); + SGP_TRYCATCH_RETHROW(oBuffer.copyToBuffer(oFile.file()), L"Could not copy file to buffer"); oBuffer.close(); //vfs::CUncompressed7zLibrary oLib(&oFile.file(),""); - ObjBlockAllocator allocator(128); + vfs::ObjBlockAllocator allocator(128); vfs::CUncompressed7zLibrary oLib(vfs::tReadableFile::cast(&oBuffer),"",false, &allocator); if(!oLib.init()) @@ -728,11 +733,11 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) for(; !it.end(); it.next()) { // check extension - utf8string::str_t const& fname = it.value()->getName().c_wcs(); - utf8string::size_t dot = fname.find_last_of(vfs::Const::DOT()); - if(dot != utf8string::str_t::npos) + vfs::String::str_t const& fname = it.value()->getName().c_wcs(); + vfs::String::size_t dot = fname.find_last_of(vfs::Const::DOT()); + if(dot != vfs::String::str_t::npos) { - if( StrCmp::Equal(fname.substr(dot,fname.length()-dot), CONST_DOTPNG) ) + if( vfs::StrCmp::Equal(fname.substr(dot,fname.length()-dot), CONST_DOTPNG) ) { std::wstringstream bss; bss.str( fname.substr(0,dot) ); @@ -744,10 +749,10 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) } else { - THROWEXCEPTION(L"invalid index"); + SGP_THROW(L"invalid index"); } } - else if (StrCmp::Equal(fname.substr(dot,fname.length()-dot), CONST_DOTXML) ) + else if (vfs::StrCmp::Equal(fname.substr(dot,fname.length()-dot), CONST_DOTXML) ) { appdata_file = vfs::tReadableFile::cast(it.value()); } @@ -783,18 +788,18 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) std::wstringstream wss; wss << L"Unknown image datatype : channels = " << (int)(lpng.Info()->channels) << L", bit depth = " << (int)(lpng.Info()->bit_depth); - THROWEXCEPTION(wss.str().c_str()); + SGP_THROW(wss.str().c_str()); } return true; } } - catch(CBasicException &ex) + catch(std::exception &ex) { std::wstringstream wss; wss << L"Loading PNG image from file '" - << oFile.file().getPath().c_wcs() + << oFile->getPath().c_wcs() << L"' failed"; - RETHROWEXCEPTION(wss.str().c_str(),&ex); + SGP_RETHROW(wss.str().c_str(), ex); } return false; } @@ -809,7 +814,7 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) } try { - vfs::CMemoryFile oTempFile(""); + vfs::CBufferFile oTempFile(""); oTempFile.copyToBuffer( *vfs::tReadableFile::cast(*fit) ); // LoadPngFile lpng( vfs::tReadableFile::cast(*fit) ); @@ -822,7 +827,7 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) { if(!bHasPalette) { - THROWIFFALSE(lpng.Info()->num_palette == 256, L"size of palette is not 256"); + SGP_THROW_IFFALSE(lpng.Info()->num_palette == 256, L"size of palette is not 256"); image.setPalette(lpng.Info()->palette, lpng.Info()->num_palette); bHasPalette = true; } @@ -837,16 +842,16 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) else { std::wstringstream wss; - wss << L"PNG file '" << (*fit)->getName()() << L" @ " << oFile.file().getPath()() << L"' is not a paletted image"; - THROWEXCEPTION(wss.str().c_str()); + wss << L"PNG file '" << (*fit)->getName()() << L" @ " << oFile->getPath()() << L"' is not a paletted image"; + SGP_THROW(wss.str().c_str()); } } } - catch(CBasicException& ex) + catch(std::exception& ex) { std::wstringstream wss; - wss << L"Loading PNG image [" << findex << L"] from file '" << oFile.file().getPath().c_wcs() << L"' failed"; - RETHROWEXCEPTION(wss.str().c_str(),&ex); + wss << L"Loading PNG image [" << findex << L"] from file '" << oFile->getPath().c_wcs() << L"' failed"; + SGP_RETHROW(wss.str().c_str(), ex); } } } @@ -861,14 +866,34 @@ bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) void Load32bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) { +#if 1 + hImage->pETRLEObject = (ETRLEObject*)MemAlloc(1 * sizeof(ETRLEObject)); + if(!hImage->pETRLEObject) + { + SGP_THROW(L"bad alloc"); + } + memset(hImage->pETRLEObject, 0, sizeof(ETRLEObject)); + hImage->usNumberOfObjects = 1; + + hImage->pETRLEObject[0].usHeight = (UINT16)info->height; + hImage->pETRLEObject[0].usWidth = (UINT16)info->width; + + hImage->pETRLEObject[0].sOffsetX = (INT16)info->x_offset; + hImage->pETRLEObject[0].sOffsetY = (INT16)info->y_offset; + hImage->usHeight = (UINT16)info->height; hImage->usWidth = (UINT16)info->width; hImage->ubBitDepth = 32; + + UINT32 SIZE = info->height * info->width * sizeof(UINT32); + hImage->p32BPPData = (UINT32*)MemAlloc(SIZE); + if(!hImage->p32BPPData) + { + MemFree(hImage->pETRLEObject); + SGP_THROW(L"bad alloc"); + } + memset(hImage->p32BPPData, 0, SIZE); -#if 1 - UINT32 SIZE = info->height * info->width; - hImage->p32BPPData = new UINT32[SIZE]; - memset(hImage->p32BPPData, 0, SIZE*sizeof(UINT32)); UINT32* dest_row = NULL; UINT32 rgbcolor = 0; for(unsigned int i=0; iheight; ++i) @@ -877,6 +902,8 @@ void Load32bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) png::png_bytep row_i = rows[i]; memcpy(dest_row,row_i,info->width * sizeof(UINT32)); } + + hImage->fFlags |= IMAGE_BITMAPDATA; #else UINT32 SIZE = info->height * info->width; hImage->p16BPPData = new UINT16[SIZE]; @@ -913,13 +940,32 @@ void Load32bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) void Load24bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) { + hImage->pETRLEObject = (ETRLEObject*)MemAlloc(1 * sizeof(ETRLEObject)); + if(!hImage->pETRLEObject) + { + SGP_THROW(L"bad alloc"); + } + memset(hImage->pETRLEObject, 0, sizeof(ETRLEObject)); + hImage->usNumberOfObjects = 1; + + hImage->pETRLEObject[0].usHeight = (UINT16)info->height; + hImage->pETRLEObject[0].usWidth = (UINT16)info->width; + + hImage->pETRLEObject[0].sOffsetX = (UINT16)info->x_offset; + hImage->pETRLEObject[0].sOffsetY = (UINT16)info->y_offset; + hImage->usHeight = (UINT16)info->height; hImage->usWidth = (UINT16)info->width; hImage->ubBitDepth = 16; - UINT32 SIZE = info->height * info->width; - hImage->p16BPPData = new UINT16[SIZE]; - memset(hImage->p16BPPData, 0, SIZE*sizeof(UINT16)); + UINT32 SIZE = info->height * info->width * sizeof(UINT16); + hImage->p16BPPData = (UINT16*)MemAlloc(SIZE); + if(!hImage->p16BPPData) + { + MemFree(hImage->pETRLEObject); + SGP_THROW(L"bad alloc"); + } + memset(hImage->p16BPPData, 0, SIZE); UINT16* dest_row = NULL; UINT32 rgbcolor = 0; @@ -932,12 +978,17 @@ void Load24bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) dest_row[dx] = Get16BPPColor( FROMRGB(row_i[sx], row_i[sx+1], row_i[sx+2]) ); } } + hImage->fFlags |= IMAGE_BITMAPDATA; } void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) { - UINT32 SIZE = info->height * info->width; - UINT8 *data = new UINT8[SIZE]; + UINT32 SIZE = info->height * info->width * sizeof(UINT8); + UINT8 *data = (UINT8*)MemAlloc(SIZE); + if(!data) + { + SGP_THROW(L"bad alloc"); + } memset(data,0,SIZE); for(unsigned int i = 0; i < info->height; ++i) { @@ -945,7 +996,12 @@ void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop in } hImage->usNumberOfObjects = 1; - hImage->pETRLEObject = new ETRLEObject[hImage->usNumberOfObjects]; + hImage->pETRLEObject = (ETRLEObject*)MemAlloc(hImage->usNumberOfObjects * sizeof(ETRLEObject)); + if(!hImage->pETRLEObject) + { + MemFree(data); + SGP_THROW(L"bad alloc"); + } memset(hImage->pETRLEObject,0, hImage->usNumberOfObjects * sizeof(ETRLEObject)); ETRLEObject &subimage = hImage->pETRLEObject[0]; @@ -956,7 +1012,13 @@ void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop in // why allocate so much? because in in the worst case we need one TAG and one DATAVALUE per pixel UINT32 RESIZE = 3*SIZE; - hImage->p8BPPData = new UINT8[RESIZE]; + hImage->p8BPPData = (UINT8*)MemAlloc( RESIZE ); + if(!hImage->p8BPPData) + { + MemFree(hImage->pETRLEObject); + MemFree(data); + SGP_THROW(L"bad alloc"); + } UINT8 *compressed = hImage->p8BPPData; memset(hImage->p8BPPData,0,RESIZE); UINT32 compressed_size = 0; @@ -970,7 +1032,7 @@ void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop in subim.usWidth = subimage.usWidth; UINT32 etrle_size = ETRLECompressSubImage( hImage->p8BPPData, RESIZE, data, (UINT16)info->width, (UINT16)info->height, &subim); - THROWIFFALSE( etrle_size > 0, L"ETRLE compression of PNG image failed" ); + SGP_THROW_IFFALSE( etrle_size > 0, L"ETRLE compression of PNG image failed" ); subim.sOffsetX = subimage.sOffsetX; subim.sOffsetY = subimage.sOffsetY; #if 0 @@ -1047,9 +1109,9 @@ void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop in hImage->fFlags |= IMAGE_BITMAPDATA; // palette - THROWIFFALSE(info->num_palette == 256, L"palette has size != 256"); + SGP_THROW_IFFALSE(info->num_palette == 256, L"palette has size != 256"); - hImage->pPalette = new SGPPaletteEntry[256]; + hImage->pPalette = (SGPPaletteEntry*)MemAlloc(sizeof(SGPPaletteEntry) *256); for(int i=0; i<256; ++i) { hImage->pPalette[i].peRed = info->palette[i].red; diff --git a/Standard Gaming Platform/SGP_VS2005.vcproj b/Standard Gaming Platform/SGP_VS2005.vcproj new file mode 100644 index 00000000..927f8439 --- /dev/null +++ b/Standard Gaming Platform/SGP_VS2005.vcproj @@ -0,0 +1,803 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Standard Gaming Platform/SGP_VS2008.vcproj b/Standard Gaming Platform/SGP_VS2008.vcproj index 1ad1521d..31520e6e 100644 --- a/Standard Gaming Platform/SGP_VS2008.vcproj +++ b/Standard Gaming Platform/SGP_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -375,6 +375,10 @@ RelativePath="DEBUG.H" > + + @@ -495,6 +499,10 @@ RelativePath="RAD.H" > + + @@ -511,6 +519,14 @@ RelativePath="sgp.h" > + + + + @@ -631,6 +647,14 @@ RelativePath="DEBUG.cpp" > + + + + @@ -727,6 +751,10 @@ RelativePath="sgp.cpp" > + + diff --git a/Standard Gaming Platform/SGP_VS2010.vcxproj b/Standard Gaming Platform/SGP_VS2010.vcxproj new file mode 100644 index 00000000..13489454 --- /dev/null +++ b/Standard Gaming Platform/SGP_VS2010.vcxproj @@ -0,0 +1,326 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {1237FA1E-6E76-4AB5-B569-45B01C691FAB} + Win32Proj + SGP + SGP + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;NO_ZLIB_COMPRESSION;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;NO_ZLIB_COMPRESSION;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;NO_ZLIB_COMPRESSION;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;NO_ZLIB_COMPRESSION;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;NO_ZLIB_COMPRESSION;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Standard Gaming Platform/SGP_VS2010.vcxproj.filters b/Standard Gaming Platform/SGP_VS2010.vcxproj.filters new file mode 100644 index 00000000..4d7304a1 --- /dev/null +++ b/Standard Gaming Platform/SGP_VS2010.vcxproj.filters @@ -0,0 +1,354 @@ + + + + + {efcdc6de-effe-499c-865f-bbb1cd30a876} + + + {3abaeda9-a6ab-443e-9e82-5b43020f6328} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Standard Gaming Platform/Types.h b/Standard Gaming Platform/Types.h index ad4b1861..46d11e0e 100644 --- a/Standard Gaming Platform/Types.h +++ b/Standard Gaming Platform/Types.h @@ -33,8 +33,10 @@ #if defined( JA2 ) || defined( UTILS ) typedef unsigned int UINT32; -typedef __int64 INT64; // WANNE - BMP: Used for Big Maps +typedef signed __int64 INT64; // WANNE - BMP: Used for Big Maps typedef signed int INT32; +typedef unsigned __int64 UINT64; +typedef unsigned long long UINT128; #else typedef unsigned int UINT32; typedef int INT32; @@ -132,4 +134,52 @@ typedef VECTOR4 MATRIX4[4]; // 4x4 matrix typedef VECTOR4 COLOR; // rgba color array +#include +#include + +inline void convert_string(std::wstring const& str_in, std::string &str_out) +{ +#if !defined(USE_VFS) + const wchar_t* src = str_in.c_str(); + size_t len = wcstombs(NULL, src, str_in.length()); + if(len > 0) + { + str_out.resize(len); + wcstombs(&str_out[0], src, len); + } +#else + if(vfs::Settings::getUseUnicode()) + { + str_out = vfs::String::as_utf8(str_in); + } + else + { + vfs::String::narrow(str_in, str_out); + } +#endif +} + +inline void convert_string(std::string const& str_in, std::wstring &str_out) +{ +#if !defined(USE_VFS) + const char* src = str_in.c_str(); + size_t len = mbstowcs(NULL, src, str_in.length()); + if(len > 0) + { + str_out.resize(len); + mbstowcs(&str_out[0], src, len); + } +#else + if(vfs::Settings::getUseUnicode()) + { + vfs::String::as_utf16(str_in, str_out); + } + else + { + vfs::String::widen(str_in, str_out); + } +#endif +} + + #endif \ No newline at end of file diff --git a/Standard Gaming Platform/WinFont.cpp b/Standard Gaming Platform/WinFont.cpp index f3545e5a..72968228 100644 Binary files a/Standard Gaming Platform/WinFont.cpp and b/Standard Gaming Platform/WinFont.cpp differ diff --git a/Standard Gaming Platform/debug_util.cpp b/Standard Gaming Platform/debug_util.cpp new file mode 100644 index 00000000..5f6e680c --- /dev/null +++ b/Standard Gaming Platform/debug_util.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "debug_util.h" + +const void *const *StackTrace::Addresses(size_t* count) { + *count = trace_.size(); + if (trace_.size()) + return &trace_[0]; + return NULL; +} + +void sgp::dumpStackTrace(vfs::String const& msg) +{ + // the first error is the important one anyway + static bool already_dumping = false; + + if(!already_dumping) // needs a mutes to be sure + { + already_dumping = true; + StackTrace str; + str.PrintBacktrace(msg.utf8().c_str()); + already_dumping = false; + } +} + +#ifdef __MINGW32__ +StackTrace::StackTrace() +{ +} + +void StackTrace::PrintBacktrace(const char* msg) +{ +} + +#endif diff --git a/Standard Gaming Platform/debug_util.h b/Standard Gaming Platform/debug_util.h new file mode 100644 index 00000000..ac06cfe5 --- /dev/null +++ b/Standard Gaming Platform/debug_util.h @@ -0,0 +1,54 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a cross platform interface for helper functions related to debuggers. +// You should use this to test if you're running under a debugger, and if you +// would like to yield (breakpoint) into the debugger. + +#ifndef BASE_DEBUG_UTIL_H_ +#define BASE_DEBUG_UTIL_H_ + +#include +#include + +#include "sgp_logger.h" + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// An older, deprecated, politically incorrect name for the above. +#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName) + +// A stacktrace can be helpful in debugging. For example, you can include a +// stacktrace member in a object (probably around #ifndef NDEBUG) so that you +// can later see where the given object was created from. +class StackTrace { +public: + // Create a stacktrace from the current location + StackTrace(); + // Get an array of instruction pointer values. + // count: (output) the number of elements in the returned array + const void *const *Addresses(size_t* count); + // Print a backtrace to stderr + void PrintBacktrace(const char* msg); + + // Resolve backtrace to symbols and write to stream. + void OutputToStream(const char* msg, sgp::Logger::LogInstance* os); + +private: + std::vector trace_; + int count_; + + DISALLOW_EVIL_CONSTRUCTORS(StackTrace); +}; + +namespace sgp +{ + void dumpStackTrace(vfs::String const& msg); +} + +#endif // BASE_DEBUG_UTIL_H_ diff --git a/Standard Gaming Platform/debug_win_util.cpp b/Standard Gaming Platform/debug_win_util.cpp new file mode 100644 index 00000000..7e9df4ad --- /dev/null +++ b/Standard Gaming Platform/debug_win_util.cpp @@ -0,0 +1,223 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + + +#if defined(_MSC_VER) + +#include "debug_util.h" + +#include + + +#include +#include + +#include + + + +// The arraysize(arr) macro returns the # of elements in an array arr. +// The expression is a compile-time constant, and therefore can be +// used in defining new arrays, for example. If you use arraysize on +// a pointer by mistake, you will get a compile-time error. +// +// One caveat is that arraysize() doesn't accept any array of an +// anonymous type or a type defined inside a function. In these rare +// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is +// due to a limitation in C++'s template system. The limitation might +// eventually be removed, but it hasn't happened yet. + +// This template function declaration is used in defining arraysize. +// Note that the function doesn't need an implementation, as we only +// use its type. +template +char (&ArraySizeHelper(T (&array)[N]))[N]; + +// That gcc wants both of these prototypes seems mysterious. VC, for +// its part, can't decide which to use (another mystery). Matching of +// template overloads: the final frontier. +#ifndef _MSC_VER +template +char (&ArraySizeHelper(const T (&array)[N]))[N]; +#endif + +#define arraysize(array) (sizeof(ArraySizeHelper(array))) + + +namespace { + // SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family + // of functions. The Sym* family of functions may only be invoked by one + // thread at a time. SymbolContext code may access a symbol server over the + // network while holding the lock for this singleton. In the case of high + // latency, this code will adversly affect performance. + // + // There is also a known issue where this backtrace code can interact + // badly with breakpad if breakpad is invoked in a separate thread while + // we are using the Sym* functions. This is because breakpad does now + // share a lock with this function. See this related bug: + // + // http://code.google.com/p/google-breakpad/issues/detail?id=311 + // + // This is a very unlikely edge case, and the current solution is to + // just ignore it. + class SymbolContext { + public: + static SymbolContext* Get() { + static SymbolContext* s_singleton = NULL; + if(!s_singleton) s_singleton = new SymbolContext(); + return s_singleton; + // We use a leaky singleton because code may call this during process + // termination. + + //return Singleton >::get(); + } + + // Returns the error code of a failed initialization. + DWORD init_error() const { + return init_error_; + } + + // For the given trace, attempts to resolve the symbols, and output a trace + // to the ostream os. The format for each line of the backtrace is: + // + // SymbolName[0xAddress+Offset] (FileName:LineNo) + // + // This function should only be called if Init() has been called. We do not + // LOG(FATAL) here because this code is called might be triggered by a + // LOG(FATAL) itself. + void OutputTraceToStream(const std::vector& trace, sgp::Logger::LogInstance* os) { + //AutoLock lock(lock_); + + for (size_t i = 0; (i < trace.size()); ++i) { + const int kMaxNameLength = 256; + DWORD_PTR frame = reinterpret_cast(trace[i]); + + // Code adapted from MSDN example: + // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx + ULONG64 buffer[ + (sizeof(SYMBOL_INFO) + + kMaxNameLength * sizeof(wchar_t) + + sizeof(ULONG64) - 1) / + sizeof(ULONG64)]; + + // Initialize symbol information retrieval structures. + DWORD64 sym_displacement = 0; + PSYMBOL_INFO symbol = reinterpret_cast(&buffer[0]); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = kMaxNameLength; + BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame, + &sym_displacement, symbol); + + // Attempt to retrieve line number information. + DWORD line_displacement = 0; + IMAGEHLP_LINE64 line = {}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame, + &line_displacement, &line); + + // Output the backtrace line. + (*os) << " "; + if (has_symbol) + { + (*os) << " [0x" << trace[i] << "+" << sym_displacement << "]\t"; + (*os) << vfs::String(symbol->Name); + } + else + { + (*os) << " [0x" << trace[i] << "]\t"; + // If there is no symbol information, add a spacer. + (*os) << " (No symbol)"; + } + if (has_line) + { + (*os) << " - (" << line.FileName << ":" << line.LineNumber << ")"; + } + (*os) << sgp::endl; + } + (*os) << sgp::endl; + } + + private: + SymbolContext() : init_error_(ERROR_SUCCESS) { + // Initializes the symbols for the process. + // Defer symbol load until they're needed, use undecorated names, and + // get line numbers. + SymSetOptions(SYMOPT_DEFERRED_LOADS | + SYMOPT_UNDNAME | + SYMOPT_LOAD_LINES); + if (SymInitialize(GetCurrentProcess(), NULL, TRUE)) { + init_error_ = ERROR_SUCCESS; + } else { + __debugbreak(); + init_error_ = GetLastError(); + } + } + + DWORD init_error_; + //Lock lock_; + DISALLOW_COPY_AND_ASSIGN(SymbolContext); + }; + +} // namespace + +#define ENABLE_STACK_TRACE 0 +StackTrace::StackTrace() { + // From http://msdn.microsoft.com/en-us/library/bb204633(VS.85).aspx, + // the sum of FramesToSkip and FramesToCapture must be less than 63, + // so set it to 62. + const int kMaxCallers = 62; + + void* callers[kMaxCallers]; + // TODO(ajwong): Migrate this to StackWalk64. + + // WANNE: VS 2005 compilation error + // WANNE: I disabled the method call "CaptureStackBackTrace()" because it gives a compilation error in VS 2005 +#if ENABLE_STACK_TRACE + int count = CaptureStackBackTrace(0, kMaxCallers, callers, NULL); + + // WANNE: This also does not work in VS 2005 + //int count = RtlCaptureStackBackTrace(0, kMaxCallers, callers, NULL); + if (count > 0) { + trace_.resize(count); + memcpy(&trace_[0], callers, sizeof(callers[0]) * count); + } else { + trace_.resize(0); + } +#endif +} + +static struct StackTraceLog { + sgp::Logger_ID id; + StackTraceLog() { + id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(id, L"stack_trace.log", false, sgp::Logger::FLUSH_ON_ENDL); + }; +} s_log; + +void StackTrace::PrintBacktrace(const char* msg) { + OutputToStream(msg, &(SGP_LOG(s_log.id))); +} + +void StackTrace::OutputToStream(const char* msg, sgp::Logger::LogInstance* os) { + SymbolContext* context = SymbolContext::Get(); + DWORD error = context->init_error(); + if (error != ERROR_SUCCESS) + { + (*os) << "Error initializing symbols (" << error + << "). Dumping unresolved backtrace:" + << sgp::endl; + for (size_t i = 0; (i < trace_.size()); ++i) + { + (*os) << "\t" << trace_[i] << sgp::endl; + } + } + else + { + (*os) << L"Backtrace: " << (msg != NULL ? msg : "") << sgp::endl; + context->OutputTraceToStream(trace_, os); + } +} + +#endif // _MSC_VER diff --git a/Standard Gaming Platform/himage.cpp b/Standard Gaming Platform/himage.cpp index b91dfe8e..08d5c1a6 100644 --- a/Standard Gaming Platform/himage.cpp +++ b/Standard Gaming Platform/himage.cpp @@ -20,9 +20,9 @@ #include "vobject.h" #endif -#include "VFS/vfs.h" +#include -const utf8string::str_t CONST_DOTJPC(L".jpc.7z"); +const vfs::String::str_t CONST_DOTJPC(L".jpc.7z"); @@ -52,14 +52,92 @@ typedef union UINT32 uiValue; } SplitUINT32; -HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents ) +namespace ImageFileType { - HIMAGE hImage = NULL; - SGPFILENAME Extension; - CHAR8 ExtensionSep[] = "."; - STR StrPtr; + typedef std::map ExtMap_t; + + static int map(vfs::String const& ext) + { + static ExtMap_t _ext_map; + static bool inited = false; + if(!inited) + { + _ext_map["pcx"] = PCX_FILE_READER; + _ext_map["tga"] = TGA_FILE_READER; + _ext_map["sti"] = STCI_FILE_READER; + _ext_map["png"] = PNG_FILE_READER; + _ext_map["jpc.7z"] = JPC_FILE_READER; + inited = true; + } + ExtMap_t::const_iterator cit = _ext_map.find(ext); + if(cit != _ext_map.end()) + { + return cit->second; + } + return UNKNOWN_FILE_READER; + } + + static int getFileReaderType(std::string& filename, TestOrder order) + { + std::string::size_type pos = filename.find_last_of("."); + std::string ext = filename.substr(pos+1, std::string::npos); + if(ext.empty()) + { + ext = "pcx"; + filename += ".pcx"; + } + int reader_type = map(ext); + + /* + * if DEFAULT, then just check existance of file + * if not STI, then there is no different load order, just continue as usual + */ + if(order == DEFAULT || reader_type != STCI_FILE_READER) + { + return getVFS()->fileExists(filename) ? reader_type : UNKNOWN_FILE_READER; + } + /* + * file must have originally been an STI file, but should be treated as a JPC or a PNG file + */ + else if(order == JPC || order == PNG) + { + vfs::String file = filename.substr(0, pos+1).append(order == JPC ? "jpc.7z" : "png"); + if( getVFS()->fileExists(file) ) + { + filename = file.utf8(); + return order == JPC ? JPC_FILE_READER : PNG_FILE_READER; + } + return UNKNOWN_FILE_READER; + } + /* + * file must have originally been an STI file, but should be treated as a JPC or a PNG file + * if the replacement filetypes don't exist, fall back to STI + */ + else if(order == JPC_FALLBACK || order == PNG_FALLBACK) + { + vfs::String file = filename.substr(0, pos+1).append(order == JPC_FALLBACK ? "jpc.7z" : "png"); + if( getVFS()->fileExists(file) ) + { + filename = file.utf8(); + return order == JPC_FALLBACK ? JPC_FILE_READER : PNG_FILE_READER; + } + // fallback to original type + return getVFS()->fileExists(filename) ? reader_type : UNKNOWN_FILE_READER; + } + return UNKNOWN_FILE_READER; + } +}; + +HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents, ImageFileType::TestOrder order ) +{ + HIMAGE hImage = NULL; + CHAR8 ExtensionSep[] = "."; UINT32 iFileLoader; +#if 0 + SGPFILENAME Extension; + STR StrPtr; + // Depending on extension of filename, use different image readers // Get extension StrPtr = strstr( ImageFile, ExtensionSep ); @@ -96,9 +174,9 @@ HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents ) #ifdef USE_VFS // see if there is a .jpc file first and when that fails, try .sti vfs::Path str(ImageFile); - utf8string::str_t const& findext = str.c_wcs(); - utf8string::size_t dot = findext.find_last_of(vfs::Const::DOT()); - utf8string fname = findext.substr(0,dot).append(CONST_DOTJPC); + vfs::String::str_t const& findext = str.c_wcs(); + vfs::String::size_t dot = findext.find_last_of(vfs::Const::DOT()); + vfs::String fname = findext.substr(0,dot).append(CONST_DOTJPC); if(getVFS()->fileExists(fname)) { iFileLoader = JPC_FILE_READER; @@ -116,7 +194,7 @@ HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents ) break; } #ifdef USE_VFS - else if ( StrCmp::Equal(Extension, L"jpc.7z") ) + else if ( vfs::StrCmp::Equal(Extension, L"jpc.7z") ) { iFileLoader = JPC_FILE_READER; break; @@ -137,6 +215,23 @@ HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents ) return( NULL ); } +#else + std::string filename(ImageFile); + iFileLoader = ImageFileType::getFileReaderType(filename, order); + if ( iFileLoader == UNKNOWN_FILE_READER ) + { + //If in debug, make fatal! +#ifdef JA2 +#ifdef _DEBUG + //FatalError( "Resource file %s does not exist.", ImageFile ); +#endif +#endif + DbgMessage( TOPIC_HIMAGE, DBG_LEVEL_2, String("Resource file %s does not exist.", ImageFile) ); + + return( NULL ); + } + +#endif // Create memory for image structure hImage = (HIMAGE)MemAlloc( sizeof( image_type ) ); @@ -152,7 +247,7 @@ HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents ) //hImage->pui16BPPPalette = NULL; // Set filename and loader - strcpy( hImage->ImageFile, ImageFile ); + strncpy( hImage->ImageFile, /*ImageFile*/filename.c_str(), filename.length() ); hImage->iFileLoader = iFileLoader; if ( !LoadImageData( hImage, fContents ) ) diff --git a/Standard Gaming Platform/himage.h b/Standard Gaming Platform/himage.h index 2396b23c..bc997f72 100644 --- a/Standard Gaming Platform/himage.h +++ b/Standard Gaming Platform/himage.h @@ -138,9 +138,21 @@ typedef struct extern "C" { #endif +namespace ImageFileType +{ + enum TestOrder + { + DEFAULT = 0, // check extension + JPC, // ignore file extension, test only *.jpc + JPC_FALLBACK, // test *.jpc, fallback to original type + PNG, // ignore file extension, test only *.png + PNG_FALLBACK, // test *.png, fallback to original type + }; +}; + // This function will return NULL if it fails, and call SetLastError() to set // error information -HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents ); +HIMAGE CreateImage( SGPFILENAME ImageFile, UINT16 fContents, ImageFileType::TestOrder order = ImageFileType::JPC_FALLBACK); // This function destroys the HIMAGE structure as well as its contents BOOLEAN DestroyImage( HIMAGE hImage ); diff --git a/Standard Gaming Platform/input.cpp b/Standard Gaming Platform/input.cpp index 568484ca..874d87f2 100644 --- a/Standard Gaming Platform/input.cpp +++ b/Standard Gaming Platform/input.cpp @@ -8,6 +8,10 @@ #elif defined( WIZ8_PRECOMPILED_HEADERS ) #include "WIZ8 SGP ALL.H" #else +//** dd . +#define _WIN32_WINNT 0x500 + +//** #include "types.h" #include #include //dnl @@ -69,12 +73,18 @@ BOOLEAN gfRecordedLeftButtonUp; UINT32 guiLeftButtonRepeatTimer; UINT32 guiRightButtonRepeatTimer; +UINT32 guiMiddleButtonRepeatTimer; +UINT32 guiX1ButtonRepeatTimer; +UINT32 guiX2ButtonRepeatTimer; BOOLEAN gfTrackMousePos; // TRUE = queue mouse movement events, FALSE = don't BOOLEAN gfLeftButtonState; // TRUE = Pressed, FALSE = Not Pressed BOOLEAN gfRightButtonState; // TRUE = Pressed, FALSE = Not Pressed BOOLEAN gfMiddleButtonState;//dnl TRUE = Pressed, FALSE = Not Pressed -INT16 gsMouseWheelDeltaValue;//dnl positive value indicates that the wheel was rotated forward, negative value indicates that the wheel was rotated backward, and user handler procedure for mouse wheel should restore after usege this value to zero! +//INT16 gsMouseWheelDeltaValue;//dnl positive value indicates that the wheel was rotated forward, negative value indicates that the wheel was rotated backward, and user handler procedure for mouse wheel should restore after usege this value to zero! +BOOLEAN gfX1ButtonState; +BOOLEAN gfX2ButtonState; + INT16 gusMouseXPos; // X position of the mouse on screen INT16 gusMouseYPos; // y position of the mouse on screen @@ -104,322 +114,131 @@ StringInput *gpCurrentStringDescriptor; void QueueEvent(UINT16 ubInputEvent, UINT32 usParam, UINT32 uiParam); void RedirectToString(UINT16 uiInputCharacter); -void HandleSingleClicksAndButtonRepeats( void ); -void AdjustMouseForWindowOrigin(void); +void HandleSingleClicksAndButtonRepeats( void ); +void AdjustMouseForWindowOrigin(void); // These are the hook functions for both keyboard and mouse LRESULT CALLBACK KeyboardHandler(int Code, WPARAM wParam, LPARAM lParam) { -#ifndef JA2 - if((Code < 0) || (!gfApplicationActive)) -#else - if (Code < 0) -#endif - { // Do not handle this message, pass it on to another window - return CallNextHookEx(ghKeyboardHook, Code, wParam, lParam); - } + if (Code < 0) // Do not handle this message, pass it on to another window + return CallNextHookEx(ghKeyboardHook, Code, wParam, lParam); - if (lParam & TRANSITION_MASK) - { // The key has been released - KeyUp(wParam, lParam); - //gfSGPInputReceived = TRUE; - } + if (lParam & TRANSITION_MASK) // The key has been released + KeyUp(wParam, lParam); //gfSGPInputReceived = TRUE; else { // Key was up KeyDown(wParam, lParam); gfSGPInputReceived = TRUE; } - return TRUE; } -#ifdef JA2 LRESULT CALLBACK MouseHandler(int Code, WPARAM wParam, LPARAM lParam) { UINT32 uiParam; POINT mpos; + MOUSEHOOKSTRUCTEX* p_mhs; -#ifndef JA2 - if((Code < 0) || (!gfApplicationActive)) -#else - if (Code < 0) -#endif - { // Do not handle this message, pass it on to another window - return CallNextHookEx(ghMouseHook, Code, wParam, lParam); - } + if (Code < 0) // Do not handle this message, pass it on to another window + return CallNextHookEx(ghMouseHook, Code, wParam, lParam); + + p_mhs = (MOUSEHOOKSTRUCTEX*)lParam; + + mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; + ScreenToClient( ghWindow, &mpos); + gusMouseXPos = (INT16)mpos.x; + gusMouseYPos = (INT16)mpos.y; + uiParam = gusMouseYPos; + uiParam = uiParam << 16; + uiParam = uiParam | gusMouseXPos; switch (wParam) { - case WM_LBUTTONDOWN : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient( ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update the button state - gfLeftButtonState = TRUE; - - //Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event - QueueEvent(LEFT_BUTTON_DOWN, 0, uiParam); + case WM_XBUTTONDOWN://** + if( p_mhs->mouseData== (XBUTTON1<<16) ) //MessageBeep(-1); + { + gfX1ButtonState = TRUE; + gfSGPInputReceived = TRUE; + QueueEvent(X1_BUTTON_DOWN, 0, uiParam); + } + if( p_mhs->mouseData== (XBUTTON2<<16) ) //MessageBeep(0x00000040L); + { + gfX2ButtonState = TRUE; + gfSGPInputReceived = TRUE; + QueueEvent(X2_BUTTON_DOWN, 0, uiParam); + } break; - case WM_LBUTTONUP : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient( ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update the button state - gfLeftButtonState = FALSE; - - // Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event - QueueEvent(LEFT_BUTTON_UP, 0, uiParam); + case WM_XBUTTONUP://** + if( p_mhs->mouseData== (XBUTTON1<<16) ) + { + gfX1ButtonState = FALSE; + gfSGPInputReceived = TRUE; + QueueEvent(X1_BUTTON_UP, 0, uiParam); + } + if( p_mhs->mouseData== (XBUTTON2<<16) ) + { + gfX2ButtonState = FALSE; + gfSGPInputReceived = TRUE; + QueueEvent(X2_BUTTON_UP, 0, uiParam); + } break; - case WM_RBUTTONDOWN : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient( ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update the button state - gfRightButtonState = TRUE; - - // Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event - QueueEvent(RIGHT_BUTTON_DOWN, 0, uiParam); + case WM_MOUSEWHEEL: + if(p_mhs->mouseData==(WHEEL_DELTA<<16)) //up MessageBeep(-1); + QueueEvent(MOUSE_WHEEL_UP, 0, uiParam); + if(p_mhs->mouseData==(-WHEEL_DELTA<<16)) //dn MessageBeep(0x00000040L); + QueueEvent(MOUSE_WHEEL_DOWN, 0, uiParam); break; - case WM_RBUTTONUP : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient( ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update the button state - gfRightButtonState = FALSE; - - //Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event - QueueEvent(RIGHT_BUTTON_UP, 0, uiParam); + case WM_MBUTTONDOWN: + gfMiddleButtonState= TRUE; //Set that we have input + gfSGPInputReceived = TRUE;//Set that we have input + QueueEvent(MIDDLE_BUTTON_DOWN, 0, uiParam);// Trigger an input event break; - - //dnl begin part for additional mouse events - case WM_MBUTTONDOWN : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient(ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update the button state - gfMiddleButtonState = TRUE; - - //Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event - QueueEvent(MIDDLE_BUTTON_DOWN, 0, uiParam); - break; - case WM_MBUTTONUP : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient(ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update the button state - gfMiddleButtonState = FALSE; - - //Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event + case WM_MBUTTONUP: + gfMiddleButtonState= FALSE; + gfSGPInputReceived = TRUE; QueueEvent(MIDDLE_BUTTON_UP, 0, uiParam); break; - //case WM_MBUTTONDBLCLK: - // break; - case WM_MOUSEWHEEL : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient(ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - - // Update mouse wheel delta value - gsMouseWheelDeltaValue = GetMouseWheelDeltaValue(((MOUSEHOOKSTRUCTEX *)lParam)->mouseData); - - //Set that we have input - gfSGPInputReceived = TRUE; - - // Trigger an input event - QueueEvent(MOUSE_WHEEL, 0, uiParam); + case WM_LBUTTONDOWN: + gfLeftButtonState = TRUE; + gfSGPInputReceived = TRUE; + QueueEvent(LEFT_BUTTON_DOWN, 0, uiParam); break; - - //dnl end part for additional mouse events - case WM_MOUSEMOVE : - // Update the current mouse position - mpos = ((MOUSEHOOKSTRUCT *)lParam)->pt; - ScreenToClient( ghWindow, &mpos); - gusMouseXPos = (INT16)mpos.x; - gusMouseYPos = (INT16)mpos.y; - uiParam = gusMouseYPos; - uiParam = uiParam << 16; - uiParam = uiParam | gusMouseXPos; - + case WM_LBUTTONUP: + gfLeftButtonState = FALSE; + gfSGPInputReceived = TRUE; + QueueEvent(LEFT_BUTTON_UP, 0, uiParam); + break; + case WM_RBUTTONDOWN: + gfRightButtonState = TRUE; + gfSGPInputReceived = TRUE; + QueueEvent(RIGHT_BUTTON_DOWN, 0, uiParam); + break; + case WM_RBUTTONUP: + gfRightButtonState = FALSE; + gfSGPInputReceived = TRUE; + QueueEvent(RIGHT_BUTTON_UP, 0, uiParam); + break; + case WM_MOUSEMOVE: // Trigger an input event if (gfTrackMousePos == TRUE) - { QueueEvent(MOUSE_POS, 0, uiParam); - } - //Set that we have input - gfSGPInputReceived = TRUE; + gfSGPInputReceived = TRUE; break; - default : + default: return CallNextHookEx(ghMouseHook, Code, wParam, lParam); } + //ddd why below code commented? // if (gusMouseXPos < 0 || gusMouseXPos >= SCREEN_WIDTH || // gusMouseYPos < 0 || gusMouseYPos >= SCREEN_HEIGHT) - { return CallNextHookEx(ghMouseHook, Code, wParam, lParam); - } return TRUE; } -#else -// Wizardry mouse hander - -LRESULT CALLBACK MouseHandler(int Code, WPARAM wParam, LPARAM lParam) -{ - UINT32 uiParam; - UINT32 uiXPos, uiYPos; - RECT rcClient; - BOOLEAN fOutsideClient=FALSE; - static BOOLEAN fResizing=FALSE; - LRESULT Result; - - uiXPos= (((MOUSEHOOKSTRUCT *)lParam)->pt).x; - uiYPos= (((MOUSEHOOKSTRUCT *)lParam)->pt).y; - - if(!VideoIsFullScreen()) - { - if(wParam==WM_NCLBUTTONDOWN) - { - fResizing=TRUE; - } - VideoGetClientRect(&rcClient); - if((uiXPos < (UINT32)rcClient.left) || (uiXPos > (UINT32)rcClient.right) || (uiYPos < (UINT32)rcClient.top) || (uiYPos > (UINT32)rcClient.bottom)) - { - fOutsideClient=TRUE; - } - } - - if((Code < 0) || (!gfApplicationActive) || fOutsideClient || fResizing) - { - // Do not handle this message, pass it on to another window - Result = CallNextHookEx(ghMouseHook, Code, wParam, lParam); - - if((wParam==WM_LBUTTONUP) || (wParam==WM_NCLBUTTONUP)) - { - fResizing=FALSE; - } - return(Result); - } - - switch (wParam) - { - case WM_LBUTTONUP: - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MOUSEMOVE: - if(VideoIsFullScreen()) - { - gusMouseXPos = (UINT16)(uiXPos); - gusMouseYPos = (UINT16)(uiYPos); - } - else - { - gusMouseXPos = (UINT16)(uiXPos-rcClient.left); - gusMouseYPos = (UINT16)(uiYPos-rcClient.top); - } - uiParam = (UINT32)gusMouseYPos<<16 | (UINT32)gusMouseXPos; - - //Set that we have input - gfSGPInputReceived = TRUE; - break; - } - - if ( wParam == WM_MOUSEWHEEL ) - { - return( FALSE ); - } - - switch (wParam) - { - case WM_LBUTTONDOWN: - gfLeftButtonState = TRUE; - QueueEvent(LEFT_BUTTON_DOWN, 0, uiParam); - break; - case WM_LBUTTONUP: - gfLeftButtonState = FALSE; - QueueEvent(LEFT_BUTTON_UP, 0, uiParam); - break; - case WM_RBUTTONDOWN: - gfRightButtonState = TRUE; - QueueEvent(RIGHT_BUTTON_DOWN, 0, uiParam); - break; - case WM_RBUTTONUP: - gfRightButtonState = FALSE; - QueueEvent(RIGHT_BUTTON_UP, 0, uiParam); - break; - case WM_MOUSEMOVE: - if(gfTrackMousePos) - QueueEvent(MOUSE_POS, 0, uiParam); - break; - } - - return(TRUE); -} - -#endif BOOLEAN InitializeInputManager(void) { @@ -531,19 +350,25 @@ void QueueEvent(UINT16 ubInputEvent, UINT32 usParam, UINT32 uiParam) } if (ubInputEvent == RIGHT_BUTTON_DOWN) - { guiRightButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT; - } + if (ubInputEvent == MIDDLE_BUTTON_DOWN) + guiMiddleButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT; + if (ubInputEvent == X1_BUTTON_DOWN) + guiX1ButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT; + if (ubInputEvent == X2_BUTTON_DOWN) + guiX2ButtonRepeatTimer = uiTimer + BUTTON_REPEAT_TIMEOUT; if (ubInputEvent == LEFT_BUTTON_UP) - { guiLeftButtonRepeatTimer = 0; - } - if (ubInputEvent == RIGHT_BUTTON_UP) - { guiRightButtonRepeatTimer = 0; - } + if (ubInputEvent == MIDDLE_BUTTON_UP) + guiMiddleButtonRepeatTimer = 0; + if (ubInputEvent == X1_BUTTON_UP) + guiX1ButtonRepeatTimer = 0; + if (ubInputEvent == X2_BUTTON_UP) + guiX2ButtonRepeatTimer = 0; + if ( (ubInputEvent == LEFT_BUTTON_UP) ) { diff --git a/Standard Gaming Platform/input.h b/Standard Gaming Platform/input.h index 36b6f0f0..fc5fa577 100644 --- a/Standard Gaming Platform/input.h +++ b/Standard Gaming Platform/input.h @@ -18,9 +18,21 @@ #define RIGHT_BUTTON_UP 0x0100 #define RIGHT_BUTTON_REPEAT 0x0200 #define MOUSE_POS 0x0400 -#define MOUSE_WHEEL 0x0800 -#define MIDDLE_BUTTON_UP 0x1000//dnl -#define MIDDLE_BUTTON_DOWN 0x2000//dnl +#define MOUSE_WHEEL 0x0800 +#define MOUSE_WHEEL_UP 0x0800 +#define MOUSE_WHEEL_DOWN 0x1000 +#define MIDDLE_BUTTON_DOWN 0x2000 +#define MIDDLE_BUTTON_UP 0x4000 +#define MIDDLE_BUTTON_REPEAT 0x8000 +#define X1_BUTTON_DOWN 0x8010 +#define X1_BUTTON_UP 0x8020 +#define X1_BUTTON_REPEAT 0x8030 +#define X2_BUTTON_DOWN 0x8040 +#define X2_BUTTON_UP 0x8050 +#define X2_BUTTON_REPEAT 0x8060 +//#define MIDDLE_BUTTON_UP 0x1000//dnl +//#define MIDDLE_BUTTON_DOWN 0x2000//dnl + #define SHIFT_DOWN 0x01 #define CTRL_DOWN 0x02 diff --git a/Standard Gaming Platform/mousesystem.cpp b/Standard Gaming Platform/mousesystem.cpp index 2a75b271..5071d13e 100644 --- a/Standard Gaming Platform/mousesystem.cpp +++ b/Standard Gaming Platform/mousesystem.cpp @@ -40,6 +40,8 @@ #include "mousesystem.h" #include "Cursor Control.h" #include "Button System.h" + ///***ddd + #include "GameSettings.h" #endif #ifdef JA2_PRECOMPILED_HEADERS @@ -79,7 +81,8 @@ INT32 MSYS_CurrentID=MSYS_ID_SYSTEM; INT16 MSYS_CurrentMX=0; INT16 MSYS_CurrentMY=0; INT16 MSYS_CurrentButtons=0; -INT16 MSYS_Action=0; +INT16 MSYS_Action=MSYS_NO_ACTION; +INT16 MSYS_Wheel=0; BOOLEAN MSYS_SystemInitialized=FALSE; BOOLEAN MSYS_UseMouseHandlerHook=FALSE; @@ -114,7 +117,7 @@ void ExecuteMouseHelpEndCallBack( MOUSE_REGION *region ); //values there as well. That's the only reason why I left this here. MOUSE_REGION MSYS_SystemBaseRegion = { MSYS_ID_SYSTEM, MSYS_PRIORITY_SYSTEM, BASE_REGION_FLAGS, - -32767, -32767, 32767, 32767, 0, 0, 0, 0, 0, 0, + -32767, -32767, 32767, 32767, 0, 0, 0, 0, 0, 0, 0, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK, { 0,0,0,0 }, 0, 0, -1, MSYS_NO_CALLBACK, NULL, NULL }; @@ -158,6 +161,7 @@ INT32 MSYS_Init(void) MSYS_CurrentMX = 0; MSYS_CurrentMY = 0; MSYS_CurrentButtons = 0; + MSYS_Wheel = 0; MSYS_Action=MSYS_NO_ACTION; MSYS_PrevRegion = NULL; @@ -168,25 +172,26 @@ INT32 MSYS_Init(void) MSYS_GrabRegion = NULL; // Setup the system's background region - MSYS_SystemBaseRegion.IDNumber = MSYS_ID_SYSTEM; - MSYS_SystemBaseRegion.PriorityLevel = MSYS_PRIORITY_SYSTEM; - MSYS_SystemBaseRegion.uiFlags = BASE_REGION_FLAGS; - MSYS_SystemBaseRegion.RegionTopLeftX = -32767; - MSYS_SystemBaseRegion.RegionTopLeftY = -32767; + MSYS_SystemBaseRegion.IDNumber = MSYS_ID_SYSTEM; + MSYS_SystemBaseRegion.PriorityLevel = MSYS_PRIORITY_SYSTEM; + MSYS_SystemBaseRegion.uiFlags = BASE_REGION_FLAGS; + MSYS_SystemBaseRegion.RegionTopLeftX = -32767; + MSYS_SystemBaseRegion.RegionTopLeftY = -32767; MSYS_SystemBaseRegion.RegionBottomRightX = 32767; MSYS_SystemBaseRegion.RegionBottomRightY = 32767; - MSYS_SystemBaseRegion.MouseXPos = 0; - MSYS_SystemBaseRegion.MouseYPos = 0; - MSYS_SystemBaseRegion.RelativeXPos = 0; - MSYS_SystemBaseRegion.RelativeYPos = 0; - MSYS_SystemBaseRegion.ButtonState = 0; - MSYS_SystemBaseRegion.Cursor = 0; - MSYS_SystemBaseRegion.UserData[0] = 0; - MSYS_SystemBaseRegion.UserData[1] = 0; - MSYS_SystemBaseRegion.UserData[2] = 0; - MSYS_SystemBaseRegion.UserData[3] = 0; + MSYS_SystemBaseRegion.MouseXPos = 0; + MSYS_SystemBaseRegion.MouseYPos = 0; + MSYS_SystemBaseRegion.RelativeXPos = 0; + MSYS_SystemBaseRegion.RelativeYPos = 0; + MSYS_SystemBaseRegion.ButtonState = 0; + MSYS_SystemBaseRegion.Cursor = 0; + MSYS_SystemBaseRegion.WheelState = 0; + MSYS_SystemBaseRegion.UserData[0] = 0; + MSYS_SystemBaseRegion.UserData[1] = 0; + MSYS_SystemBaseRegion.UserData[2] = 0; + MSYS_SystemBaseRegion.UserData[3] = 0; MSYS_SystemBaseRegion.MovementCallback = MSYS_NO_CALLBACK; - MSYS_SystemBaseRegion.ButtonCallback = MSYS_NO_CALLBACK; + MSYS_SystemBaseRegion.ButtonCallback = MSYS_NO_CALLBACK; MSYS_SystemBaseRegion.FastHelpTimer = 0; MSYS_SystemBaseRegion.FastHelpText = 0; @@ -204,7 +209,17 @@ INT32 MSYS_Init(void) return(1); } - +/* +LONG WINAPI UEFilter(PEXCEPTION_POINTERS pEI) +{ + MessageBox(NULL, ("Exception"), ("Oops !!!"), MB_ICONSTOP); + TerminateProcess(GetCurrentProcess(), -1); + return -1; +} + SetUnhandledExceptionFilter(UEFilter); + +*(char*)0 = 0; +*/ //====================================================================================================== @@ -232,6 +247,8 @@ void MSYS_Shutdown(void) // void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLEAN LeftButton, BOOLEAN RightButton) { + + // If the mouse system isn't initialized, get out o' here if(!MSYS_SystemInitialized) return; @@ -240,6 +257,12 @@ void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLE if(!MSYS_UseMouseHandlerHook) return; + if(!gGameExternalOptions.fExtMouseKeyEnabled && + (Type == MIDDLE_BUTTON_UP || Type == MIDDLE_BUTTON_DOWN || Type == X1_BUTTON_DOWN || + Type == X1_BUTTON_UP || Type == X2_BUTTON_DOWN || Type == X2_BUTTON_UP || Type == X1_BUTTON_REPEAT || + Type == X2_BUTTON_REPEAT || Type == MOUSE_WHEEL_UP || Type == MOUSE_WHEEL_DOWN ) ) + return; + MSYS_Action=MSYS_NO_ACTION; switch(Type) { @@ -247,12 +270,23 @@ void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLE case LEFT_BUTTON_UP: case RIGHT_BUTTON_DOWN: case RIGHT_BUTTON_UP: + case MIDDLE_BUTTON_UP: + case MIDDLE_BUTTON_DOWN: + case X1_BUTTON_DOWN: + case X1_BUTTON_UP: + case X2_BUTTON_DOWN: + case X2_BUTTON_UP: + //MSYS_Action|=MSYS_DO_BUTTONS; if(Type == LEFT_BUTTON_DOWN) + { MSYS_Action |= MSYS_DO_LBUTTON_DWN; + MSYS_CurrentButtons|=MSYS_LEFT_BUTTON; + } else if(Type == LEFT_BUTTON_UP) { MSYS_Action |= MSYS_DO_LBUTTON_UP; + MSYS_CurrentButtons&=(~MSYS_LEFT_BUTTON); //Kris: //Used only if applicable. This is used for that special button that is locked with the //mouse press -- just like windows. When you release the button, the previous state @@ -265,9 +299,45 @@ void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLE #endif } else if(Type == RIGHT_BUTTON_DOWN) + { MSYS_Action |= MSYS_DO_RBUTTON_DWN; + MSYS_CurrentButtons|=MSYS_RIGHT_BUTTON; + } else if(Type == RIGHT_BUTTON_UP) + { MSYS_Action |= MSYS_DO_RBUTTON_UP; + MSYS_CurrentButtons&=(~MSYS_RIGHT_BUTTON); + } + else if(Type == MIDDLE_BUTTON_DOWN) + { + MSYS_Action |= MSYS_DO_MBUTTON_DWN; + MSYS_CurrentButtons|=MSYS_MIDDLE_BUTTON; + } + else if(Type == MIDDLE_BUTTON_UP) + { + MSYS_Action |= MSYS_DO_MBUTTON_UP; + MSYS_CurrentButtons&=(~MSYS_MIDDLE_BUTTON); + } + else if(Type == X1_BUTTON_DOWN) + { + MSYS_Action |= MSYS_DO_X1BUTTON_DWN; + MSYS_CurrentButtons|=MSYS_X1_BUTTON; + } + else if(Type == X1_BUTTON_UP) + { + MSYS_Action |= MSYS_DO_X1BUTTON_UP; + MSYS_CurrentButtons&=(~MSYS_X1_BUTTON); + } + else if(Type == X2_BUTTON_DOWN) + { + MSYS_Action |= MSYS_DO_X2BUTTON_DWN; + MSYS_CurrentButtons|=MSYS_X2_BUTTON; + } + else if(Type == X2_BUTTON_UP) + { + MSYS_Action |= MSYS_DO_X2BUTTON_UP; + MSYS_CurrentButtons&=(~MSYS_X2_BUTTON); + } if(LeftButton) MSYS_CurrentButtons|=MSYS_LEFT_BUTTON; @@ -293,11 +363,20 @@ void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLE // Call mouse region with new reason case LEFT_BUTTON_REPEAT: case RIGHT_BUTTON_REPEAT: + case MIDDLE_BUTTON_REPEAT: + case X1_BUTTON_REPEAT: + case X2_BUTTON_REPEAT: if(Type == LEFT_BUTTON_REPEAT) MSYS_Action |= MSYS_DO_LBUTTON_REPEAT; else if(Type == RIGHT_BUTTON_REPEAT) MSYS_Action |= MSYS_DO_RBUTTON_REPEAT; + else if(Type == MIDDLE_BUTTON_REPEAT) + MSYS_Action |= MSYS_DO_MBUTTON_REPEAT; + else if(Type == X1_BUTTON_REPEAT) + MSYS_Action |= MSYS_DO_X1BUTTON_REPEAT; + else if(Type == X2_BUTTON_REPEAT) + MSYS_Action |= MSYS_DO_X2BUTTON_REPEAT; if((Xcoord != MSYS_CurrentMX) || (Ycoord != MSYS_CurrentMY)) { @@ -308,6 +387,20 @@ void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLE MSYS_UpdateMouseRegion(); break; + case MOUSE_WHEEL_UP: + case MOUSE_WHEEL_DOWN: + if(Type == MOUSE_WHEEL_UP) + { + MSYS_Action |= MSYS_DO_WHEEL_UP; + MSYS_Wheel++; + } + else if(Type == MOUSE_WHEEL_DOWN) + { + MSYS_Action |= MSYS_DO_WHEEL_DOWN; + MSYS_Wheel--; + } + MSYS_UpdateMouseRegion(); + break; case MOUSE_POS: if((Xcoord != MSYS_CurrentMX) || (Ycoord != MSYS_CurrentMY) || gfRefreshUpdate ) @@ -326,6 +419,17 @@ void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLE DbgMessage(TOPIC_MOUSE_SYSTEM, DBG_LEVEL_0, "ERROR -- MSYS 2 SGP Mouse Hook got bad type"); break; } + // check for moved mouse + if((Xcoord != MSYS_CurrentMX) || (Ycoord != MSYS_CurrentMY) || gfRefreshUpdate ) + { + MSYS_Action|=MSYS_DO_MOVE; + MSYS_CurrentMX = Xcoord; + MSYS_CurrentMY = Ycoord; + } + + // update if something happened + if (MSYS_Action != MSYS_NO_ACTION) + MSYS_UpdateMouseRegion(); } @@ -713,6 +817,8 @@ void MSYS_UpdateMouseRegion(void) MSYS_CurrRegion->RelativeYPos = MSYS_CurrentMY - MSYS_CurrRegion->RegionTopLeftY; MSYS_CurrRegion->ButtonState = MSYS_CurrentButtons; + MSYS_CurrRegion->WheelState = MSYS_Wheel; + MSYS_Wheel = 0; if( MSYS_CurrRegion->uiFlags & MSYS_REGION_ENABLED && MSYS_CurrRegion->uiFlags & MSYS_MOVE_CALLBACK && MSYS_Action & MSYS_DO_MOVE ) @@ -1080,7 +1186,7 @@ void MSYS_DisableRegion(MOUSE_REGION *region) // void MSYS_SetCurrentCursor(UINT16 Cursor) { - TRYCATCH_RETHROW(SetCurrentCursorFromDatabase( Cursor ), "Could not set Cursor"); + SGP_TRYCATCH_RETHROW(SetCurrentCursorFromDatabase( Cursor ), "Could not set Cursor"); } @@ -1746,3 +1852,8 @@ MOUSE_REGION *get_next_entry_in_MSYS_RegList(MOUSE_REGION *current_region) { return current_region->next; } + +void ResetWheelState( MOUSE_REGION *region ) +{ + region->WheelState = 0; +} \ No newline at end of file diff --git a/Standard Gaming Platform/mousesystem.h b/Standard Gaming Platform/mousesystem.h index 89021089..87d17297 100644 --- a/Standard Gaming Platform/mousesystem.h +++ b/Standard Gaming Platform/mousesystem.h @@ -35,22 +35,23 @@ typedef void (*MOUSE_CALLBACK)(struct _MOUSE_REGION *,INT32); // Define MOUSE_CA typedef void (*MOUSE_HELPTEXT_DONE_CALLBACK)( ); // the help is done callback typedef struct _MOUSE_REGION { - UINT16 IDNumber; // Region's ID number, set by mouse system - INT8 PriorityLevel; // Region's Priority, set by system and/or caller - UINT32 uiFlags; // Region's state flags - INT16 RegionTopLeftX; // Screen area affected by this region (absolute coordinates) - INT16 RegionTopLeftY; - INT16 RegionBottomRightX; - INT16 RegionBottomRightY; - INT16 MouseXPos; // Mouse's Coordinates in absolute screen coordinates - INT16 MouseYPos; - INT16 RelativeXPos; // Mouse's Coordinates relative to the Top-Left corner of the region - INT16 RelativeYPos; - UINT16 ButtonState; // Current state of the mouse buttons - UINT16 Cursor; // Cursor to use when mouse in this region (see flags) + UINT16 IDNumber; // Region's ID number, set by mouse system + INT8 PriorityLevel; // Region's Priority, set by system and/or caller + UINT32 uiFlags; // Region's state flags + INT16 RegionTopLeftX; // Screen area affected by this region (absolute coordinates) + INT16 RegionTopLeftY; + INT16 RegionBottomRightX; + INT16 RegionBottomRightY; + INT16 MouseXPos; // Mouse's Coordinates in absolute screen coordinates + INT16 MouseYPos; + INT16 RelativeXPos; // Mouse's Coordinates relative to the Top-Left corner of the region + INT16 RelativeYPos; + UINT16 ButtonState; // Current state of the mouse buttons + INT16 WheelState; // Wheel state +/-number of wheel units + UINT16 Cursor; // Cursor to use when mouse in this region (see flags) MOUSE_CALLBACK MovementCallback; // Pointer to callback function if movement occured in this region - MOUSE_CALLBACK ButtonCallback; // Pointer to callback function if button action occured in this region - INT32 UserData[4]; // User Data, can be set to anything! + MOUSE_CALLBACK ButtonCallback; // Pointer to callback function if button action occured in this region + INT32 UserData[4]; // User Data, can be set to anything! //Fast help vars. INT16 FastHelpTimer; // Countdown timer for FastHelp text @@ -70,28 +71,28 @@ typedef struct _MOUSE_REGION { // ***************************************************************************** // Mouse Region Flags -#define MSYS_NO_FLAGS 0x00000000 -#define MSYS_MOUSE_IN_AREA 0x00000001 -#define MSYS_SET_CURSOR 0x00000002 -#define MSYS_MOVE_CALLBACK 0x00000004 -#define MSYS_BUTTON_CALLBACK 0x00000008 -#define MSYS_REGION_EXISTS 0x00000010 -#define MSYS_SYSTEM_INIT 0x00000020 -#define MSYS_REGION_ENABLED 0x00000040 -#define MSYS_FASTHELP 0x00000080 -#define MSYS_GOT_BACKGROUND 0x00000100 -#define MSYS_HAS_BACKRECT 0x00000200 -#define MSYS_FASTHELP_RESET 0x00000400 +#define MSYS_NO_FLAGS 0x00000000 +#define MSYS_MOUSE_IN_AREA 0x00000001 +#define MSYS_SET_CURSOR 0x00000002 +#define MSYS_MOVE_CALLBACK 0x00000004 +#define MSYS_BUTTON_CALLBACK 0x00000008 +#define MSYS_REGION_EXISTS 0x00000010 +#define MSYS_SYSTEM_INIT 0x00000020 +#define MSYS_REGION_ENABLED 0x00000040 +#define MSYS_FASTHELP 0x00000080 +#define MSYS_GOT_BACKGROUND 0x00000100 +#define MSYS_HAS_BACKRECT 0x00000200 +#define MSYS_FASTHELP_RESET 0x00000400 #define MSYS_ALLOW_DISABLED_FASTHELP 0x00000800 // Mouse region IDs -#define MSYS_ID_BASE 1 -#define MSYS_ID_MAX 0xfffffff // ( INT32 max ) +#define MSYS_ID_BASE 1 +#define MSYS_ID_MAX 0xfffffff // ( INT32 max ) #define MSYS_ID_SYSTEM 0 // Mouse region priorities #define MSYS_PRIORITY_LOWEST 0 -#define MSYS_PRIORITY_LOW 15 +#define MSYS_PRIORITY_LOW 15 #define MSYS_PRIORITY_BASE 31 #define MSYS_PRIORITY_NORMAL 31 #define MSYS_PRIORITY_HIGH 63 @@ -100,20 +101,43 @@ typedef struct _MOUSE_REGION { #define MSYS_PRIORITY_AUTO -1 // Mouse system defines used during updates -#define MSYS_NO_ACTION 0 -#define MSYS_DO_MOVE 1 -#define MSYS_DO_LBUTTON_DWN 2 -#define MSYS_DO_LBUTTON_UP 4 -#define MSYS_DO_RBUTTON_DWN 8 -#define MSYS_DO_RBUTTON_UP 16 +#define MSYS_NO_ACTION 0 +#define MSYS_DO_MOVE 1 +#define MSYS_DO_LBUTTON_DWN 2 +#define MSYS_DO_LBUTTON_UP 4 +#define MSYS_DO_RBUTTON_DWN 8 +#define MSYS_DO_RBUTTON_UP 16 #define MSYS_DO_LBUTTON_REPEAT 32 #define MSYS_DO_RBUTTON_REPEAT 64 +#define MSYS_DO_MBUTTON_DWN 128 +#define MSYS_DO_MBUTTON_UP 256 +#define MSYS_DO_MBUTTON_REPEAT 512 -#define MSYS_DO_BUTTONS (MSYS_DO_LBUTTON_DWN|MSYS_DO_LBUTTON_UP|MSYS_DO_RBUTTON_DWN|MSYS_DO_RBUTTON_UP|MSYS_DO_RBUTTON_REPEAT|MSYS_DO_LBUTTON_REPEAT) +#define MSYS_DO_X1BUTTON_DWN 1024 +#define MSYS_DO_X1BUTTON_UP 2048 +#define MSYS_DO_X1BUTTON_REPEAT 4096 +#define MSYS_DO_X2BUTTON_DWN 8192 +#define MSYS_DO_X2BUTTON_UP 16384 +#define MSYS_DO_X2BUTTON_REPEAT 32768 + +#define MSYS_DO_WHEEL_UP 65536 +#define MSYS_DO_WHEEL_DOWN 131072 + +#define MSYS_DO_BUTTONS (MSYS_DO_LBUTTON_DWN|MSYS_DO_LBUTTON_UP|MSYS_DO_LBUTTON_REPEAT|\ + MSYS_DO_RBUTTON_DWN|MSYS_DO_RBUTTON_UP|MSYS_DO_RBUTTON_REPEAT|\ + MSYS_DO_MBUTTON_DWN|MSYS_DO_MBUTTON_UP|MSYS_DO_MBUTTON_REPEAT|\ + MSYS_DO_X1BUTTON_DWN|MSYS_DO_X1BUTTON_UP|MSYS_DO_X1BUTTON_REPEAT|\ + MSYS_DO_X2BUTTON_DWN|MSYS_DO_X2BUTTON_UP|MSYS_DO_X2BUTTON_REPEAT) + +#define MSYS_DO_WHEEL (MSYS_DO_WHEEL_UP|MSYS_DO_WHEEL_DOWN) +//#define MSYS_DO_BUTTONS (MSYS_DO_LBUTTON_DWN|MSYS_DO_LBUTTON_UP|MSYS_DO_RBUTTON_DWN|MSYS_DO_RBUTTON_UP|MSYS_DO_RBUTTON_REPEAT|MSYS_DO_LBUTTON_REPEAT) // Mouse system button masks -#define MSYS_LEFT_BUTTON 1 -#define MSYS_RIGHT_BUTTON 2 +#define MSYS_LEFT_BUTTON 1 +#define MSYS_RIGHT_BUTTON 2 +#define MSYS_MIDDLE_BUTTON 4 +#define MSYS_X1_BUTTON 8 +#define MSYS_X2_BUTTON 16 // Mouse system special values #define MSYS_NO_CALLBACK NULL @@ -127,8 +151,8 @@ typedef struct _MOUSE_REGION { #define MSYS_CALLBACK_REASON_LBUTTON_UP 8 #define MSYS_CALLBACK_REASON_RBUTTON_DWN 16 #define MSYS_CALLBACK_REASON_RBUTTON_UP 32 -#define MSYS_CALLBACK_REASON_BUTTONS (MSYS_CALLBACK_REASON_LBUTTON_DWN|MSYS_CALLBACK_REASON_LBUTTON_UP| \ - MSYS_CALLBACK_REASON_RBUTTON_DWN|MSYS_CALLBACK_REASON_RBUTTON_UP) +//#define MSYS_CALLBACK_REASON_BUTTONS (MSYS_CALLBACK_REASON_LBUTTON_DWN|MSYS_CALLBACK_REASON_LBUTTON_UP| \ +// MSYS_CALLBACK_REASON_RBUTTON_DWN|MSYS_CALLBACK_REASON_RBUTTON_UP) #define MSYS_CALLBACK_REASON_LOST_MOUSE 64 #define MSYS_CALLBACK_REASON_GAIN_MOUSE 128 @@ -142,6 +166,26 @@ typedef struct _MOUSE_REGION { //supports double clicks and single clicks, make sure the DOUBLECLICK event is checked first (rejecting //the LBUTTON_DWN event if detected) #define MSYS_CALLBACK_REASON_LBUTTON_DOUBLECLICK 1024 +#define MSYS_CALLBACK_REASON_MBUTTON_DWN 2048 +#define MSYS_CALLBACK_REASON_MBUTTON_UP 4096 +#define MSYS_CALLBACK_REASON_MBUTTON_REPEAT 8192 +#define MSYS_CALLBACK_REASON_WHEEL_UP 16384 +#define MSYS_CALLBACK_REASON_WHEEL_DOWN 32768 +#define MSYS_CALLBACK_REASON_X1BUTTON_DWN 65536 +#define MSYS_CALLBACK_REASON_X1BUTTON_UP 131072 +#define MSYS_CALLBACK_REASON_X1BUTTON_REPEAT 262144 +#define MSYS_CALLBACK_REASON_X2BUTTON_DWN 524288 +#define MSYS_CALLBACK_REASON_X2BUTTON_UP 1048576 +#define MSYS_CALLBACK_REASON_X2BUTTON_REPEAT 2097152 + + +#define MSYS_CALLBACK_REASON_BUTTONS (MSYS_CALLBACK_REASON_LBUTTON_DWN|MSYS_CALLBACK_REASON_LBUTTON_UP| \ + MSYS_CALLBACK_REASON_RBUTTON_DWN|MSYS_CALLBACK_REASON_RBUTTON_UP| \ + MSYS_CALLBACK_REASON_MBUTTON_DWN|MSYS_CALLBACK_REASON_MBUTTON_UP|\ + MSYS_CALLBACK_REASON_X1BUTTON_DWN|MSYS_CALLBACK_REASON_X1BUTTON_UP|\ + MSYS_CALLBACK_REASON_X2BUTTON_DWN|MSYS_CALLBACK_REASON_X2BUTTON_UP) + +#define MSYS_CALLBACK_REASON_WHEEL (MSYS_CALLBACK_REASON_WHEEL_UP|MSYS_CALLBACK_REASON_WHEEL_DOWN) // Mouse grabbing return codes @@ -217,7 +261,7 @@ void EnableMouseFastHelp( void ); void DisableMouseFastHelp( void ); void ResetClickedMode(void); - +void ResetWheelState( MOUSE_REGION *region ); #ifdef _JA2_RENDER_DIRTY BOOLEAN SetRegionSavedRect( MOUSE_REGION *region); diff --git a/Standard Gaming Platform/radbase.h b/Standard Gaming Platform/radbase.h new file mode 100644 index 00000000..39a62353 --- /dev/null +++ b/Standard Gaming Platform/radbase.h @@ -0,0 +1,369 @@ +// __RAD16__ means 16 bit code (Win16) +// __RAD32__ means 32 bit code (DOS, Win386, Win32s, Mac) + +// __RADDOS__ means DOS code (16 or 32 bit) +// __RADWIN__ means Windows code (Win16, Win386, Win32s) +// __RADWINEXT__ means Windows 386 extender (Win386) +// __RADNT__ means Win32s code +// __RADMAC__ means Macintosh +// __RADXBOX__ means the XBox console +// __RADNGC__ means the Nintendo GameCube + +// __RADX86__ means Intel x86 +// __RADMMX__ means Intel x86 MMX instructions are allowed +// __RAD68K__ means 68K +// __RADPPC__ means PowerPC + +// __RADLITTLEENDIAN__ means processor is little-endian (x86) +// __RADBIGENDIAN__ means processor is big-endian (680x0, PPC) + +#ifndef __RADBASEH__ +#define __RADBASEH__ + +#if defined(GEKKO) + + #define __RADNGC__ + #define __RAD32__ + #define __RADPPC__ + #define __RADBIGENDIAN__ + #define RADINLINE inline + +#elif (defined(__MWERKS__) && !defined(__INTEL__)) || defined(__MRC__) || defined(THINK_C) || defined(powerc) || defined(macintosh) || defined(__powerc) + + #define __RADMAC__ + #if defined(powerc) || defined(__powerc) + #define __RADPPC__ + #else + #define __RAD68K__ + #endif + + #define __RAD32__ + #define __RADBIGENDIAN__ + + #if defined(__MWERKS__) + #if (defined(__cplusplus) || ! __option(only_std_keywords)) + #define RADINLINE inline + #endif + #elif defined(__MRC__) + #if defined(__cplusplus) + #define RADINLINE inline + #endif + #endif + +#else + + #define __RADX86__ + #define __RADMMX__ + + #ifdef __MWERKS__ + #define _WIN32 + #endif + + #ifdef __DOS__ + #define __RADDOS__ + #endif + + #ifdef __386__ + #define __RAD32__ + #endif + + #ifdef _Windows //For Borland + #ifdef __WIN32__ + #define WIN32 + #else + #define __WINDOWS__ + #endif + #endif + + #ifdef _WINDOWS //For MS + #ifndef _WIN32 + #define __WINDOWS__ + #endif + #endif + + #ifdef _WIN32 + #ifdef _XBOX + #define __RADXBOX__ + #else + #define __RADNT__ + #endif + #define __RADWIN__ + #define __RAD32__ + #else + #ifdef __NT__ + #ifdef _XBOX + #define __RADXBOX__ + #else + #define __RADNT__ + #endif + #define __RADWIN__ + #define __RAD32__ + #else + #ifdef __WINDOWS_386__ + #define __RADWIN__ + #define __RADWINEXT__ + #define __RAD32__ + #else + #ifdef __WINDOWS__ + #define __RADWIN__ + #define __RAD16__ + #else + #ifdef WIN32 + #ifdef _XBOX + #define __RADXBOX__ + #else + #define __RADNT__ + #endif + #define __RADWIN__ + #define __RAD32__ + #endif + #endif + #endif + #endif + #endif + + #define __RADLITTLEENDIAN__ + #define RADINLINE __inline +#endif + +#if (!defined(__RADDOS__) && !defined(__RADWIN__) && !defined(__RADMAC__) && !defined(__RADNGC__) && !defined(__RADXBOX__)) + #error "RAD.H did not detect your platform. Define __DOS__, __WINDOWS__, WIN32, macintosh, or powerc." +#endif + +#ifdef __RADFINAL__ +#define RADTODO(str) { char __str[0]=str; } +#else +#define RADTODO(str) +#endif + +#ifdef __RADNGC__ + + #define RADLINK + #define RADEXPLINK + #define RADEXPFUNC RADDEFFUNC + #define RADASMLINK + #define PTR4 + +#elif defined(__RADMAC__) + + // this define is for CodeWarrior 11's stupid new libs (even though + // we don't use longlong's). + + #define __MSL_LONGLONG_SUPPORT__ + + #define RADLINK + #define RADEXPLINK + + #ifdef __CFM68K__ + #ifdef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(export) + #else + #define RADEXPFUNC RADDEFFUNC __declspec(import) + #endif + #else + #define RADEXPFUNC RADDEFFUNC + #endif + #define RADASMLINK + +#else + + #ifdef __RADNT__ + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #endif + + #ifdef __RADWIN__ + #ifdef __RAD32__ + #ifdef __RADXBOX__ + + #define RADLINK __stdcall + #define RADEXPLINK __stdcall + #define RADEXPFUNC RADDEFFUNC + + #else + #ifdef __RADNT__ + + #define RADLINK __stdcall + #define RADEXPLINK __stdcall + + #ifdef __RADINEXE__ + #define RADEXPFUNC RADDEFFUNC + #else + #ifndef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(dllimport) + #ifdef __BORLANDC__ + #if __BORLANDC__<=0x460 + #undef RADEXPFUNC + #define RADEXPFUNC RADDEFFUNC + #endif + #endif + #else + #define RADEXPFUNC RADDEFFUNC __declspec(dllexport) + #endif + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal __export + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + + #define RADASMLINK __cdecl + +#endif + +#ifndef __RADXBOX__ + #ifdef __RADWIN__ + #ifndef _WINDOWS + #define _WINDOWS + #endif + #endif +#endif + +#ifndef RADDEFFUNC + +#ifdef __cplusplus + #define RADDEFFUNC extern "C" + #define RADDEFSTART extern "C" { + #define RADDEFEND } + #define RADDEFINEDATA extern "C" + #define RADDECLAREDATA extern "C" + #define RADDEFAULT( val ) =val +#else + #define RADDEFFUNC + #define RADDEFSTART + #define RADDEFEND + #define RADDEFINEDATA + #define RADDECLAREDATA extern + #define RADDEFAULT( val ) +#endif + +#endif + +#ifdef __RADNGC__ + #define RAD_ATTRIBUTE_ALIGN(num) __attribute__ ((aligned (num))) +#else + #ifdef __RADX86__ + #define RAD_ATTRIBUTE_ALIGN(num) __declspec(align(num)) + #else + #define RAD_ATTRIBUTE_ALIGN(num) + #endif +#endif + +#ifdef __RADX86__ + #ifdef __WATCOMC__ + #define RAD_ALIGN_TYPE double + #define RAD_ALIGN_DEF 0.0 + #else + #define RAD_ALIGN_TYPE double __declspec(align(8)) + #define RAD_ALIGN_DEF 0.0 + #endif +#else + #define RAD_ALIGN_TYPE double + #define RAD_ALIGN_DEF 0.0 +#endif + +#define RAD_ALIGN_ADD_TYPE(var) RAD_ALIGN_TYPE var##align = RAD_ALIGN_DEF + +#define S8 signed char +#define U8 unsigned char +#define U32 unsigned long +#define S32 signed long +#define F32 float +#define F64 double + +#if defined(__MWERKS__) || defined(__MRC__) || defined( GEKKO ) + #define U64 unsigned long long + #define S64 signed long long +#else + #define U64 unsigned __int64 + #define S64 signed __int64 +#endif + +#ifdef __RAD32__ + #define PTR4 + #define U16 unsigned short + #define S16 signed short +#else + #define PTR4 __far + #define U16 unsigned int + #define S16 signed int +#endif + +#ifndef RAD_NO_LOWERCASE_TYPES + +#ifdef __RADNGC__ + + // Unfortunately dolphin\types.h typedefs the + // same types that we use. + // So we use the typedefs for this platform. + + #include + +#else + +#ifndef u8 + #define u8 U8 +#endif +#ifndef s8 + #define s8 S8 +#endif +#ifndef u16 + #define u16 U16 +#endif +#ifndef s16 + #define s16 S16 +#endif +#ifndef u32 + #define u32 U32 +#endif +#ifndef s32 + #define s32 S32 +#endif +#ifndef u64 + #define u64 U64 +#endif +#ifndef s64 + #define s64 S64 +#endif +#ifndef f32 + #define f32 F32 +#endif +#ifndef f64 + #define f64 F64 +#endif + +#endif + +#endif + +#ifndef radassert + #if defined(_DEBUG) && !defined(NDEBUG) + #ifdef __RADNGC__ + #define radassert( cond ) { if (!(cond)) { OSReport("Assert: %s File: %s Line %i\n",#cond,__FILE__, __LINE__); BreakPoint(); } } + #else + #define radassert( cond ) { if (!(cond)) BreakPoint(); } + #endif + #else + #define radassert( cond ) + #endif +#endif + +typedef void PTR4* (RADLINK PTR4* RADMEMALLOC) (U32 bytes); +typedef void (RADLINK PTR4* RADMEMFREE) (void PTR4* ptr); + +#endif diff --git a/Standard Gaming Platform/sgp.cpp b/Standard Gaming Platform/sgp.cpp index 5f7b3e3a..f1edaa0a 100644 --- a/Standard Gaming Platform/sgp.cpp +++ b/Standard Gaming Platform/sgp.cpp @@ -37,15 +37,20 @@ #include "input.h" #include "zmouse.h" -#include "VFS/vfs.h" -#include "VFS/vfs_init.h" -#include "VFS/File/vfs_file.h" -#include "VFS/Location/vfs_slf_library.h" -#include "VFS/Tools/Log.h" -#include "VFS/Tools/ParserTools.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sgp_logger.h" #include "Text.h" -#include "VFS/os_functions.h" -#include "VFS/vfs_settings.h" +#include "LocalizedStrings.h" +#include "ExportStrings.h" +#include "ImportStrings.h" #define USE_CONSOLE 0 @@ -79,17 +84,53 @@ static std::list vfs_config_ini; static bool s_DebugKeyboardInput = false; static vfs::Path s_CodePage; -void SHOWEXCEPTION(CBasicException& ex) +static vfs::FileLogger *vfslog = NULL; + +void SHOWEXCEPTION(sgp::Exception& ex) { try { _ExceptionMessage(ex); } - catch(CBasicException &ex2) { - logException(ex2); + catch(sgp::Exception &ex2) { + SGP_ERROR(ex2.what()); exit(0); } } +void SHOWEXCEPTION(vfs::Exception& ex) +{ + try { + _ExceptionMessage(ex); + } + catch(vfs::Exception &ex2) { + SGP_ERROR(ex2.what()); + exit(0); + } +} + +#define HANDLE_FATAL_ERROR \ + catch(sgp::Exception &ex){ \ + SGP_ERROR(ex.what()); \ + FatalError((const STR8)ex.what()); \ + exit(0); } \ + catch(vfs::Exception &ex){ \ + SGP_ERROR(ex.what()); \ + FatalError((const STR8)ex.getExceptionString().utf8().c_str()); \ + exit(0); } \ + catch(std::exception &ex){ \ + SGP_ERROR(ex.what()); \ + FatalError((const STR8)ex.what()); \ + exit(0); } \ + catch(const char* msg){ \ + SGP_ERROR(msg); \ + FatalError((const STR8)msg); \ + exit(0); } \ + catch(...){ \ + SGP_ERROR("Caught undefined exception"); \ + FatalError("Caught undefined exception"); \ + exit(0); } + + extern UINT32 MemDebugCounter; #ifdef JA2 extern BOOLEAN gfPauseDueToPlayerGamePause; @@ -159,6 +200,15 @@ BOOLEAN gfIgnoreMessages=FALSE; // GLOBAL VARIBLE, SET TO DEFAULT BUT CAN BE CHANGED BY THE GAME IF INIT FILE READ UINT8 gbPixelDepth = PIXEL_DEPTH; +bool s_bExportStrings = false; +extern bool g_bUseXML_Strings;// = false; +bool g_bUseXML_Structures = false; +bool g_bUseXML_Tilesets = false; + +#ifdef USE_VFS +static vfs::Path sp_force_load_jsd_xml_file; +#endif + INT32 FAR PASCAL WindowProcedure(HWND hWindow, UINT16 Message, WPARAM wParam, LPARAM lParam) { static BOOLEAN fRestore = FALSE; @@ -174,11 +224,14 @@ INT32 FAR PASCAL WindowProcedure(HWND hWindow, UINT16 Message, WPARAM wParam, LP return(DefWindowProc(hWindow, Message, wParam, lParam)); // ATE: This is for older win95 or NT 3.51 to get MOUSE_WHEEL Messages - if ( Message == guiMouseWheelMsg ) - { - QueueEvent(MOUSE_WHEEL, wParam, lParam); - return( 0L ); - } + //if ( Message == guiMouseWheelMsg ) + //{ + // QueueEvent(MOUSE_WHEEL, wParam, lParam); + // return( 0L ); + //} + + + switch(Message) { @@ -186,11 +239,11 @@ INT32 FAR PASCAL WindowProcedure(HWND hWindow, UINT16 Message, WPARAM wParam, LP PostQuitMessage(0); break; /*dnl kick this out, because in input.sgp MouseHandler() hook has priority so it will process same event twice, someone force MouseHandler() hook to always return unhandled events status so what ever mouse event you process in WindowProcedure() be aware that this event is already occur in MouseHandler() (mouse clicks, move etc.) Probably this is done because when you lost focus even if you click back on window region this will not restore them, so need condition in MouseHandler to restore window focus - case WM_MOUSEWHEEL: - { - QueueEvent(MOUSE_WHEEL, wParam, lParam); - break; - } +// case WM_MOUSEWHEEL: +// { +// QueueEvent(MOUSE_WHEEL, wParam, lParam); +// break; +// } */ #ifdef JA2 case WM_MOVE: @@ -526,9 +579,9 @@ INT32 FAR PASCAL WindowProcedure(HWND hWindow, UINT16 Message, WPARAM wParam, LP #ifdef USE_CODE_PAGE if(s_DebugKeyboardInput) { - static CLog& debugKeys = *CLog::Create(L"DebugKeys.txt"); + static vfs::Log& debugKeys = *vfs::Log::Create(L"DebugKeys.txt"); static int input_counter = 1; - debugKeys << (input_counter++) << " : " << (int)wParam << CLog::endl; + debugKeys << (input_counter++) << " : " << (int)wParam << vfs::Log::endl; } #endif // USE_CODE_PAGE KeyDown(wParam, lParam); @@ -594,32 +647,7 @@ BOOLEAN InitializeStandardGamingPlatform(HINSTANCE hInstance, int sCommandShow) #endif // Second, read in settings - std::list exlist; - try - { - GetRuntimeSettings( ); - } - catch(CBasicException& ex) - { - logException(ex); - // nothing is set up, no vfs, no video manager - // regular error processing wouldn't work here - // set default values and continue as if nothing has happened - iResolution = 1; - - gbPixelDepth = PIXEL_DEPTH; - - SCREEN_WIDTH = 800; - SCREEN_HEIGHT = 600; - - iScreenWidthOffset = (SCREEN_WIDTH - 640) / 2; - iScreenHeightOffset = (SCREEN_HEIGHT - 480) / 2; - - iScreenMode = 1; - iPlayIntro = 0; - // rethrow exception after full setup - exlist.push_back(ex); - } + GetRuntimeSettings( ); // Initialize the Debug Manager - success doesn't matter InitializeDebugManager(); @@ -698,13 +726,14 @@ BOOLEAN InitializeStandardGamingPlatform(HINSTANCE hInstance, int sCommandShow) //InitializeJA2TimerID(); #ifdef USE_VFS - vfs::Path exe_dir, exe_file; - os::getExecutablePath(exe_dir, exe_file); + //vfs::Path exe_dir, exe_file; + //os::getExecutablePath(exe_dir, exe_file); - // set current directory to exe's directory - os::setCurrectDirectory(exe_dir); + //// set current directory to exe's directory + //os::setCurrectDirectory(exe_dir); + + SGP_THROW_IFFALSE( vfs_init::initVirtualFileSystem( vfs_config_ini ), L"Initializing Virtual File System failed"); - THROWIFFALSE( initVirtualFileSystem( vfs_config_ini ), L"Initializing Virtual File System failed"); s_VfsIsInitialized = true; @@ -713,6 +742,19 @@ BOOLEAN InitializeStandardGamingPlatform(HINSTANCE hInstance, int sCommandShow) getVFS()->getVirtualLocation(vfs::Path(pMessageStrings[MSG_SAVEDIRECTORY]+3),true)->setIsExclusive(true); getVFS()->getVirtualLocation(vfs::Path(pMessageStrings[MSG_MPSAVEDIRECTORY]+3),true)->setIsExclusive(true); + if(!sp_force_load_jsd_xml_file.empty()) + { + try + { + std::string filename = vfs::String::as_utf8(sp_force_load_jsd_xml_file()); + STRUCTURE_FILE_REF *pStructureFileRef = LoadStructureFile((STR8)filename.c_str()); + } + catch(std::exception &ex) + { + SGP_RETHROW(_BS(L"failed to load and/or process file : ") << sp_force_load_jsd_xml_file << _BS::wget, ex); + } + } + #ifdef USE_CODE_PAGE charSet::InitializeCharSets(); @@ -723,11 +765,11 @@ BOOLEAN InitializeStandardGamingPlatform(HINSTANCE hInstance, int sCommandShow) CodePageReader cpr; cpr.ReadCodePage(s_CodePage); } - catch(CBasicException& ex) + catch(std::exception& ex) { std::wstringstream wss; wss << L"Could not process codepage file \"" << s_CodePage() << L"\""; - RETHROWEXCEPTION(wss.str().c_str(), &ex); + SGP_RETHROW(wss.str().c_str(), ex); } } #endif // USE_CODE_PAGE @@ -762,6 +804,16 @@ BOOLEAN InitializeStandardGamingPlatform(HINSTANCE hInstance, int sCommandShow) gCustomDataCat.NewCat(std::string(CurrentDir) + '\\' + customDataPath); } #endif + + if(g_bUseXML_Strings) + { + if(s_bExportStrings) + { + Loc::ExportStrings(); + } + Loc::ImportStrings(); + } + //#ifdef JA2 InitJA2SplashScreen(); //#endif @@ -813,10 +865,6 @@ BOOLEAN InitializeStandardGamingPlatform(HINSTANCE hInstance, int sCommandShow) gfGameInitialized = TRUE; - if(!exlist.empty()) - { - RETHROWEXCEPTION(L"Error during reading runtime settings", &exlist.front()); - } return TRUE; } @@ -893,17 +941,19 @@ void ShutdownStandardGamingPlatform(void) ShutdownDebugManager(); - CLog::flushFinally(); + sgp::Logger::instance().shutdown(); + vfs::Log::flushDeleteAll(); + if(vfslog) delete vfslog; vfs::CVirtualFileSystem::shutdownVFS(); - CFileAllocator::clear(); + vfs::ObjectAllocator::clear(); } #ifdef USE_VFS #include "MPJoinScreen.h" -utf8string getGameID() +vfs::String getGameID() { - static utf8string _id; + static vfs::String _id; static bool has_id = false; if(!has_id) { @@ -914,6 +964,58 @@ utf8string getGameID() } #endif +#include "debug_util.h" +#include + +class VfsLogAdapter : public vfs::Aspects::ILogger +{ +public: + VfsLogAdapter(sgp::Logger_ID ID, bool stacktrace = false) : _id(ID), _trace(stacktrace) {}; + + virtual void Msg(const wchar_t* msg) + { + SGP_LOG(_id, msg); + if(_trace) + { + sgp::dumpStackTrace(msg); + } + } + virtual void Msg(const char* msg) + { + SGP_LOG(_id, msg); + if(_trace) + { + sgp::dumpStackTrace(msg); + } + } +private: + sgp::Logger_ID _id; + bool _trace; +}; + +//#include +//#include "sgp_mutex.h" +//class VfsMutex : public vfs::Aspects::IMutex +//{ +//public: +// virtual void lock(){ +// _mutex.lock(); +// } +// virtual void unlock(){ +// _mutex.unlock(); +// } +//private: +// sgp::Mutex _mutex; +//}; +//class VfsMutexFactory : public vfs::Aspects::IMutexFactory +//{ +//public: +// virtual vfs::Aspects::IMutex* createMutex() +// { +// return new VfsMutex(); +// } +//}; + int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCommandLine, int sCommandShow) { @@ -951,6 +1053,22 @@ int PASCAL HandledWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pC HWND hPrevInstanceWindow; UINT32 uiTimer = 0; +#ifdef USE_VFS + vfs::Log::setSharedString( getGameID() ); +#endif + //if(!vfs::Aspects::getMutexFactory()) + //{ + // vfs::Aspects::setMutexFactory( new VfsMutexFactory() ); + //} + sgp::Logger_ID VFS_LOG = sgp::Logger::instance().createLogger(); + + sgp::Logger::instance().connectFile(VFS_LOG, L"vfs.log", false, sgp::Logger::FLUSH_ON_DELETE); + + VfsLogAdapter* vfslog = new VfsLogAdapter(VFS_LOG, false); + VfsLogAdapter* vfslog_error = new VfsLogAdapter(VFS_LOG, true); + + vfs::Aspects::setLogger(vfslog, vfslog, vfslog_error, NULL /* vfslog */); + // Make sure that only one instance of this application is running at once // // Look for prev instance by searching for the window hPrevInstanceWindow = FindWindowEx( NULL, NULL, APPLICATION_NAME, APPLICATION_NAME ); @@ -967,10 +1085,6 @@ int PASCAL HandledWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pC // Initialize random number generator InitializeRandom(); // no Shutdown -#ifdef USE_VFS - CLog::setSharedString( getGameID() ); -#endif - //rain //NSLoadSettings(); //NSSaveSettings(); @@ -1029,9 +1143,9 @@ int PASCAL HandledWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pC // ShowCursor(FALSE); #ifdef USE_VFS - vfs::Path exe_dir, exe_file; - os::getExecutablePath(exe_dir, exe_file); - os::setCurrectDirectory(exe_dir); + //vfs::Path exe_dir, exe_file; + //os::getExecutablePath(exe_dir, exe_file); + //os::setCurrectDirectory(exe_dir); #else STRING512 sExecutableDir; GetExecutableDirectory( sExecutableDir ); @@ -1046,65 +1160,11 @@ int PASCAL HandledWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pC return 0; } } - catch(CBasicException &ex) - { - if(!s_VfsIsInitialized) - { - vfs::CFile* fonts = new vfs::CFile("Data/Fonts.slf"); - vfs::CSLFLibrary* slfLib = new vfs::CSLFLibrary(vfs::tReadableFile::cast(fonts),""); - if(slfLib->init()) - { - getVFS()->addLocation(slfLib,"doesn't matter"); - } - // fonts not initialized - FontTranslationTable *pFontTable = CreateEnglishTransTable( ); - if ( pFontTable == NULL ) - { - return( FALSE ); - } + HANDLE_FATAL_ERROR; - // Initialize Font Manager - FastDebugMsg("Initializing the Font Manager"); - // Init the manager and copy the TransTable stuff into it. - if ( !InitializeFontManager( 8, pFontTable ) ) - { - FastDebugMsg("FAILED : Initializing Font Manager"); - return FALSE; - } - // Don't need this thing anymore, so get rid of it (but don't de-alloc the contents) - MemFree( pFontTable ); - if ( !InitializeFonts( ) ) - { - // Send debug message and quit - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "COULD NOT INUT FONT SYSTEM..."); - return( ERROR_SCREEN ); - } - } - gfProgramIsRunning = 1; - logException(ex); - SHOWEXCEPTION(ex); - } - catch(std::exception &ex) - { - gfProgramIsRunning = 1; - CBasicException nex(ex.what(),_FUNCTION_FORMAT_,__LINE__,__FILE__); - logException(nex); - SHOWEXCEPTION(nex); - } - catch(const char* msg) - { - gfProgramIsRunning = 1; - CBasicException ex(msg,_FUNCTION_FORMAT_,__LINE__,__FILE__); - logException(ex); - SHOWEXCEPTION(ex); - } - catch(...) - { - gfProgramIsRunning = 1; - CBasicException ex("Caught undefined exception", _FUNCTION_FORMAT_, __LINE__, __FILE__); - logException( ex ); - SHOWEXCEPTION(ex); - } +#ifdef USE_VFS + vfs::Log::flushReleaseAll(); +#endif #ifdef LUACONSOLE if (1==iScreenMode) @@ -1114,9 +1174,13 @@ int PASCAL HandledWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pC #endif #ifdef JA2 - #ifdef ENGLISH +# ifdef ENGLISH + try + { SetIntroType( INTRO_SPLASH ); - #endif + } + HANDLE_FATAL_ERROR; +# endif #endif gfApplicationActive = TRUE; @@ -1146,27 +1210,32 @@ int PASCAL HandledWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pC DispatchMessage(&Message); } } - catch(CBasicException &ex) + catch(sgp::Exception &ex) { - logException(ex); + SGP_ERROR(ex.what()); + SHOWEXCEPTION(ex); + } + catch(vfs::Exception &ex) + { + SGP_ERROR(ex.what()); SHOWEXCEPTION(ex); } catch(std::exception &ex) { - CBasicException nex(ex.what(),_FUNCTION_FORMAT_,__LINE__,__FILE__); - logException(nex); + sgp::Exception nex(ex.what()); + SGP_ERROR(nex.what()); SHOWEXCEPTION(nex); } catch(const char* msg) { - CBasicException ex(msg,_FUNCTION_FORMAT_,__LINE__,__FILE__); - logException(ex); + sgp::Exception ex(msg); + SGP_ERROR(ex.what()); SHOWEXCEPTION(ex); } catch(...) { - CBasicException ex("Caught undefined exception", _FUNCTION_FORMAT_, __LINE__, __FILE__); - logException( ex ); + sgp::Exception ex("Caught undefined exception"); + SGP_ERROR( ex.what() ); SHOWEXCEPTION(ex); } @@ -1262,7 +1331,7 @@ void GetRuntimeSettings( ) strcat(INIFile, "\\Ja2.ini"); #else - CPropertyContainer oProps; + vfs::PropertyContainer oProps; oProps.initFromIniFile("Ja2.ini"); #endif iResolution = -1; @@ -1272,24 +1341,24 @@ void GetRuntimeSettings( ) iResolution = atoi(zScreenResolution); } #else - utf8string loc = oProps.getStringProperty("Ja2 Settings", L"LOCALE"); + vfs::String loc = oProps.getStringProperty("Ja2 Settings", L"LOCALE"); if(!loc.empty()) { - THROWIFFALSE( setlocale(LC_ALL, loc.utf8().c_str()), BuildString().add(L"invalid locale : ").add(loc).get()); + SGP_THROW_IFFALSE( setlocale(LC_ALL, loc.utf8().c_str()), _BS(L"invalid locale : ") << loc << _BS::wget ); } iResolution = (int)oProps.getIntProperty(L"Ja2 Settings", L"SCREEN_RESOLUTION", -1); vfs::Settings::setUseUnicode( !oProps.getBoolProperty(L"Ja2 Settings", L"VFS_NO_UNICODE", false) ); - std::list ini_list; + std::list ini_list; - utf8string vfs_config_file; + vfs::String vfs_config_file; if(oProps.getStringProperty(L"Ja2 Settings", L"VFS_CONFIG", vfs_config_file)) { - CPropertyContainer temp_cont; + vfs::PropertyContainer temp_cont; temp_cont.initFromIniFile(vfs_config_file); - utf8string temp_str; + vfs::String temp_str; if(temp_cont.getStringProperty(L"vfs_config", L"VFS_CONFIG_INI", temp_str)) { oProps.setStringProperty(L"Ja2 Settings", L"VFS_CONFIG_INI", temp_str); @@ -1298,7 +1367,7 @@ void GetRuntimeSettings( ) if(oProps.getStringListProperty(L"Ja2 Settings", L"VFS_CONFIG_INI", ini_list, L"")) { vfs_config_ini.clear(); - for(std::list::iterator it = ini_list.begin(); it != ini_list.end(); ++it) + for(std::list::iterator it = ini_list.begin(); it != ini_list.end(); ++it) { vfs_config_ini.push_back(*it); } @@ -1307,6 +1376,25 @@ void GetRuntimeSettings( ) { vfs_config_ini.push_back(L"vfs_config.ini"); } + std::list merge_list; + if(oProps.getStringListProperty(L"Ja2 Settings", L"MERGE_INI_FILES", merge_list, L"")) + { + for(std::list::iterator it = merge_list.begin(); it != merge_list.end(); ++it) + { + CIniReader::RegisterFileForMerging(*it); + } + } +#endif + +#ifdef USE_VFS + extern bool g_bUsePngItemImages; + g_bUsePngItemImages = oProps.getBoolProperty(L"Ja2 Settings", L"USE_PNG_ITEM_IMAGES", false); + g_bUseXML_Structures = oProps.getBoolProperty(L"Ja2 Settings", L"USE_XML_STRUCTURES", false); + g_bUseXML_Tilesets = oProps.getBoolProperty(L"Ja2 Settings", L"USE_XML_TILESETS", false); + g_bUseXML_Strings = oProps.getBoolProperty(L"Ja2 Settings", L"USE_XML_STRINGS", false); + s_bExportStrings = oProps.getBoolProperty(L"Ja2 Settings", L"EXPORT_STRINGS", false); + + sp_force_load_jsd_xml_file = oProps.getStringProperty(L"Ja2 Settings", L"FORCE_LOAD_JSD_XML_FILE", L""); #endif #ifdef JA2EDITOR @@ -1320,11 +1408,6 @@ void GetRuntimeSettings( ) #endif #endif -#ifdef USE_VFS - extern bool g_bUsePngItemImages; - g_bUsePngItemImages = oProps.getBoolProperty(L"Ja2 Settings", "USE_PNG_ITEM_IMAGES", false); -#endif - int iResX; int iResY; diff --git a/Standard Gaming Platform/sgp_auto_memory.h b/Standard Gaming Platform/sgp_auto_memory.h new file mode 100644 index 00000000..08c63495 --- /dev/null +++ b/Standard Gaming Platform/sgp_auto_memory.h @@ -0,0 +1,113 @@ +#ifndef _SGP_AUTO_MEMORY_H_ +#define _SGP_AUTO_MEMORY_H_ + +namespace sgp +{ + /************************************************************/ + + template + class TAutoArray + { + public: + T& operator[](size_t index) + { + return _array[index]; + } + + T* operator()() + { + return _array; + } + T* operator->() + { + return _array; + } + T& operator*() + { + return *_array; + } + bool operator!() + { + // NULL == _array + return !_array; + } + + T* release() + { + T* tmp = _array; + _array = NULL; + return tmp; + } + protected: + T* _array; + }; + + /************************************************************/ + + template + class AutoArray : public TAutoArray + { + public: + AutoArray(size_t size) + { + _array = new T[size]; + } + ~AutoArray() + { + if(_array) + { + delete[] _array; + } + } + }; + + /************************************************************/ + + template + class AutoCArray : public TAutoArray + { + public: + AutoCArray(size_t size = 1, size_t sizeof_elem=1) + { + _array = (T*)Alloc( size * sizeof_elem ); + } + ~AutoCArray() + { + if(_array) + { + Dealloc(_array); + } + } + }; + + /************************************************************/ + +} // namespace sgp + +#ifdef JA2 + +#include "MemMan.h" + +namespace sgp +{ + template + class AutoMMArray : public sgp::TAutoArray + { + public: + AutoMMArray(size_t size, size_t sizeof_elem=1) + { + _array = (T*)MemAlloc( size * sizeof_elem ); + } + ~AutoMMArray() + { + if(_array) + { + MemFree(_array); + } + } + }; +} + +#endif + +#endif // _SGP_AUTO_MEMORY_H_ diff --git a/Standard Gaming Platform/sgp_logger.cpp b/Standard Gaming Platform/sgp_logger.cpp new file mode 100644 index 00000000..54772eba --- /dev/null +++ b/Standard Gaming Platform/sgp_logger.cpp @@ -0,0 +1,270 @@ +#include "sgp_logger.h" +#include "Debug.h" +#include "Font Control.h" + +#include "Message.h" +#include + +static inline void flush_screen(std::wstringstream& stream) +{ + std::wstring str = stream.str(); + if(!str.empty()) + { + ScreenMsg(MSG_FONT_YELLOW, 255, (STR16)str.c_str()); + } +} + +int sgp::Logger::_next_log_id = -1; + +#if defined(USE_VFS) + //std::vector sgp::Logger::_logs; + std::vector sgp::Logger::_logs; +#endif + +sgp::Logger::Logger() +{ +#if defined(USE_VFS) + connectFile(this->createLogger(), L"game_log.log", false, sgp::Logger::FLUSH_ON_ENDL); +#endif +} + +sgp::Logger::~Logger() +{ +} + +sgp::Logger& sgp::Logger::instance() +{ + static Logger _logger; + return _logger; +} + +bool sgp::Logger::init() +{ + return true; +} + +bool sgp::Logger::shutdown() +{ + for(::size_t i=0; i < _logs.size(); ++i) + { +#if defined(USE_VFS) + disconnectFile(i); +#endif + disconnectStream(i); + disconnectScreen(i); + } + return true; +} + +sgp::Logger_ID sgp::Logger::createLogger() +{ + _logs.push_back(sgp::Logger::LogData()); + Logger_ID id = _logs.size() - 1; + _logs[id].timer.startTimer(); + return id; +} + +sgp::Logger::FlushMode sgp::Logger::flushMode(sgp::Logger_ID id) +{ + sgp::Logger::FlushMode fmode = (sgp::Logger::FlushMode)-1; + if(id >= 0 && id < _logs.size()) + { + if(_logs[id].file) + { + vfs::Log::EFlushMode fm = _logs[id].file->flushMode(); + + if (fm == vfs::Log::FLUSH_ON_DELETE) fmode = sgp::Logger::FLUSH_ON_DELETE; + else if(fm == vfs::Log::FLUSH_IMMEDIATELY) fmode = sgp::Logger::FLUSH_IMMIDIATELY; + else if(fm == vfs::Log::FLUSH_BUFFER) fmode = sgp::Logger::FLUSH_FULL_BUFFER; + else if(fm == vfs::Log::FLUSH_ON_ENDL) fmode = sgp::Logger::FLUSH_ON_ENDL; + } + } + return fmode; +} + +void sgp::Logger::flushMode(sgp::Logger_ID id, sgp::Logger::FlushMode fmode) +{ + if(id >= 0 && id < _logs.size()) + { + vfs::Log::EFlushMode fm; + if (fmode == sgp::Logger::FLUSH_ON_DELETE) fm = vfs::Log::FLUSH_ON_DELETE; + else if(fmode == sgp::Logger::FLUSH_IMMIDIATELY) fm = vfs::Log::FLUSH_IMMEDIATELY; + else if(fmode == sgp::Logger::FLUSH_FULL_BUFFER) fm = vfs::Log::FLUSH_BUFFER; + else if(fmode == sgp::Logger::FLUSH_ON_ENDL) fm = vfs::Log::FLUSH_ON_ENDL; + else fm = vfs::Log::FLUSH_IMMEDIATELY; + + if(_logs[id].file) + { + _logs[id].file->releaseFile(); + _logs[id].file->flushMode(fm); + } + } +} + + +#if defined(USE_VFS) +void sgp::Logger::connectFile(sgp::Logger_ID id, vfs::Path const& log_file, bool append, FlushMode fmode) +{ + if(id >= 0 && id < _logs.size()) + { + vfs::Log::EFlushMode fm; + if (fmode == sgp::Logger::FLUSH_ON_DELETE) fm = vfs::Log::FLUSH_ON_DELETE; + else if(fmode == sgp::Logger::FLUSH_IMMIDIATELY) fm = vfs::Log::FLUSH_IMMEDIATELY; + else if(fmode == sgp::Logger::FLUSH_FULL_BUFFER) fm = vfs::Log::FLUSH_BUFFER; + else if(fmode == sgp::Logger::FLUSH_ON_ENDL) fm = vfs::Log::FLUSH_ON_ENDL; + else fm = vfs::Log::FLUSH_IMMEDIATELY; + + _logs[id].file = vfs::Log::create(log_file,append,fm); + } +} +void sgp::Logger::disconnectFile(sgp::Logger_ID id) +{ + if(id >= 0 && id < _logs.size()) + { + if(_logs[id].file) + { + _logs[id].file->destroy(); + _logs[id].file = NULL; + } + } +} +#endif + +void sgp::Logger::connectStream(sgp::Logger_ID id, std::ostream& stream) +{ + if(id >= 0 && id < _logs.size()) + { + _logs[id].stream = &std::wcout; + } +} +void sgp::Logger::disconnectStream(sgp::Logger_ID id) +{ + if(id >= 0 && id < _logs.size()) + { + _logs[id].stream = NULL; + } +} + +void sgp::Logger::connectScreen(sgp::Logger_ID id) +{ + if(id >= 0 && id < _logs.size()) + { + if(_logs[id].screen) + { + disconnectScreen(id); + } + _logs[id].screen = new std::wstringstream; + } +} +void sgp::Logger::disconnectScreen(sgp::Logger_ID id) +{ + if(id >= 0 && id < _logs.size()) + { + if(_logs[id].screen) + { + flush_screen(*_logs[id].screen); + delete _logs[id].screen; + _logs[id].screen = NULL; + } + } +} + + +//#if defined(USE_VFS) +//int sgp::Logger::createLogger(vfs::Path const& log_file, bool append, FlushMode fp) +//{ +// vfs::Log::EFlushMode fm; +// if(fp == sgp::Logger::FLUSH_ON_DELETE) fm = vfs::Log::FLUSH_ON_DELETE; +// else if(fp == sgp::Logger::FLUSH_IMMIDIATELY) fm = vfs::Log::FLUSH_IMMEDIATELY; +// else if(fp == sgp::Logger::FLUSH_FULL_BUFFER) fm = vfs::Log::FLUSH_BUFFER; +// else if(fp == sgp::Logger::FLUSH_ON_ENDL) fm = vfs::Log::FLUSH_ON_ENDL; +// else fm = vfs::Log::FLUSH_IMMEDIATELY; +// +// _logs.push_back(STimeLog()); +// _next_log_id++; +// _logs[_next_log_id]._log = vfs::Log::create(log_file,append,fm); +// _logs[_next_log_id]._timer.startTimer(); +// return _next_log_id; +//} +//#endif + +sgp::Logger::LogInstance sgp::Logger::logger(sgp::Logger_ID id) +{ + if(id < _logs.size()) + { +#if defined(USE_VFS) + std::wstringstream tmp; + tmp << L"[" << _logs[id].timer.running() << L"] : "; + std::wstring str(tmp.str()); + + LogData& ld = _logs[id]; + if(ld.file) { + (*ld.file).lock(); + (*ld.file) << str; + } + if(ld.stream) { + (*ld.stream) << str; + } + if(ld.screen) { + (*ld.screen) << str; + } +#endif + return sgp::Logger::LogInstance(&ld); + } + SGP_THROW(L"Unknown log id"); +} + +template <> +sgp::Logger::LogInstance& sgp::Logger::LogInstance::operator<< (sgp::_flush const& e) +{ + if(_log.file) + { +#if defined(USE_VFS) + (*_log.file).flush(); + (*_log.file).unlock(); +#endif + } + if(_log.stream) + { + (*_log.stream).flush(); + } + if(_log.screen) + { + flush_screen(*_log.screen); + } + return *this; +} + +template <> +sgp::Logger::LogInstance& sgp::Logger::LogInstance::operator<< (sgp::_endl const& e) +{ + if(_log.file) + { +#if defined(USE_VFS) + (*_log.file) << vfs::Log::endl; + if(_log.file->flushMode() == vfs::Log::FLUSH_ON_ENDL) + { + (*_log.file).flush(); + } + (*_log.file).unlock(); +#endif + } + if(_log.stream) + { + (*_log.stream) << std::endl; + (*_log.stream).flush(); + } + if(_log.screen) + { + flush_screen(*_log.screen); + } + return *this; +} +template <> +sgp::Logger::LogInstance& sgp::Logger::LogInstance::operator<< (sgp::_lock const& l) +{ +#if defined(USE_VFS) + _log.file->lock(); +#endif + return *this; +} diff --git a/Standard Gaming Platform/sgp_logger.h b/Standard Gaming Platform/sgp_logger.h new file mode 100644 index 00000000..d93c7cd6 --- /dev/null +++ b/Standard Gaming Platform/sgp_logger.h @@ -0,0 +1,149 @@ +#ifndef SGP_LOGGER_H +#define SGP_LOGGER_H + +#include +#if defined(USE_VFS) +# include +# include +# include +#else +# include +#endif + +namespace sgp +{ + typedef unsigned int Logger_ID; + + enum _endl{endl}; + enum _lock{lock}; + enum _flush{flush}; + + class Logger + { + struct LogData + { +#if defined(USE_VFS) + LogData() : file(NULL), stream(NULL), screen(NULL) {}; + vfs::HPTimer timer; + vfs::Log* file; +#else + LogData() : stream(NULL), screen(NULL) {}; +#endif + std::wostream* stream; + std::wstringstream* screen; + }; + public: + + enum FlushMode + { + FLUSH_ON_DELETE, + FLUSH_ON_ENDL, + FLUSH_ON_FLUSH, + FLUSH_FULL_BUFFER, + FLUSH_IMMIDIATELY, + }; + + // need to lock/unlock on every logging operation, as they can be called from multiple threads + class LogInstance + { + friend class Logger; + LogInstance(LogData* ld) : _log(*ld) {}; + public: + template + LogInstance& operator<<(T const& t){ + if(_log.stream) (*_log.stream) << t; + if(_log.screen) (*_log.screen) << t; +#if defined(USE_VFS) + if(_log.file ) (*_log.file) << t; +#endif + return *this; + } + private: + LogData& _log; + }; + + + static Logger& instance(); + + bool init(); + bool shutdown(); + + LogInstance logger(Logger_ID id); + + Logger_ID createLogger(); + +#if defined(USE_VFS) + void connectFile(Logger_ID id, vfs::Path const& log_file, bool append, FlushMode fp); + void disconnectFile(Logger_ID id); +#endif + void connectStream(Logger_ID id, std::ostream& stream); + void disconnectStream(Logger_ID id); + + void connectScreen(Logger_ID id); + void disconnectScreen(Logger_ID id); + + void flushMode(Logger_ID id, FlushMode fmode); + FlushMode flushMode(Logger_ID id); + private: + Logger(); + ~Logger(); + + private: + static int _next_log_id; + + static std::vector _logs; + }; + + template <> + Logger::LogInstance& Logger::LogInstance::operator<< <_endl>(_endl const& e); + template <> + Logger::LogInstance& Logger::LogInstance::operator<< <_lock>(_lock const& l); + template <> + Logger::LogInstance& Logger::LogInstance::operator<< <_flush>(_flush const& f); +} + +#if defined(USE_VFS) +inline sgp::Logger::LogInstance SGP_LOG(sgp::Logger_ID id, vfs::String const& str){ +#else +inline sgp::Logger::LogInstance SGP_LOG(int id, const char* str){ +#endif + return sgp::Logger::instance().logger(id) << (str) << sgp::endl; +} +inline sgp::Logger::LogInstance SGP_LOG(sgp::Logger_ID id){ + return sgp::Logger::instance().logger(id); +} + +#if defined(USE_VFS) +inline sgp::Logger::LogInstance SGP_INFO(vfs::String const& str){ +#else +inline sgp::Logger::LogInstance SGP_INFO(const char* str){ +#endif + return sgp::Logger::instance().logger(0) << str << sgp::endl; +} +inline sgp::Logger::LogInstance SGP_INFO(){ + return sgp::Logger::instance().logger(0); +} + +#if defined(USE_VFS) +inline sgp::Logger::LogInstance SGP_WARNING(vfs::String const& str){ +#else +inline sgp::Logger::LogInstance SGP_WARNING(const char* str){ +#endif + return sgp::Logger::instance().logger(0) << "WARNING : " << str << sgp::endl; +} +inline sgp::Logger::LogInstance SGP_WARNING(){ + return sgp::Logger::instance().logger(0) << "WARNING : "; +} + +#if defined(USE_VFS) +inline sgp::Logger::LogInstance SGP_ERROR(vfs::String const& str){ +#else +inline sgp::Logger::LogInstance SGP_ERROR(const char* str){ +#endif + return sgp::Logger::instance().logger(0) << "ERROR : " << str << sgp::endl; +} +inline sgp::Logger::LogInstance SGP_ERROR(){ + return sgp::Logger::instance().logger(0) << "ERROR : "; +} + +#endif // SGP_LOGGER_H diff --git a/Standard Gaming Platform/soundman.cpp b/Standard Gaming Platform/soundman.cpp index 43209612..6386eaa3 100644 --- a/Standard Gaming Platform/soundman.cpp +++ b/Standard Gaming Platform/soundman.cpp @@ -21,6 +21,7 @@ #include "random.h" #include "fmod.h" #include "fmod_errors.h" + #include "sgp_logger.h" #endif // Uncomment this to disable the startup of sound hardware @@ -1801,14 +1802,16 @@ UINT32 uiCount; return(FALSE); } -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" - // Lesh modifications // Sound debug -#ifdef USE_VFS -static CLog& s_SoundLog = *CLog::create(SndDebugFileName,true); -#endif +static struct SoundLog { + sgp::Logger_ID id; + SoundLog() { + id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(id, SndDebugFileName, true, sgp::Logger::FLUSH_ON_DELETE); + } +} s_SoundLog; + //***************************************************************************************** // SoundLog // Writes string into log file @@ -1826,7 +1829,7 @@ void SoundLog(CHAR8 *strMessage) fclose(SndDebug); } #else - s_SoundLog << strMessage << CLog::ENDL; + SGP_LOG(s_SoundLog.id, vfs::String::widen(strMessage,strlen(strMessage))); #endif } diff --git a/Standard Gaming Platform/video.cpp b/Standard Gaming Platform/video.cpp index 51e15aa7..95adb585 100644 --- a/Standard Gaming Platform/video.cpp +++ b/Standard Gaming Platform/video.cpp @@ -18,11 +18,12 @@ #include "Fileman.h" #include "Input.h" #include "GameSettings.h" +#include "sgp_logger.h" #endif #include "resource.h" -#include "VFS/vfs.h" -#include "VFS/vfs_file_raii.h" +#include +#include #include "Local.h" #include "text.h" @@ -665,15 +666,39 @@ void ShutdownVideoManager(void) // down // - IDirectDrawSurface2_Release(gpMouseCursorOriginal); - IDirectDrawSurface2_Release(gpMouseCursor); - IDirectDrawSurface2_Release(gMouseCursorBackground[0].pSurface); - IDirectDrawSurface2_Release(gpBackBuffer); - IDirectDrawSurface2_Release(gpPrimarySurface); + if(gpMouseCursorOriginal) + { + IDirectDrawSurface2_Release(gpMouseCursorOriginal); + gpMouseCursorOriginal = NULL; + } + if(gpMouseCursor) + { + IDirectDrawSurface2_Release(gpMouseCursor); + gpMouseCursor = NULL; + } + if(gMouseCursorBackground[0].pSurface) + { + IDirectDrawSurface2_Release(gMouseCursorBackground[0].pSurface); + gMouseCursorBackground[0].pSurface = NULL; + } + if(gpBackBuffer) + { + IDirectDrawSurface2_Release(gpBackBuffer); + gpBackBuffer = NULL; + } + if(gpPrimarySurface) + { + IDirectDrawSurface2_Release(gpPrimarySurface); + gpPrimarySurface = NULL; + } - IDirectDraw2_RestoreDisplayMode( gpDirectDrawObject ); - IDirectDraw2_SetCooperativeLevel(gpDirectDrawObject, ghWindow, DDSCL_NORMAL ); - IDirectDraw2_Release( gpDirectDrawObject ); + if(gpDirectDrawObject) + { + IDirectDraw2_RestoreDisplayMode( gpDirectDrawObject ); + IDirectDraw2_SetCooperativeLevel(gpDirectDrawObject, ghWindow, DDSCL_NORMAL ); + IDirectDraw2_Release( gpDirectDrawObject ); + gpDirectDrawObject = NULL; + } // destroy the window // DestroyWindow( ghWindow ); @@ -1993,7 +2018,7 @@ void RefreshScreen(void *DummyVariable) { vfs::COpenWriteFile wfile(FileName,true,true); char head[] = {0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, LOBYTE(SCREEN_WIDTH), HIBYTE(SCREEN_WIDTH), LOBYTE(SCREEN_HEIGHT), HIBYTE(SCREEN_HEIGHT), 0x10, 0}; - TRYCATCH_RETHROW(wfile.file().write(head,18), L""); + SGP_TRYCATCH_RETHROW(wfile->write(head,18), L""); #endif // @@ -2034,7 +2059,7 @@ void RefreshScreen(void *DummyVariable) #ifndef USE_VFS fwrite( p16BPPData, SCREEN_WIDTH * 2, 1, OutputFile); #else - TRYCATCH_RETHROW(wfile.file().write((vfs::Byte*)p16BPPData, SCREEN_WIDTH * 2), L""); + SGP_TRYCATCH_RETHROW(wfile->write((vfs::Byte*)p16BPPData, SCREEN_WIDTH * 2), L""); #endif } else @@ -2042,7 +2067,7 @@ void RefreshScreen(void *DummyVariable) #ifndef USE_VFS fwrite((void *)(((UINT8 *)SurfaceDescription.lpSurface) + (iIndex * SCREEN_WIDTH * 2)), SCREEN_WIDTH * 2, 1, OutputFile); #else - TRYCATCH_RETHROW(wfile.file().write((vfs::Byte*)(((UINT8 *)SurfaceDescription.lpSurface) + (iIndex * SCREEN_WIDTH * 2)), SCREEN_WIDTH * 2), L""); + SGP_TRYCATCH_RETHROW(wfile->write((vfs::Byte*)(((UINT8 *)SurfaceDescription.lpSurface) + (iIndex * SCREEN_WIDTH * 2)), SCREEN_WIDTH * 2), L""); #endif } } @@ -2069,9 +2094,9 @@ void RefreshScreen(void *DummyVariable) } #ifdef USE_VFS - catch(CBasicException& ex) + catch(std::exception& ex) { - RETHROWEXCEPTION(L"",&ex); + SGP_RETHROW(L"", ex); } #endif @@ -3177,8 +3202,12 @@ void FatalError( const STR8 pError, ...) gfFatalError = TRUE; // Release DDraw - IDirectDraw2_RestoreDisplayMode( gpDirectDrawObject ); - IDirectDraw2_Release( gpDirectDrawObject ); + if(gpDirectDrawObject) + { + IDirectDraw2_RestoreDisplayMode( gpDirectDrawObject ); + IDirectDraw2_Release( gpDirectDrawObject ); + gpDirectDrawObject = NULL; + } ShowWindow( ghWindow, SW_HIDE ); // destroy the window @@ -3186,8 +3215,8 @@ void FatalError( const STR8 pError, ...) gfProgramIsRunning = FALSE; - MessageBox( ghWindow, gFatalErrorString, "JA2 Fatal Error", MB_OK | MB_TASKMODAL ); - + //MessageBox( ghWindow, gFatalErrorString, "JA2 Fatal Error", MB_OK | MB_TASKMODAL ); + MessageBoxW( ghWindow, vfs::String::as_utf16(gFatalErrorString).c_str(), L"JA2 Fatal Error", MB_OK | MB_TASKMODAL ); } @@ -3383,7 +3412,7 @@ void RefreshMovieCache( ) #ifndef USE_VFS fwrite(&Header, sizeof(TARGA_HEADER), 1, disk); #else - TRYCATCH_RETHROW(wfile.file().write((vfs::Byte*)&Header, sizeof(TARGA_HEADER)), L""); + SGP_TRYCATCH_RETHROW(wfile->write((vfs::Byte*)&Header, sizeof(TARGA_HEADER)), L""); #endif pDest = gpFrameData[ cnt ]; @@ -3394,7 +3423,7 @@ void RefreshMovieCache( ) #ifndef USE_VFS fwrite( ( pDest + ( iCountY * SCREEN_WIDTH ) + iCountX ), sizeof(UINT16), 1, disk); #else - TRYCATCH_RETHROW(wfile.file().write( (vfs::Byte*)( pDest + ( iCountY * SCREEN_WIDTH ) + iCountX ), sizeof(UINT16)), L""); + SGP_TRYCATCH_RETHROW(wfile->write( (vfs::Byte*)( pDest + ( iCountY * SCREEN_WIDTH ) + iCountX ), sizeof(UINT16)), L""); #endif } @@ -3414,9 +3443,9 @@ void RefreshMovieCache( ) //SetFileManCurrentDirectory( ExecDir ); #else } - catch(CBasicException& ex) + catch(std::exception& ex) { - logException(ex); + SGP_ERROR(ex.what()); } #endif } diff --git a/Standard Gaming Platform/vobject.cpp b/Standard Gaming Platform/vobject.cpp index c393ee67..1ce9b7a0 100644 --- a/Standard Gaming Platform/vobject.cpp +++ b/Standard Gaming Platform/vobject.cpp @@ -302,7 +302,7 @@ BOOLEAN BltVideoObjectFromIndex(UINT32 uiDestVSurface, UINT32 uiSrcVObject, UINT // Now we have the video object and surface, call the VO blitter function if ( !BltVideoObjectToBuffer( pBuffer, uiPitch, hSrcVObject, usRegionIndex, iDestX, iDestY, fBltFlags, pBltFx ) ) { - UnLockVideoSurface( uiDestVSurface ); + UnLockVideoSurface( uiDestVSurface ); // VO Blitter will set debug messages for error conditions return FALSE; } @@ -434,8 +434,19 @@ HVOBJECT CreateVideoObject( VOBJECT_DESC *VObjectDesc ) { if ( VObjectDesc->fCreateFlags & VOBJECT_CREATE_FROMFILE ) { + ImageFileType::TestOrder order = ImageFileType::JPC_FALLBACK; + + if(VObjectDesc->fCreateFlags & VOBJECT_CREATE_FROMJPC) { + order = ImageFileType::JPC; + } else if(VObjectDesc->fCreateFlags & VOBJECT_CREATE_FROMJPC_FALLBACK) { + order = ImageFileType::JPC_FALLBACK; + } else if(VObjectDesc->fCreateFlags & VOBJECT_CREATE_FROMPNG) { + order = ImageFileType::PNG_FALLBACK; + } else if(VObjectDesc->fCreateFlags & VOBJECT_CREATE_FROMPNG_FALLBACK) { + order = ImageFileType::PNG_FALLBACK; + } // Create himage object from file - hImage = CreateImage( VObjectDesc->ImageFile, IMAGE_ALLIMAGEDATA ); + hImage = CreateImage( VObjectDesc->ImageFile, IMAGE_ALLIMAGEDATA, order ); if ( hImage == NULL ) { @@ -457,17 +468,31 @@ HVOBJECT CreateVideoObject( VOBJECT_DESC *VObjectDesc ) if(hImage->ubBitDepth == 32) { - hVObject->p16BPPObject = new SixteenBPPObjectInfo; - int SIZE = hImage->usHeight*hImage->usWidth; - hVObject->pPixData = new UINT32[SIZE]; - memcpy(hVObject->pPixData, hImage->p32BPPData, SIZE*sizeof(UINT32)); - hVObject->p16BPPObject->p16BPPData = NULL; - hVObject->p16BPPObject->sOffsetX = 0; - hVObject->p16BPPObject->sOffsetY = 0; - hVObject->p16BPPObject->ubShadeLevel = 0; - hVObject->p16BPPObject->usHeight = hImage->usHeight; - hVObject->p16BPPObject->usWidth = hImage->usWidth; - hVObject->p16BPPObject->usRegionIndex = 0; + SGP_THROW_IFFALSE(hImage->usNumberOfObjects > 0, L"bad himage"); + + // create one 16bpp object (that contains 32bpp data) + hVObject->p16BPPObject = (SixteenBPPObjectInfo*)MemAlloc(sizeof(SixteenBPPObjectInfo)); + if(!hVObject->p16BPPObject) + { + SGP_THROW(L"bad alloc"); + } + memset(hVObject->p16BPPObject, 0, sizeof(SixteenBPPObjectInfo)); + + int SIZE = hImage->pETRLEObject[0].usHeight * hImage->pETRLEObject[0].usWidth * sizeof(UINT32); + hVObject->p16BPPObject->p16BPPData = (UINT16*)MemAlloc(SIZE); // UINT32* + if(!hVObject->p16BPPObject->p16BPPData) + { + MemFree(hVObject->p16BPPObject); + SGP_THROW(L"bad alloc"); + } + memcpy(hVObject->p16BPPObject->p16BPPData, hImage->p32BPPData, SIZE); + + hVObject->p16BPPObject->sOffsetX = hImage->pETRLEObject[0].sOffsetX; + hVObject->p16BPPObject->sOffsetY = hImage->pETRLEObject[0].sOffsetY; + hVObject->p16BPPObject->ubShadeLevel = 0; + hVObject->p16BPPObject->usHeight = hImage->pETRLEObject[0].usHeight; + hVObject->p16BPPObject->usWidth = hImage->pETRLEObject[0].usWidth; + hVObject->p16BPPObject->usRegionIndex = 0; hVObject->usNumberOf16BPPObjects = 1; hVObject->ubBitDepth = hImage->ubBitDepth; @@ -481,16 +506,31 @@ HVOBJECT CreateVideoObject( VOBJECT_DESC *VObjectDesc ) } else if(hImage->ubBitDepth == 16) { - hVObject->p16BPPObject = new SixteenBPPObjectInfo; - int SIZE = hImage->usHeight*hImage->usWidth; - hVObject->p16BPPObject->p16BPPData = new UINT16[SIZE]; - memcpy(hVObject->p16BPPObject->p16BPPData, hImage->p16BPPData, SIZE*sizeof(UINT16)); - hVObject->p16BPPObject->sOffsetX = 0; - hVObject->p16BPPObject->sOffsetY = 0; - hVObject->p16BPPObject->ubShadeLevel = 0; - hVObject->p16BPPObject->usHeight = hImage->usHeight; - hVObject->p16BPPObject->usWidth = hImage->usWidth; - hVObject->p16BPPObject->usRegionIndex = 0; + SGP_THROW_IFFALSE(hImage->usNumberOfObjects > 0, L"bad himage"); + + // create one 16bpp object (that contains 32bpp data) + hVObject->p16BPPObject = (SixteenBPPObjectInfo*)MemAlloc(sizeof(SixteenBPPObjectInfo)); + if(!hVObject->p16BPPObject) + { + SGP_THROW(L"bad alloc"); + } + memset(hVObject->p16BPPObject, 0, sizeof(SixteenBPPObjectInfo)); + + int SIZE = hImage->pETRLEObject[0].usHeight * hImage->pETRLEObject[0].usWidth * sizeof(UINT16); + hVObject->p16BPPObject->p16BPPData = (UINT16*)MemAlloc(SIZE); + if(!hVObject->p16BPPObject->p16BPPData) + { + MemFree(hVObject->p16BPPObject); + SGP_THROW(L"bad alloc"); + } + memcpy(hVObject->p16BPPObject->p16BPPData, hImage->p16BPPData, SIZE); + + hVObject->p16BPPObject->sOffsetX = hImage->pETRLEObject[0].sOffsetX; + hVObject->p16BPPObject->sOffsetY = hImage->pETRLEObject[0].sOffsetY; + hVObject->p16BPPObject->ubShadeLevel = 0; + hVObject->p16BPPObject->usHeight = hImage->pETRLEObject[0].usHeight; + hVObject->p16BPPObject->usWidth = hImage->pETRLEObject[0].usWidth; + hVObject->p16BPPObject->usRegionIndex = 0; hVObject->usNumberOf16BPPObjects = 1; hVObject->ubBitDepth = hImage->ubBitDepth; @@ -520,9 +560,9 @@ HVOBJECT CreateVideoObject( VOBJECT_DESC *VObjectDesc ) // Set values hVObject->usNumberOfObjects = TempETRLEData.usNumberOfObjects; - hVObject->pETRLEObject = TempETRLEData.pETRLEObject; - hVObject->pPixData = TempETRLEData.pPixData; - hVObject->uiSizePixData = TempETRLEData.uiSizePixData; + hVObject->pETRLEObject = TempETRLEData.pETRLEObject; + hVObject->pPixData = TempETRLEData.pPixData; + hVObject->uiSizePixData = TempETRLEData.uiSizePixData; // Set palette from himage if ( hImage->ubBitDepth == 8 ) @@ -768,11 +808,11 @@ UINT32 count; BOOLEAN BltVideoObjectToBuffer( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, HVOBJECT hSrcVObject, UINT16 usIndex, INT32 iDestX, INT32 iDestY, INT32 fBltFlags, blt_fx *pBltFx ) { // Sometimes an exception is thrown in that method. - __try +//BF __try { // Assertions //Assert( pBuffer != NULL ); - THROWIFFALSE( pBuffer != NULL, L"No Destination Buffer" ); + SGP_THROW_IFFALSE( pBuffer != NULL, L"No Destination Buffer" ); if ( hSrcVObject == NULL ) { @@ -780,13 +820,14 @@ BOOLEAN BltVideoObjectToBuffer( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, HVOBJE } //Assert( hSrcVObject != NULL ); - THROWIFFALSE( hSrcVObject != NULL, L"No Source Object" ) + SGP_THROW_IFFALSE( hSrcVObject != NULL, L"No Source Object" ) SixteenBPPObjectInfo *image = NULL; // Check For Flags and bit depths switch( hSrcVObject->ubBitDepth ) { case 32: + SGP_THROW_IFFALSE(usIndex < hSrcVObject->usNumberOf16BPPObjects, L"index larger that number images"); image = &hSrcVObject->p16BPPObject[usIndex]; #if 0 Blt16BPPTo16BPPTrans( pBuffer, uiDestPitchBYTES, @@ -796,24 +837,35 @@ BOOLEAN BltVideoObjectToBuffer( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, HVOBJE 0 ); #else Blt32BPPTo16BPPTrans( pBuffer, uiDestPitchBYTES, - (UINT32*)hSrcVObject->pPixData, image->usWidth * sizeof(UINT32), + (UINT32*)image->p16BPPData, image->usWidth * sizeof(UINT32), iDestX, iDestY, 0, 0, image->usWidth, image->usHeight); #endif break; case 16: + SGP_THROW_IFFALSE(usIndex < hSrcVObject->usNumberOf16BPPObjects, L"index larger that number images"); image = &hSrcVObject->p16BPPObject[usIndex]; - Blt16BPPTo16BPP( pBuffer, uiDestPitchBYTES, - image->p16BPPData, image->usWidth * sizeof(UINT16), - iDestX, iDestY, - 0, 0, image->usWidth, image->usHeight ); + if ( fBltFlags & VO_BLT_SRCTRANSPARENCY ) + { + Blt16BPPTo16BPPTrans( pBuffer, uiDestPitchBYTES, + image->p16BPPData, image->usWidth * sizeof(UINT16), + iDestX, iDestY, + 0, 0, image->usWidth, image->usHeight, 0x1F ); // 0x1f = 5 bits of blue + } + else + { + Blt16BPPTo16BPP( pBuffer, uiDestPitchBYTES, + image->p16BPPData, image->usWidth * sizeof(UINT16), + iDestX, iDestY, + 0, 0, image->usWidth, image->usHeight ); + } break; case 8: - THROWIFFALSE( hSrcVObject->usNumberOfObjects > usIndex, L"Video object index is larger than the number of subimages"); + SGP_THROW_IFFALSE( hSrcVObject->usNumberOfObjects > usIndex, L"Video object index is larger than the number of subimages"); // Switch based on flags given do { @@ -877,10 +929,11 @@ BOOLEAN BltVideoObjectToBuffer( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, HVOBJE return( TRUE ); } - __except(filter(GetExceptionCode(), GetExceptionInformation())) - { - return ( TRUE ); - } + //BF + //__except(filter(GetExceptionCode(), GetExceptionInformation())) + //{ + // return ( TRUE ); + //} } BOOLEAN PixelateVideoObjectRect( UINT32 uiDestVSurface, INT32 X1, INT32 Y1, INT32 X2, INT32 Y2) @@ -1452,13 +1505,30 @@ BOOLEAN BltVideoObjectOutlineShadowFromIndex(UINT32 uiDestVSurface, UINT32 uiSrc #endif CHECKF( GetVideoObject( &hSrcVObject, uiSrcVObject ) ); - if( BltIsClipped( hSrcVObject, iDestX, iDestY, usIndex, &ClippingRect) ) + if(hSrcVObject->ubBitDepth == 8) { - Blt8BPPDataTo16BPPBufferOutlineShadowClip((UINT16*)pBuffer, uiPitch, hSrcVObject, iDestX, iDestY, usIndex, &ClippingRect ); + if( BltIsClipped( hSrcVObject, iDestX, iDestY, usIndex, &ClippingRect) ) + { + Blt8BPPDataTo16BPPBufferOutlineShadowClip((UINT16*)pBuffer, uiPitch, hSrcVObject, iDestX, iDestY, usIndex, &ClippingRect ); + } + else + { + Blt8BPPDataTo16BPPBufferOutlineShadow((UINT16*)pBuffer, uiPitch, hSrcVObject, iDestX, iDestY, usIndex ); + } } - else + else if(hSrcVObject->ubBitDepth == 16) { - Blt8BPPDataTo16BPPBufferOutlineShadow((UINT16*)pBuffer, uiPitch, hSrcVObject, iDestX, iDestY, usIndex ); + SGP_THROW_IFFALSE(usIndex < hSrcVObject->usNumberOf16BPPObjects, L"index larger that number images"); + SixteenBPPObjectInfo &image = hSrcVObject->p16BPPObject[0]; + Blt16BPPTo16BPPTransShadow(pBuffer, uiPitch, image.p16BPPData, image.usWidth * sizeof(UINT16), + iDestX, iDestY, 0, 0, image.usWidth, image.usHeight, 0x1F); + } + else if(hSrcVObject->ubBitDepth == 32) + { + SGP_THROW_IFFALSE(usIndex < hSrcVObject->usNumberOf16BPPObjects, L"index larger that number images"); + SixteenBPPObjectInfo &image = hSrcVObject->p16BPPObject[0]; + Blt32BPPTo16BPPTransShadow(pBuffer, uiPitch, (UINT32*)image.p16BPPData, image.usWidth * sizeof(UINT32), + iDestX, iDestY, 0, 0, image.usWidth, image.usHeight); } // Now we have the video object and surface, call the VO blitter function diff --git a/Standard Gaming Platform/vobject.h b/Standard Gaming Platform/vobject.h index a2f6b8e6..54a0a3be 100644 --- a/Standard Gaming Platform/vobject.h +++ b/Standard Gaming Platform/vobject.h @@ -72,6 +72,10 @@ typedef struct #define VOBJECT_CREATE_DEFAULT 0x00000020 // Creates and empty object of given width, height and BPP #define VOBJECT_CREATE_FROMFILE 0x00000040 // Creates a video object from a file ( using HIMAGE ) #define VOBJECT_CREATE_FROMHIMAGE 0x00000080 // Creates a video object from a pre-loaded hImage +#define VOBJECT_CREATE_FROMJPC 0x00010000 // replace file extension : sti -> jpc.7z +#define VOBJECT_CREATE_FROMPNG 0x00020000 // replace file extension : sti -> png +#define VOBJECT_CREATE_FROMJPC_FALLBACK 0x00100000 // replace file extension : sti -> jpc.7z, fall back to sti when it doesn't exist +#define VOBJECT_CREATE_FROMPNG_FALLBACK 0x00200000 // replace file extension : sti -> png, fall back to sti when it doesn't exist // VOBJECT FLAGS #define VOBJECT_FLAG_SHADETABLE_SHARED 0x00000100 diff --git a/Standard Gaming Platform/vobject_blitters.cpp b/Standard Gaming Platform/vobject_blitters.cpp index 188f4018..ffa1d868 100644 --- a/Standard Gaming Platform/vobject_blitters.cpp +++ b/Standard Gaming Platform/vobject_blitters.cpp @@ -19,6 +19,7 @@ #include "vobject.h" #include "vobject_blitters.h" #include "shading.h" + #include "sgp_logger.h" #endif #include @@ -66,29 +67,33 @@ BOOLEAN Blt32BPPTo16BPPTrans(UINT16 *pDest, UINT32 uiDestPitch, UINT32 *pSrc, UI UINT32 w = uiWidth; do { - //alpha = (UINT8)((0xFF000000 & *pSrcPtr) >> 24); - alpha = 255; - // r - dst_channel = (UINT8)((0x1F & *pDestPtr) << 3); - src_channel = (UINT8)((0xFF & *pSrcPtr) ); - //red = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); - red = (UINT8)( g_AlphaTimesValueCache[alpha][src_channel] ); + // a + alpha = (UINT8)((0xFF000000 & *pSrcPtr) >> 24); + //alpha = 255; + if(alpha > 0) + { + // r + dst_channel = (UINT8)((0x1F & *pDestPtr) << 3); + src_channel = (UINT8)((0xFF & *pSrcPtr) ); + red = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); + //red = (UINT8)( g_AlphaTimesValueCache[alpha][src_channel] ); - // g - dst_channel = (UINT8)((0x7E0 & *pDestPtr) >> 3); - src_channel = (UINT8)((0xFF00 & *pSrcPtr) >> 8); - //green = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); - green = (UINT8)( g_AlphaTimesValueCache[alpha][src_channel] ); + // g + dst_channel = (UINT8)((0x7E0 & *pDestPtr) >> 3); + src_channel = (UINT8)((0xFF00 & *pSrcPtr) >> 8); + green = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); + //green = (UINT8)( g_AlphaTimesValueCache[alpha][src_channel] ); - // b - dst_channel = (UINT8)((0xF800 & *pDestPtr) >> 8); - src_channel = (UINT8)((0xFF0000 & *pSrcPtr) >> 16); - //blue = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); - blue = (UINT8)( g_AlphaTimesValueCache[alpha][src_channel] ); + // b + dst_channel = (UINT8)((0xF800 & *pDestPtr) >> 8); + src_channel = (UINT8)((0xFF0000 & *pSrcPtr) >> 16); + blue = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); + //blue = (UINT8)( g_AlphaTimesValueCache[alpha][src_channel] ); - UINT32 newcolor = FROMRGB(red,green,blue); - *pDestPtr = Get16BPPColor(newcolor); + UINT32 newcolor = FROMRGB(red,green,blue); + *pDestPtr = Get16BPPColor(newcolor); + } pSrcPtr++; pDestPtr++; } @@ -101,6 +106,75 @@ BOOLEAN Blt32BPPTo16BPPTrans(UINT16 *pDest, UINT32 uiDestPitch, UINT32 *pSrc, UI return ( TRUE ); } +BOOLEAN Blt32BPPTo16BPPTransShadow(UINT16 *pDst, UINT32 uiDstPitch, UINT32 *pSrc, UINT32 uiSrcPitch, INT32 iDstXPos, INT32 iDstYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight) +{ + UINT32 *pSrcPtr; + UINT16 *pDstPtr; + UINT32 uiLineSkipDst, uiLineSkipSrc; + + Assert(pDst!=NULL); + Assert(pSrc!=NULL); + + pSrcPtr = (UINT32*)((UINT8*)pSrc + (iSrcYPos * uiSrcPitch) + (iSrcXPos * 4)); + uiLineSkipSrc = uiSrcPitch-(uiWidth*4); + + pDstPtr = (UINT16*)((UINT8*)pDst + (iDstYPos * uiDstPitch) + (iDstXPos * 2)); + uiLineSkipDst = uiDstPitch-(uiWidth*2); + + UINT8 alpha, dst_channel, src_channel; + UINT8 red, green, blue; + UINT16 tmpVal; + UINT32 newcolor; + do + { + UINT32 w = uiWidth; + do + { + // a + alpha = (UINT8)((0xFF000000 & *pSrcPtr) >> 24); + //alpha = 255; + if(alpha > 0) + { +#if 1 + // the darker shade + tmpVal = ShadeTable[*pDstPtr]; + + // r + dst_channel = (UINT8)((0x1F & *pDstPtr) << 3); + //src_channel = (UINT8)((0xFF & tmpVal) ); + src_channel = (UINT8)((0x1F & tmpVal) << 3); + red = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); + + // g + dst_channel = (UINT8)((0x7E0 & *pDstPtr) >> 3); + //src_channel = (UINT8)((0xFF00 & tmpVal) >> 8); + src_channel = (UINT8)((0x7E0 & tmpVal) >> 3); + green = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); + + // b + dst_channel = (UINT8)((0xF800 & *pDstPtr) >> 8); + //src_channel = (UINT8)((0xFF0000 & tmpVal) >> 16); + src_channel = (UINT8)((0xF800 & tmpVal) >> 8); + blue = (UINT8)( g_AlphaTimesValueCache[255-alpha][dst_channel] + g_AlphaTimesValueCache[alpha][src_channel] ); + + + newcolor = FROMRGB(red,green,blue); + *pDstPtr = Get16BPPColor(newcolor); +#else + *pDstPtr = ShadeTable[*pDstPtr]; +#endif + } + pSrcPtr++; + pDstPtr++; + } + while (--w != 0); + pSrcPtr = (UINT32*)((UINT8*)pSrcPtr + uiLineSkipSrc); + pDstPtr = (UINT16*)((UINT8*)pDstPtr + uiLineSkipDst); + } + while (--uiHeight != 0); + + return ( TRUE ); +} /* Here are bliting functions. If you dont know what kind of functions they are so : @@ -7007,7 +7081,7 @@ UINT32 uiLineSkipDest, uiLineSkipSrc; } } surfID = SurfaceData::GetSurfaceID((BYTE*)pSrc); - if( (ct=g_SurfaceRectangle[surfID].Clip(iSrcXPos, iSrcYPos,uiWidth, uiHeight)) != ClipRectangle::NoClip ) + if( surfID && (ct=g_SurfaceRectangle[surfID].Clip(iSrcXPos, iSrcYPos,uiWidth, uiHeight)) != ClipRectangle::NoClip ) { #if _DEBUG WriteMessageToFile(L"Trying to render from outside of surface surface"); @@ -7018,9 +7092,9 @@ UINT32 uiLineSkipDest, uiLineSkipSrc; } } } - catch(CBasicException& ex) + catch(std::exception& ex) { - logException(ex); + SGP_ERROR(ex.what()); return false; } @@ -7085,16 +7159,16 @@ BlitDone: **********************************************************************************************/ BOOLEAN Blt16BPPTo16BPPTrans(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight, UINT16 usTrans) { -UINT16 *pSrcPtr, *pDestPtr; -UINT32 uiLineSkipDest, uiLineSkipSrc; + UINT16 *pSrcPtr, *pDestPtr; + UINT32 uiLineSkipDest, uiLineSkipSrc; Assert(pDest!=NULL); Assert(pSrc!=NULL); - pSrcPtr=(UINT16 *)((UINT8 *)pSrc+(iSrcYPos*uiSrcPitch)+(iSrcXPos*2)); - pDestPtr=(UINT16 *)((UINT8 *)pDest+(iDestYPos*uiDestPitch)+(iDestXPos*2)); - uiLineSkipDest=uiDestPitch-(uiWidth*2); - uiLineSkipSrc=uiSrcPitch-(uiWidth*2); + pSrcPtr = (UINT16*)((UINT8 *)pSrc+(iSrcYPos*uiSrcPitch)+(iSrcXPos*2)); + pDestPtr = (UINT16*)((UINT8 *)pDest+(iDestYPos*uiDestPitch)+(iDestXPos*2)); + uiLineSkipDest = uiDestPitch - (uiWidth*2); + uiLineSkipSrc = uiSrcPitch - (uiWidth*2); #if 1 do { @@ -7143,6 +7217,40 @@ Blit3: return(TRUE); } +BOOLEAN Blt16BPPTo16BPPTransShadow(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight, UINT16 usTrans) +{ + UINT16 *pSrcPtr, *pDestPtr; + UINT32 uiLineSkipDest, uiLineSkipSrc; + + Assert(pDest != NULL); + Assert(pSrc != NULL); + + pSrcPtr = (UINT16*)((UINT8 *)pSrc + (iSrcYPos * uiSrcPitch) + (iSrcXPos * 2)); + pDestPtr = (UINT16*)((UINT8 *)pDest + (iDestYPos * uiDestPitch) + (iDestXPos * 2)); + uiLineSkipDest = uiDestPitch - (uiWidth * 2); + uiLineSkipSrc = uiSrcPitch - (uiWidth * 2); +#if 1 + do + { + UINT32 w = uiWidth; + do + { + if (*pSrcPtr != usTrans) + { + *pDestPtr = ShadeTable[*pDestPtr]; + } + pSrcPtr++; + pDestPtr++; + } + while (--w != 0); + pSrcPtr = (UINT16*)((UINT8*)pSrcPtr + uiLineSkipSrc); + pDestPtr = (UINT16*)((UINT8*)pDestPtr + uiLineSkipDest); + } + while (--uiHeight != 0); +#endif + return TRUE; +} + /********************************************************************************************** Blt16BPPTo16BPPMirror diff --git a/Standard Gaming Platform/vobject_blitters.h b/Standard Gaming Platform/vobject_blitters.h index 4eba3317..823ccb8a 100644 --- a/Standard Gaming Platform/vobject_blitters.h +++ b/Standard Gaming Platform/vobject_blitters.h @@ -148,6 +148,7 @@ BOOLEAN DDBlt8BPPDataTo16BPPBufferShadow( HVOBJECT hDestVObject, HVOBJECT hSrcVO BOOLEAN Blt8BPPTo8BPP(UINT8 *pDest, UINT32 uiDestPitch, UINT8 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight); BOOLEAN Blt16BPPTo16BPP(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight); BOOLEAN Blt16BPPTo16BPPTrans(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight, UINT16 usTrans); +BOOLEAN Blt16BPPTo16BPPTransShadow(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight, UINT16 usTrans); BOOLEAN Blt16BPPTo16BPPFog(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight, UINT8 *pFog, UINT16 usFogPitch); BOOLEAN Blt16BPPTo16BPPMirror(UINT16 *pDest, UINT32 uiDestPitch, UINT16 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight); @@ -188,6 +189,7 @@ BOOLEAN BlitZRect(UINT16 *pZBuffer, UINT32 uiPitch, INT16 sLeft, INT16 sTop, INT // New 16/16 blitters BOOLEAN Blt32BPPTo16BPPTrans(UINT16 *pDest, UINT32 uiDestPitch, UINT32 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight); +BOOLEAN Blt32BPPTo16BPPTransShadow(UINT16 *pDest, UINT32 uiDestPitch, UINT32 *pSrc, UINT32 uiSrcPitch, INT32 iDestXPos, INT32 iDestYPos, INT32 iSrcXPos, INT32 iSrcYPos, UINT32 uiWidth, UINT32 uiHeight); BOOLEAN Blt16BPPDataTo16BPPBufferTransparentClip( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect *clipregion); BOOLEAN Blt16BPPDataTo16BPPBufferTransZClip( UINT16 *pBuffer, UINT32 uiDestPitchBYTES, UINT16 *pZBuffer, UINT16 usZValue, HVOBJECT hSrcVObject, INT32 iX, INT32 iY, UINT16 usIndex, SGPRect *clipregion); diff --git a/Standard Gaming Platform/vsurface.cpp b/Standard Gaming Platform/vsurface.cpp index 06c308f1..1897d0a6 100644 --- a/Standard Gaming Platform/vsurface.cpp +++ b/Standard Gaming Platform/vsurface.cpp @@ -167,7 +167,7 @@ namespace SurfaceData SurfaceData::_surfaceOfData[data] = surfaceID; return data; } - THROWEXCEPTION(L"Unregistered surface ID"); + SGP_THROW(L"Unregistered surface ID"); } BYTE* SetSurfaceData(HVSURFACE surface, BYTE* data) { @@ -181,7 +181,7 @@ namespace SurfaceData return data; } } - THROWEXCEPTION(L"Unregistered surface"); + SGP_THROW(L"Unregistered surface"); } void ReleaseSurfaceData(tID surfaceID) { @@ -246,7 +246,8 @@ namespace SurfaceData { return it->second; } - THROWEXCEPTION(L"Pointer to surface invalid"); + //SGP_THROW(L"Pointer to surface invalid"); + return 0; } }; @@ -1035,9 +1036,20 @@ HVSURFACE CreateVideoSurface( VSURFACE_DESC *VSurfaceDesc ) // // Create himage object from file // + ImageFileType::TestOrder order = ImageFileType::JPC_FALLBACK; + if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMJPC) { + order = ImageFileType::JPC; + } if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMJPC_FALLBACK) { + order = ImageFileType::JPC_FALLBACK; + } if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMPNG) { + order = ImageFileType::PNG; + } if(VSurfaceDesc->fCreateFlags & VSURFACE_CREATE_FROMPNG_FALLBACK) { + order = ImageFileType::PNG_FALLBACK; + } - hImage = CreateImage( VSurfaceDesc->ImageFile, IMAGE_ALLIMAGEDATA ); - + SGP_THROW_IFFALSE(hImage = CreateImage( VSurfaceDesc->ImageFile, IMAGE_ALLIMAGEDATA, order ), + _BS(L"Could not create video surface from file : ") << vfs::String(VSurfaceDesc->ImageFile) << _BS::wget); + if ( hImage == NULL ) { DbgMessage( TOPIC_VIDEOSURFACE, DBG_LEVEL_2, "Invalid Image Filename given" ); diff --git a/Standard Gaming Platform/vsurface.h b/Standard Gaming Platform/vsurface.h index 54b17d51..b8c91125 100644 --- a/Standard Gaming Platform/vsurface.h +++ b/Standard Gaming Platform/vsurface.h @@ -54,18 +54,23 @@ typedef struct // Used to describe the memory usage of a video Surface // -#define VSURFACE_DEFAULT_MEM_USAGE 0x00000001 // Default mem usage is same as DD, try video and then try system. Will usually work -#define VSURFACE_VIDEO_MEM_USAGE 0x00000002 // Will force surface into video memory and will fail if it can't -#define VSURFACE_SYSTEM_MEM_USAGE 0x00000004 // Will force surface into system memory and will fail if it can't -#define VSURFACE_RESERVED_SURFACE 0x00000100 // Reserved for special purposes, like a primary surface +#define VSURFACE_DEFAULT_MEM_USAGE 0x00000001 // Default mem usage is same as DD, try video and then try system. Will usually work +#define VSURFACE_VIDEO_MEM_USAGE 0x00000002 // Will force surface into video memory and will fail if it can't +#define VSURFACE_SYSTEM_MEM_USAGE 0x00000004 // Will force surface into system memory and will fail if it can't +#define VSURFACE_RESERVED_SURFACE 0x00000100 // Reserved for special purposes, like a primary surface // // Video Surface creation flags // Used in the VSurface_DESC structure to describe creation flags // -#define VSURFACE_CREATE_DEFAULT 0x00000020 // Creates and empty Surface of given width, height and BPP -#define VSURFACE_CREATE_FROMFILE 0x00000040 // Creates a video Surface from a file ( using HIMAGE ) +#define VSURFACE_CREATE_DEFAULT 0x00000020 // Creates and empty Surface of given width, height and BPP +#define VSURFACE_CREATE_FROMFILE 0x00000040 // Creates a video Surface from a file ( using HIMAGE ) + +#define VSURFACE_CREATE_FROMJPC 0x00010000 // replace file extension : sti -> jpc.7z +#define VSURFACE_CREATE_FROMPNG 0x00020000 // replace file extension : sti -> png +#define VSURFACE_CREATE_FROMJPC_FALLBACK 0x00100000 // replace file extension : sti -> jpc.7z, fall back to sti when it doesn't exist +#define VSURFACE_CREATE_FROMPNG_FALLBACK 0x00200000 // replace file extension : sti -> png, fall back to sti when it doesn't exist // // The following structure is used to define a region of the video Surface diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index 1bf18042..8962cc8a 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -60,8 +60,12 @@ #include "history.h" #include "Map Screen Interface Map Inventory.h" #include "interface dialogue.h" + // added by SANDRO + #include "AIInternals.h" + #include "Morale.h" #endif #include +#include //forward declarations of common classes to eliminate includes class OBJECTTYPE; @@ -95,6 +99,9 @@ enum{ VEHICLE_MENU_VEHICLE1 = 0, VEHICLE_MENU_VEHICLE2, VEHICLE_MENU_VEHICLE3, + VEHICLE_MENU_VEHICLE4, // WANNE: Allow up to 6 vehicles + VEHICLE_MENU_VEHICLE5, + VEHICLE_MENU_VEHICLE6, VEHICLE_MENU_CANCEL, }; @@ -213,6 +220,16 @@ extern BOOLEAN fSelectedListOfMercsForMapScreen[ CODE_MAXIMUM_NUMBER_OF_PLAYER_S SOLDIERTYPE *gpDismissSoldier = NULL; +///////////////////////////////////////////////////////////////////// +// these added by SANDRO +SOLDIERTYPE *pAutomaticSurgeryDoctor; +SOLDIERTYPE *pAutomaticSurgeryPatient; +void SurgeryBeforeDoctoringRequesterCallback( UINT8 bExitValue ); +void SurgeryBeforePatientingRequesterCallback( UINT8 bExitValue ); +INT16 MakeAutomaticSurgeryOnAllPatients( SOLDIERTYPE * pDoctor ); +BOOLEAN MakeAutomaticSurgery( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pDoctor ); +///////////////////////////////////////////////////////////////////// + BOOLEAN gfReEvaluateEveryonesNothingToDo = FALSE; // HEADROCK HAM 3.6: Stored Facility worker (for callback purposes) @@ -427,8 +444,10 @@ INT8 GetRegainDueToSleepNeeded( SOLDIERTYPE *pSoldier, INT32 iRateOfReGain ); void PositionCursorForTacticalAssignmentBox( void ); // can this soldier be healed by this doctor? -BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, BOOLEAN fIgnoreAssignment, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck ); -UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck ); +// SANDRO - attention - a variable added to these 2 functions +BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, BOOLEAN fIgnoreAssignment, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck, BOOLEAN fCheckForSurgery ); +UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck, BOOLEAN fCheckForSurgery ); + void CheckForAndHandleHospitalPatients( void ); void HealHospitalPatient( SOLDIERTYPE *pPatient, UINT16 usHealingPtsLeft ); @@ -462,7 +481,7 @@ extern BOOLEAN SectorIsImpassable( INT16 sSector ); extern BOOLEAN CanChangeSleepStatusForCharSlot( INT8 bCharNumber ); -extern UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OBJECTTYPE *pKit, INT16 sKitPts, INT16 sStatus ); +extern UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OBJECTTYPE *pKit, INT16 sKitPts, INT16 sStatus, BOOLEAN fOnSurgery ); // variable added by SANDRO // only 2 trainers are allowed per sector, so this function counts the # in a guy's sector // HEADROCK HAM 3.6: Now takes an extra argument for Militia Type @@ -516,8 +535,21 @@ BOOLEAN IsSoldierCloseEnoughToADoctor( SOLDIERTYPE *pPatient ); void VerifyTownTrainingIsPaidFor( void ); #endif +/// Forward declarations for dynamic repair system. +/// They are only used in this file. - +/// Comparator function for priority_queue to determine the repair priority of an item. +struct RepairPriority; +/// Struct to store items to repair in +struct RepairItem; +// The data structure used for collecting repairable items +typedef std::priority_queue, RepairPriority> RepairQueue; +/// Gets the minimum durability of all items in an object stack +static INT16 GetMinimumStackDurability(const OBJECTTYPE* pObj); +/// Check if a gun is jammed +static BOOLEAN IsGunJammed(const OBJECTTYPE* pObj); +/// Collect items that need repairing and add them to the repair queue +static void CollectRepairableItems(const SOLDIERTYPE* pSoldier, RepairQueue& itemsToFix); void InitSectorsWithSoldiersList( void ) { @@ -1030,10 +1062,11 @@ BOOLEAN CanCharacterPatient( SOLDIERTYPE *pSoldier ) return ( FALSE ); } - // is character alive and not in perfect health? - if( ( pSoldier->stats.bLife <= 0 ) || ( pSoldier->stats.bLife == pSoldier->stats.bLifeMax ) ) + // SANDRO - changed a bit + // is character alive? + if( pSoldier->stats.bLife <= 0 ) { - // dead or in perfect health + // dead return ( FALSE ); } @@ -1062,6 +1095,16 @@ BOOLEAN CanCharacterPatient( SOLDIERTYPE *pSoldier ) } } + // SANDRO - added check if having damaged stat + for ( UINT8 i = 0; i < NUM_DAMAGABLE_STATS; i++) + { + if ( pSoldier->ubCriticalStatDamage[i] > 0 ) + return ( TRUE ); + } + // if we don't have damaged stat, look if we need healing + if ( pSoldier->stats.bLife == pSoldier->stats.bLifeMax ) + return( FALSE ); + // alive and can be healed return ( TRUE ); } @@ -1225,11 +1268,19 @@ BOOLEAN CanCharacterTrainMilitia( SOLDIERTYPE *pSoldier ) // Read BASE leadership usEffectiveLeadership = pSoldier->stats.bLeadership; + if ( gGameOptions.fNewTraitSystem ) // SANDRO - old/new traits + { + if (HAS_SKILL_TRAIT( pSoldier, TEACHING_NT )) + { + // bonus from Teaching trait + usEffectiveLeadership = (usEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 ); + } + } // Apply modifier for TEACHER trait, if that feature is activated - if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) + else if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) { // Modifier applied once for each TEACHING level. - for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING ); i++ ) + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING_OT ); i++ ) { // This is a percentage modifier. usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; @@ -1623,7 +1674,10 @@ BOOLEAN CanCharacterOnDuty( SOLDIERTYPE *pSoldier ) // enemies in sector if( NumEnemiesInSector( pSoldier->sSectorX, pSoldier->sSectorY ) > 0 ) { - return( TRUE ); + if( gGameExternalOptions.ubSkyriderHotLZ == 0 ) + return( FALSE ); + else + return( TRUE ); } } } @@ -2250,7 +2304,7 @@ UINT8 FindNumberInSectorWithAssignment( INT16 sX, INT16 sY, INT8 bAssignment ) return( bNumberOfPeople ); } -UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck ) +UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck, BOOLEAN fCheckForSurgery ) { int cnt; SOLDIERTYPE *pSoldier = MercPtrs[0], *pTeamSoldier = NULL; @@ -2263,7 +2317,7 @@ UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLE { if( pTeamSoldier->bActive ) { - if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, fThisHour, fSkipKitCheck, fSkipSkillCheck ) == TRUE ) + if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, fThisHour, fSkipKitCheck, fSkipSkillCheck, fCheckForSurgery ) == TRUE ) { // increment number of doctorable patients/doctors ubNumberOfPeople++; @@ -2289,7 +2343,7 @@ SOLDIERTYPE *AnyDoctorWhoCanHealThisPatient( SOLDIERTYPE *pPatient, BOOLEAN fThi // doctor? if( ( pTeamSoldier->bActive ) && ( pTeamSoldier->bAssignment == DOCTOR ) ) { - if( CanSoldierBeHealedByDoctor( pPatient, pTeamSoldier, FALSE, fThisHour, FALSE, FALSE ) == TRUE ) + if( CanSoldierBeHealedByDoctor( pPatient, pTeamSoldier, FALSE, fThisHour, FALSE, FALSE, FALSE ) == TRUE ) { // found one return( pTeamSoldier ); @@ -2337,7 +2391,34 @@ UINT16 CalculateHealingPointsForDoctor(SOLDIERTYPE *pDoctor, UINT16 *pusMaxPts, // calculate normal doctoring rate - what it would be if his stats were "normal" (ignoring drugs, fatigue, equipment condition) // and equipment was not a hindrance *pusMaxPts = ( pDoctor->stats.bMedical * (( pDoctor->stats.bDexterity + pDoctor->stats.bWisdom ) / 2 ) * (100 + ( 5 * pDoctor->stats.bExpLevel) ) ) / gGameExternalOptions.ubDoctoringRateDivisor; - *pusMaxPts = __max(0,*pusMaxPts+((*pusMaxPts * sSectorModifier)/100)); + *pusMaxPts = __max(0,*pusMaxPts); + + // SANDRO - New Doctor Trait + if ( gGameOptions.fNewTraitSystem ) + { + // make normal doctoring rate slower + usHealPts = usHealPts * (100 + gSkillTraitValues.bSpeedModifierDoctoring) / 100; + *pusMaxPts = *pusMaxPts * (100 + gSkillTraitValues.bSpeedModifierDoctoring) / 100; + + // But with doctor make it faster. + if (HAS_SKILL_TRAIT( pDoctor, DOCTOR_NT )) + { + usHealPts += usHealPts * gSkillTraitValues.usDODoctorAssignmentBonus * NUM_SKILL_TRAITS( pDoctor, DOCTOR_NT ) / 100; + *pusMaxPts += *pusMaxPts * gSkillTraitValues.usDODoctorAssignmentBonus * NUM_SKILL_TRAITS( pDoctor, DOCTOR_NT ) / 100; + } + // penalty for aggressive people + if ( gMercProfiles[ pDoctor->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + usHealPts -= usHealPts / 10; + *pusMaxPts -= *pusMaxPts / 10; + } + // bonus for phlegmatic people + else if ( gMercProfiles[ pDoctor->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC ) + { + usHealPts += usHealPts / 20; + *pusMaxPts += *pusMaxPts / 20; + } + } // adjust for fatigue ReducePointsForFatigue( pDoctor, &usHealPts ); @@ -2400,6 +2481,30 @@ UINT8 CalculateRepairPointsForRepairman(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts // and equipment was not a hindrance *pusMaxPts = ( pSoldier->stats.bMechanical * pSoldier->stats.bDexterity * (100 + ( 5 * pSoldier->stats.bExpLevel) ) ) / ( gGameExternalOptions.ubRepairRateDivisor * gGameExternalOptions.ubAssignmentUnitsPerDay ); + // SANDRO - Technician trait gives a good bonus to repair items + if ( gGameOptions.fNewTraitSystem ) + { + usRepairPts = usRepairPts * (100 - gSkillTraitValues.bSpeedModifierRepairing) / 100; + *pusMaxPts = *pusMaxPts * (100 - gSkillTraitValues.bSpeedModifierRepairing) / 100; + + if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ) ) + { + usRepairPts += usRepairPts * gSkillTraitValues.usTERepairSpeedBonus * (NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT )) / 100; + *pusMaxPts += *pusMaxPts * gSkillTraitValues.usTERepairSpeedBonus * (NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT )) / 100; + } + // Penalty for aggressive people + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + usRepairPts -= usRepairPts / 10; // -10% + *pusMaxPts -= *pusMaxPts / 10; + } + // Bonus for phlegmatic people + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC ) + { + usRepairPts += usRepairPts / 20; // +5% + *pusMaxPts += *pusMaxPts / 20; + } + } // adjust for fatigue ReducePointsForFatigue( pSoldier, &usRepairPts ); @@ -2438,7 +2543,6 @@ UINT8 CalculateRepairPointsForRepairman(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts // adjust for equipment usRepairPts = (usRepairPts * ubKitEffectiveness) / 100; - // return current repair pts return(( UINT8 )usRepairPts); } @@ -2534,6 +2638,7 @@ void UpdatePatientsWhoAreDoneHealing( void ) { INT32 cnt = 0; SOLDIERTYPE *pSoldier = NULL, *pTeamSoldier = NULL; + BOOLEAN fHasDamagedStat = FALSE; // added by SANDRO // set as first in list pSoldier = MercPtrs[0]; @@ -2546,7 +2651,14 @@ void UpdatePatientsWhoAreDoneHealing( void ) // patient who doesn't need healing if( ( pTeamSoldier->bAssignment == PATIENT ) &&( pTeamSoldier->stats.bLife == pTeamSoldier->stats.bLifeMax ) ) { - AssignmentDone( pTeamSoldier, TRUE, TRUE ); + // SANDRO - added check if we can help to heal lost stats to this one + for (UINT8 cnt = 0; cnt < NUM_DAMAGABLE_STATS; cnt++) + { + if (pTeamSoldier->ubCriticalStatDamage[cnt] > 0 ) + fHasDamagedStat = TRUE; + } + if (!fHasDamagedStat )// || !DoctorIsPresent( pTeamSoldier, TRUE )) + AssignmentDone( pTeamSoldier, TRUE, TRUE ); } } } @@ -2568,7 +2680,7 @@ void HealCharacters( SOLDIERTYPE *pDoctor, INT16 sX, INT16 sY, INT8 bZ ) // now find number of healable mercs in sector that are wounded - ubTotalNumberOfPatients = GetNumberThatCanBeDoctored( pDoctor, HEALABLE_THIS_HOUR, FALSE, FALSE ); + ubTotalNumberOfPatients = GetNumberThatCanBeDoctored( pDoctor, HEALABLE_THIS_HOUR, FALSE, FALSE, FALSE ); // if there is anybody who can be healed right now if( ubTotalNumberOfPatients > 0 ) @@ -2586,7 +2698,7 @@ void HealCharacters( SOLDIERTYPE *pDoctor, INT16 sX, INT16 sY, INT8 bZ ) { if( pTeamSoldier->bActive ) { - if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_THIS_HOUR, FALSE, FALSE ) == TRUE ) + if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_THIS_HOUR, FALSE, FALSE, FALSE ) == TRUE ) { // can heal and is patient, heal them usRemainingHealingPts -= HealPatient( pTeamSoldier, pDoctor, usEvenHealingAmount ); @@ -2608,7 +2720,7 @@ void HealCharacters( SOLDIERTYPE *pDoctor, INT16 sX, INT16 sY, INT8 bZ ) { if( pTeamSoldier->bActive ) { - if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_THIS_HOUR, FALSE, FALSE ) == TRUE ) + if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_THIS_HOUR, FALSE, FALSE, FALSE ) == TRUE ) { if( pWorstHurtSoldier == NULL ) { @@ -2653,18 +2765,18 @@ void HealCharacters( SOLDIERTYPE *pDoctor, INT16 sX, INT16 sY, INT8 bZ ) // if there's nobody else here who can EVER be helped by this doctor (regardless of whether they got healing this hour) - if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, FALSE, FALSE ) == 0 ) + if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, FALSE, FALSE, FALSE ) == 0 ) { // then this doctor has done all that he can do, but let's find out why and tell player the reason // try again, but skip the med kit check! - if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, TRUE, FALSE ) > 0 ) + if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, TRUE, FALSE, FALSE ) > 0 ) { // he could doctor somebody, but can't because he doesn't have a med kit! AssignmentAborted( pDoctor, NO_MORE_MED_KITS ); } // try again, but skip the skill check! - else if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, FALSE, TRUE ) > 0 ) + else if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, FALSE, TRUE, FALSE ) > 0 ) { // he could doctor somebody, but can't because he doesn't have enough skill! AssignmentAborted( pDoctor, INSUF_DOCTOR_SKILL ); @@ -2737,8 +2849,10 @@ BOOLEAN IsSoldierCloseEnoughToADoctor( SOLDIERTYPE *pPatient ) */ -BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, BOOLEAN fIgnoreAssignment, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck ) +BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, BOOLEAN fIgnoreAssignment, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck, BOOLEAN fCheckForSurgery ) { + // SANDRO - added check here, if we have damaged stat + BOOLEAN fHealDamagedStat = FALSE; // must be an active guy if (pSoldier->bActive == FALSE) @@ -2752,8 +2866,8 @@ BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, return(FALSE); } - // if dead or unhurt - if ( (pSoldier->stats.bLife == 0) || (pSoldier->stats.bLife == pSoldier->stats.bLifeMax ) ) + // if dead + if ( pSoldier->stats.bLife == 0) { return(FALSE); } @@ -2788,6 +2902,24 @@ BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, return( FALSE ); } + // check if having damaged stat + if ( gGameOptions.fNewTraitSystem && NUM_SKILL_TRAITS( pDoctor, DOCTOR_NT) > 0 && (NumberOfDamagedStats( pSoldier ) > 0)) + { + fHealDamagedStat = TRUE; + } + // added check for surgery + if ( !fHealDamagedStat && fCheckForSurgery && pSoldier->iHealableInjury < 100 ) // at least one life can be healed + { + // cannot be healed + return( FALSE ); + } + // if we have no damaged stat and don't need healing + if (!fHealDamagedStat && (pSoldier->stats.bLife == pSoldier->stats.bLifeMax) ) + { + // cannot be healed + return( FALSE ); + } + return( TRUE ); } @@ -2811,177 +2943,156 @@ UINT8 GetMinHealingSkillNeeded( SOLDIERTYPE *pPatient ) UINT16 HealPatient( SOLDIERTYPE *pPatient, SOLDIERTYPE * pDoctor, UINT16 usHundredthsHealed ) { - // heal patient and return the number of healing pts used + ////////////////////////////////////////////////////////////////////////////// + // SANDRO - this whole procedure was heavily changed + //////////////////////////////////////////////////// UINT16 usHealingPtsLeft; - UINT16 usTotalFullPtsUsed = 0; UINT16 usTotalHundredthsUsed = 0; - INT8 bPointsToUse = 0; - INT8 bPointsUsed = 0; + INT16 sPointsToUse = 0; INT8 bPointsHealed = 0; - INT8 bPocket = 0; INT8 bMedFactor; -// INT8 bOldPatientLife = pPatient->stats.bLife; + BOOLEAN fWillRepiarStats = FALSE; + BOOLEAN fWillHealLife = TRUE; + UINT16 usTotalMedPoints = 0; + UINT16 ubReturnDamagedStatRate = 0; + // Look how much life do we need to heal + sPointsToUse = ( pPatient->stats.bLifeMax - pPatient->stats.bLife ); + if ( sPointsToUse <= 0 ) + fWillHealLife = FALSE; + else if ( pPatient->stats.bLife < OKLIFE ) + sPointsToUse += ((OKLIFE - pPatient->stats.bLife )* gGameExternalOptions.ubPointCostPerHealthBelowOkLife); - pPatient->sFractLife += usHundredthsHealed; - usTotalHundredthsUsed = usHundredthsHealed; // we'll subtract any unused amount later if we become fully healed... - - // convert fractions into full points - usHealingPtsLeft = pPatient->sFractLife / 100; - pPatient->sFractLife %= 100; - - // if we haven't accumulated any full points yet - if (usHealingPtsLeft == 0) + // Look how much stats do we need to repair + if ( gGameOptions.fNewTraitSystem && ( NUM_SKILL_TRAITS( pDoctor, DOCTOR_NT ) > 0 ) && (NumberOfDamagedStats( pPatient ) > 0) ) { - return( usTotalHundredthsUsed ); + fWillRepiarStats = TRUE; + sPointsToUse += NumberOfDamagedStats( pPatient ); + + ubReturnDamagedStatRate = ((gSkillTraitValues.usDORepairStatsRateBasic + gSkillTraitValues.usDORepairStatsRateOnTop * NUM_SKILL_TRAITS( pDoctor, DOCTOR_NT ))); + // reduce rate if we are going to heal at the same time + if ( fWillHealLife ) + ubReturnDamagedStatRate -= ((ubReturnDamagedStatRate * gSkillTraitValues.ubDORepStPenaltyIfAlsoHealing ) / 100); } - -/* ARM - Eliminated. We now have other methods of properly using doctors to auto-bandage bleeding, -// using the correct kits points instead of this 1 pt. "special" - - // stop all bleeding of patient..for 1 pt (it's fast). But still use up normal kit pts to do it - if (pPatient->bBleeding > 0) + // Start + if ( sPointsToUse > 0 && ( fWillHealLife || fWillRepiarStats )) { - usHealingPtsLeft--; - usTotalFullPtsUsed++; - - // get points needed to heal him to dress bleeding wounds - bPointsToUse = pPatient->bBleeding; - - // go through doctor's pockets and heal, starting at with his in-hand item - // the healing pts are based on what type of medkit is in his hand, so we HAVE to start there first! - for (bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++) - { - bMedFactor = IsMedicalKitItem( &( pDoctor->inv[ bPocket ] ) ); - if ( bMedFactor > 0 ) - { - // ok, we have med kit in this pocket, use it - - // The medFactor here doesn't affect how much the doctor can heal (that's already factored into lower healing pts) - // but it does effect how fast the medkit is used up! First aid kits disappear at double their doctoring rate! - bPointsUsed = (INT8) UseKitPoints( &( pDoctor->inv[ bPocket ] ), (UINT16) (bPointsToUse * bMedFactor), pDoctor ); - bPointsHealed = bPointsUsed / bMedFactor; - - bPointsToUse -= bPointsHealed; - pPatient->bBleeding -= bPointsHealed; - - // if we're done all we're supposed to, or the guy's no longer bleeding, bail - if ( ( bPointsToUse <= 0 ) || ( pPatient->bBleeding == 0 ) ) - { - break; - } - } - } - } -*/ - - // if below ok life, heal these first at double point cost - if( pPatient->stats.bLife < OKLIFE ) - { - // get points needed to heal him to OKLIFE - bPointsToUse = gGameExternalOptions.ubPointCostPerHealthBelowOkLife * ( OKLIFE - pPatient->stats.bLife ); - - // if he needs more than we have, reduce to that - if( bPointsToUse > usHealingPtsLeft ) - { - bPointsToUse = ( INT8 )usHealingPtsLeft; - } - - // go through doctor's pockets and heal, starting at with his in-hand item - // the healing pts are based on what type of medkit is in his hand, so we HAVE to start there first! - // CHRISL: Changed to dynamically determine max inventory locations. - for (bPocket = HANDPOS; bPocket < NUM_INV_SLOTS; bPocket++) - { - bMedFactor = IsMedicalKitItem( &( pDoctor->inv[ bPocket ] ) ); - if ( bMedFactor > 0 ) - { - // ok, we have med kit in this pocket, use it - - // The medFactor here doesn't affect how much the doctor can heal (that's already factored into lower healing pts) - // but it does effect how fast the medkit is used up! First aid kits disappear at double their doctoring rate! - bPointsUsed = (INT8) UseKitPoints( &( pDoctor->inv[ bPocket ] ), (UINT16) (bPointsToUse * bMedFactor), pDoctor ); - bPointsHealed = bPointsUsed / bMedFactor; - - bPointsToUse -= bPointsHealed; - usHealingPtsLeft -= bPointsHealed; - usTotalFullPtsUsed += bPointsHealed; - - // heal person the amount / POINT_COST_PER_HEALTH_BELOW_OKLIFE - pPatient->stats.bLife += (bPointsHealed / gGameExternalOptions.ubPointCostPerHealthBelowOkLife); - - // if we're done all we're supposed to, or the guy's at OKLIFE, bail - if ( ( bPointsToUse <= 0 ) || ( pPatient->stats.bLife >= OKLIFE ) ) - { - break; - } - } - } - } - - // critical conditions handled, now apply normal healing - - if (pPatient->stats.bLife < pPatient->stats.bLifeMax) - { - bPointsToUse = ( pPatient->stats.bLifeMax - pPatient->stats.bLife ); + // here is our maximum, we can heal this time + usHealingPtsLeft = max( 1, ((pPatient->sFractLife + usHundredthsHealed) / 100)); // if guy is hurt more than points we have...heal only what we have - if( bPointsToUse > usHealingPtsLeft ) + if( sPointsToUse > usHealingPtsLeft ) { - bPointsToUse = ( INT8 )usHealingPtsLeft; + sPointsToUse = ( INT8 )usHealingPtsLeft; } - // go through doctor's pockets and heal, starting at with his in-hand item - // the healing pts are based on what type of medkit is in his hand, so we HAVE to start there first! - // CHRISL: Changed to dynamically determine max inventory locations. - for (bPocket = HANDPOS; bPocket < NUM_INV_SLOTS; bPocket++) + bMedFactor = 1; // basic medical factor + // if we will heal life and stats at the same time, increases the medical cost + if (fWillRepiarStats && fWillHealLife) { - bMedFactor = IsMedicalKitItem( &( pDoctor->inv[ bPocket ] ) ); - if ( bMedFactor > 0 ) + bMedFactor += 1; + } + // Added a penalty for not experienced mercs, they consume the bag faster + if ( gGameOptions.fNewTraitSystem && !HAS_SKILL_TRAIT( pDoctor, DOCTOR_NT ) && (pDoctor->stats.bMedical < 50) ) + { + bMedFactor += 1; + } + /*if ( pPatient->stats.bLife < OKLIFE ) + { + bMedFactor += 1; + }*/ + + // calculate how much total points we have in all medical bags + usTotalMedPoints = TotalMedicalKitPoints(pDoctor); + + // if having enough, no problem + if (usTotalMedPoints >= (sPointsToUse * bMedFactor)) + { + usTotalHundredthsUsed = sPointsToUse * 100; + usTotalMedPoints = (sPointsToUse * bMedFactor); + } + else + { + // only heal what we have + usTotalHundredthsUsed = (usTotalMedPoints * 100 / bMedFactor) ; + } + + // calculate points for healing life (it has priority) + if ( fWillHealLife ) + { + // if we haven't accumulated any full points yet + if ((pPatient->sFractLife + usTotalHundredthsUsed) < 100) { - // ok, we have med kit in this pocket, use it (use only half if it's worth double) - - // The medFactor here doesn't affect how much the doctor can heal (that's already factored into lower healing pts) - // but it does effect how fast the medkit is used up! First aid kits disappear at double their doctoring rate! - bPointsUsed = (INT8) UseKitPoints( &( pDoctor->inv[ bPocket ] ), (UINT16) (bPointsToUse * bMedFactor), pDoctor ); - bPointsHealed = bPointsUsed / bMedFactor; - - bPointsToUse -= bPointsHealed; - usHealingPtsLeft -= bPointsHealed; - usTotalFullPtsUsed += bPointsHealed; - - pPatient->stats.bLife += bPointsHealed; - - // if we're done all we're supposed to, or the guy's fully healed, bail - if ( ( bPointsToUse <= 0 ) || ( pPatient->stats.bLife == pPatient->stats.bLifeMax ) ) - { - break; - } + pPatient->sFractLife += usTotalHundredthsUsed; + fWillHealLife = FALSE; + } + // if we would heal more than we need + else if ( !fWillRepiarStats && (pPatient->stats.bLifeMax < pPatient->stats.bLife + bPointsHealed) ) + { + usHundredthsHealed = max( 1, (usHundredthsHealed - usTotalHundredthsUsed)); } } - } - - // if this patient is fully healed - if( pPatient->stats.bLife == pPatient->stats.bLifeMax ) - { - // don't count unused full healing points as being used - usTotalHundredthsUsed -= (100 * usHealingPtsLeft); - - // wipe out fractions of extra life, and DON'T count them as used - usTotalHundredthsUsed -= pPatient->sFractLife; - pPatient->sFractLife = 0; - -/* ARM Removed. This is duplicating the check in UpdatePatientsWhoAreDoneHealing(), guy would show up twice! - // if it isn't the doctor himself) - if( ( pPatient != pDoctor ) + // repair our stats here!! + if ( fWillRepiarStats && (ubReturnDamagedStatRate > 0) ) { - AssignmentDone( pPatient, TRUE, TRUE ); + // always at least one point if repairing stats only + if ( !fWillHealLife ) + bPointsHealed = max( 1, (usTotalHundredthsUsed / 100)); + else + bPointsHealed = (usTotalHundredthsUsed / 100); + + // reduce remaining points for upcoming healing + if ( RegainDamagedStats( pPatient, (bPointsHealed * ubReturnDamagedStatRate) ) != 0 ) + { + usTotalHundredthsUsed -= ((usTotalHundredthsUsed * gSkillTraitValues.ubDOHealingPenaltyIfAlsoStatRepair ) / 100); + } + } + + // if we are actually here to heal life + if ( fWillHealLife ) + { + pPatient->sFractLife += usTotalHundredthsUsed; + + bPointsHealed = 0; + if (pPatient->sFractLife >= 100 && pPatient->stats.bLife >= OKLIFE) + { + // convert fractions into full points + bPointsHealed = (pPatient->sFractLife / 100); + pPatient->sFractLife %= 100; + + pPatient->stats.bLife = min( pPatient->stats.bLifeMax, (pPatient->stats.bLife + bPointsHealed)); + } + else if (((pPatient->sFractLife / gGameExternalOptions.ubPointCostPerHealthBelowOkLife) >= 100) && (pPatient->stats.bLife < OKLIFE)) + { + bPointsHealed = ((pPatient->sFractLife / gGameExternalOptions.ubPointCostPerHealthBelowOkLife) / 100); + pPatient->sFractLife %= 100; + + pPatient->stats.bLife = min( pPatient->stats.bLifeMax, (pPatient->stats.bLife + bPointsHealed)); + } + + // when being healed normally, reduce insta-healable HPs value + if ( pPatient->iHealableInjury > 0 && bPointsHealed > 0 ) + { + pPatient->iHealableInjury -= (bPointsHealed * 100); + if (pPatient->iHealableInjury < 0) + pPatient->iHealableInjury = 0; + } + + } + + // Finaly use all kit points (we are sure, we have that much) + if (UseTotalMedicalKitPoints( pDoctor, usTotalMedPoints ) == FALSE ) + { + // throw message if this went wrong for feedback on debugging +#ifdef JA2TESTVERSION + ScreenMsg( FONT_MCOLOR_RED, MSG_TESTVERSION, L"Warning! UseTotalKitPOints returned false, not all points were probably used." ); +#endif } -*/ } - return ( usTotalHundredthsUsed ); + return ( usHundredthsHealed ); } @@ -3051,6 +3162,14 @@ void HealHospitalPatient( SOLDIERTYPE *pPatient, UINT16 usHealingPtsLeft ) // heal person the amount / POINT_COST_PER_HEALTH_BELOW_OKLIFE pPatient->stats.bLife += ( bPointsToUse / gGameExternalOptions.ubPointCostPerHealthBelowOkLife ); + + // SANDRO - doctor trait - when being healed normally, reduce insta-healable HPs value + if ( gGameOptions.fNewTraitSystem && pPatient->iHealableInjury > 0 ) + { + pPatient->iHealableInjury -= (bPointsToUse / gGameExternalOptions.ubPointCostPerHealthBelowOkLife * 100); + if (pPatient->iHealableInjury < 0) + pPatient->iHealableInjury = 0; + } } // critical condition handled, now solve normal healing @@ -3069,6 +3188,14 @@ void HealHospitalPatient( SOLDIERTYPE *pPatient, UINT16 usHealingPtsLeft ) // heal person the amount pPatient->stats.bLife += bPointsToUse; + + // SANDRO - doctor trait - when being healed normally, reduce insta-healable HPs value + if ( gGameOptions.fNewTraitSystem && pPatient->iHealableInjury > 0 ) + { + pPatient->iHealableInjury -= (bPointsToUse * 100); + if (pPatient->iHealableInjury < 0) + pPatient->iHealableInjury = 0; + } } // if this patient is fully healed @@ -3170,7 +3297,115 @@ INT8 HandleRepairOfSAMSite( SOLDIERTYPE *pSoldier, INT8 bPointsAvailable, BOOLEA } */ +struct RepairItem { + const OBJECTTYPE* item; + const SOLDIERTYPE* owner; + INVENTORY_SLOT inventorySlot; + RepairItem (const OBJECTTYPE* object, const SOLDIERTYPE* soldier, INVENTORY_SLOT slot) : + item(object), owner(soldier), inventorySlot(slot) {} +}; + +struct RepairPriority : std::binary_function { + /// Comperator function + bool operator() (const RepairItem& firstItem, const RepairItem& secondItem) const { + UINT8 priFirst = CalculateItemPriority(firstItem), + priSecond = CalculateItemPriority(secondItem); + + // Both items have the same priority, prefer the item with less durability + if (priFirst == priSecond) { + INT16 durabilityFirst = GetMinimumStackDurability(firstItem.item), + durabilitySecond = GetMinimumStackDurability(secondItem.item); + + // Sort by durability in ascending order + return durabilityFirst > durabilitySecond; + } + else + // Sort by priority in descending order + return priFirst < priSecond; + } + + /// Calculate an item's priority + /// + /// LBE: 0 + /// Items: 1 + /// Armor: 2 + /// Face items: 3 + /// Weapons: 4 + /// Equipped armor: 5 + /// Equipped weapons: 6 + private: UINT8 CalculateItemPriority(const RepairItem& object) const { + + UINT32 itemClass = Item[object.item->usItem].usItemClass; + // Default priority + UINT8 priority = 1; + + // Set base priority + if ( itemClass == IC_LBEGEAR ) + priority = 0; + else if ( itemClass == IC_ARMOUR ) + priority = 2; + else if ( itemClass == IC_FACE ) + priority = 3; + else if ( IsWeapon(object.item->usItem) ) + priority = 4; + + // Set priority based on equip slot + if ((itemClass == IC_ARMOUR) && (object.inventorySlot == HELMETPOS || object.inventorySlot == VESTPOS || object.inventorySlot == LEGPOS)) + priority = 5; + if ((IsWeapon(object.item->usItem)) && (object.inventorySlot == HANDPOS || object.inventorySlot == SECONDHANDPOS)) + priority = 6; + + // Set priority for jammed weapons; those weapons should always be highest priority + if (IsGunJammed(object.item)) + priority = 100; + + return priority; + } +}; + +static INT16 GetMinimumStackDurability(const OBJECTTYPE* pObj) { + INT16 minDur = 100; + for (UINT8 stackIndex = 0; stackIndex < pObj->ubNumberOfObjects; ++stackIndex) { + INT16 durability = (*pObj)[stackIndex]->data.objectStatus; + + if (durability < minDur) + minDur = durability; + } + + return minDur; +} + +static void CollectRepairableItems(const SOLDIERTYPE* pSoldier, RepairQueue& itemsToFix) { + // Iterate over all pocket slots and add items in need of repair + for (UINT8 pocketIndex = HELMETPOS; pocketIndex < NUM_INV_SLOTS; ++pocketIndex) { + const OBJECTTYPE* pObj = &(const_cast(pSoldier)->inv[pocketIndex]); + + // Check if item needs repairing + BOOLEAN itemAddedToQueue = FALSE; + for (UINT8 stackIndex = 0; stackIndex < pObj->ubNumberOfObjects; ++stackIndex) { + // Check the stack item itself + if (!itemAddedToQueue && IsItemRepairable(pObj->usItem, (*pObj)[stackIndex]->data.objectStatus)) { + itemAddedToQueue = TRUE; + RepairItem item(pObj, pSoldier, (INVENTORY_SLOT) pocketIndex); + itemsToFix.push(item); + } + + // Check for attachments (are there stackable items that can take attachments though?) + UINT8 attachmentIndex = 0; + for (attachmentList::const_iterator iter = (*pObj)[stackIndex]->attachments.begin(); iter != (*pObj)[stackIndex]->attachments.end(); ++iter, ++attachmentIndex) { + if (IsItemRepairable(iter->usItem, (*iter)[attachmentIndex]->data.objectStatus )) { + RepairItem item(&(*iter), pSoldier, (INVENTORY_SLOT) pocketIndex); + itemsToFix.push(item); + } + } + } + } +} + +static BOOLEAN IsGunJammed(const OBJECTTYPE* pObj) { + return (Item[pObj->usItem].usItemClass == IC_GUN) && ((*pObj)[0]->data.gun.bGunAmmoStatus < 0); +} OBJECTTYPE* FindRepairableItemOnOtherSoldier( SOLDIERTYPE * pSoldier, UINT8 ubPassType ) { @@ -3258,7 +3493,7 @@ OBJECTTYPE* FindRepairableItemInSpecificPocket( OBJECTTYPE * pObj, UINT8 subObje // have to check for attachments after... for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) { // if it's repairable and NEEDS repairing - if ( IsItemRepairable( iter->usItem, (*iter)[subObject]->data.objectStatus ) ) { + if ( IsItemRepairable( iter->usItem, (*iter)[subObject]->data.objectStatus ) && iter->exists() ) { return( &(*iter) ); } } @@ -3286,10 +3521,18 @@ void DoActualRepair( SOLDIERTYPE * pSoldier, UINT16 usItem, INT16 * pbStatus, UI } // repairs on electronic items take twice as long if the guy doesn't have the skill -// if ( ( Item[ usItem ].fFlags & ITEM_ELECTRONIC ) && ( !( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS ) ) ) ) - if ( ( Item[ usItem ].electronic ) && ( !( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS ) ) ) ) + // Technician/Electronic traits - repairing electronic items - SANDRO + if ( Item[ usItem ].electronic ) { - sRepairCostAdj *= 2; + if (gGameOptions.fNewTraitSystem) + { + if (HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + sRepairCostAdj += (150 * max( 0, ((100 - gSkillTraitValues.ubTERepairElectronicsPenaltyReduction * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ))/100))); + else + sRepairCostAdj += 150; + } + else if ( !HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT ) ) + sRepairCostAdj *= 2; // +100% cost } // how many points of damage is the item down by? @@ -3331,7 +3574,7 @@ void DoActualRepair( SOLDIERTYPE * pSoldier, UINT16 usItem, INT16 * pbStatus, UI BOOLEAN RepairObject( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOwner, OBJECTTYPE * pObj, UINT8 * pubRepairPtsLeft ) { - UINT8 ubLoop, ubItemsInPocket, lbeLoop; + UINT8 ubLoop, ubItemsInPocket, lbeLoop, ubBeforeRepair; // added by SANDRO BOOLEAN fSomethingWasRepaired = FALSE; @@ -3342,9 +3585,26 @@ BOOLEAN RepairObject( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOwner, OBJECTTYPE * // if it's repairable and NEEDS repairing if ( IsItemRepairable( pObj->usItem, (*pObj)[ubLoop]->data.objectStatus ) ) { + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records, num items repaired + // Actually we check if we repaired at least 5% of status, otherwise the item is not considered broken + ubBeforeRepair = (UINT8)((*pObj)[ubLoop]->data.objectStatus); // repairable, try to repair it DoActualRepair( pSoldier, pObj->usItem, &((*pObj)[ubLoop]->data.objectStatus), pubRepairPtsLeft ); + // if the item was repaired to full status and the repair wa at least 5%, add a point + if ( (*pObj)[ubLoop]->data.objectStatus == 100 && (((*pObj)[ubLoop]->data.objectStatus - ubBeforeRepair) > 4 )) + { + gMercProfiles[ pSoldier->ubProfile ].records.usItemsRepaired++; + } + // if the item was now repaired to a status of 96-99 and the repair was at least 2%, add a point, consider the item repaired (no points will be awarded for it anyway) + else if ( (*pObj)[ubLoop]->data.objectStatus > 95 && (*pObj)[ubLoop]->data.objectStatus < 100 && ((*pObj)[ubLoop]->data.objectStatus - ubBeforeRepair) > 1) + { + gMercProfiles[ pSoldier->ubProfile ].records.usItemsRepaired++; + } + // note: this system is bad if we can repair only 1% per hour (which is rather we are total losers) + /////////////////////////////////////////////////////////////////////////////////////////////////////// + fSomethingWasRepaired = true; if ( (*pObj)[ubLoop]->data.objectStatus == 100 ) @@ -3369,7 +3629,7 @@ BOOLEAN RepairObject( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOwner, OBJECTTYPE * } // now check for attachments after for (attachmentList::iterator iter = (*pObj)[ubLoop]->attachments.begin(); iter != (*pObj)[ubLoop]->attachments.end(); ++iter) { - if (RepairObject(pSoldier, pOwner, &(*iter), pubRepairPtsLeft)) { + if (RepairObject(pSoldier, pOwner, &(*iter), pubRepairPtsLeft) && iter->exists()) { fSomethingWasRepaired = true; if ( *pubRepairPtsLeft == 0 ) { @@ -3407,15 +3667,9 @@ void HandleRepairBySoldier( SOLDIERTYPE *pSoldier ) UINT8 ubRepairPtsLeft =0; UINT8 ubInitialRepairPts = 0; UINT8 ubRepairPtsUsed = 0; - INT8 bPocket =0; BOOLEAN fNothingLeftToRepair = FALSE; - INT8 bLoop, bLoopStart, bLoopEnd; - BOOLEAN fAnyOfSoldiersOwnItemsWereFixed = FALSE; - OBJECTTYPE * pObj; - UINT16 usKitDegrade = 100; - // grab max number of repair pts open to this soldier ubRepairPtsLeft = CalculateRepairPointsForRepairman( pSoldier, &usMax, TRUE ); @@ -3444,14 +3698,32 @@ void HandleRepairBySoldier( SOLDIERTYPE *pSoldier ) if ( CanCharacterRepairRobot( pSoldier ) ) { // repairing the robot is very slow & difficult - ubRepairPtsLeft /= 2; - ubInitialRepairPts /= 2; - if( !( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS ) ) ) + // Check for new robot-repair system for Technicians - SANDRO + if (gGameOptions.fNewTraitSystem) + { + if (HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + { + ubRepairPtsLeft = (ubRepairPtsLeft * (100 - (80 * ( 100 - gSkillTraitValues.ubTERepairRobotPenaltyReduction * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ))/100))/100); + ubInitialRepairPts = (ubInitialRepairPts * (100 - (80 * ( 100 - gSkillTraitValues.ubTERepairRobotPenaltyReduction * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ))/100))/100); + } + else + { + ubRepairPtsLeft = ((ubRepairPtsLeft * 20 )/100); + ubInitialRepairPts = ((ubInitialRepairPts * 20 )/100); + } + } + else if ( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT ) ) { ubRepairPtsLeft /= 2; ubInitialRepairPts /= 2; } + else + { + // original value (just moved here) + ubRepairPtsLeft /= 4; + ubInitialRepairPts /= 4; + } // robot ubRepairPtsLeft -= HandleRepairOfRobotBySoldier( pSoldier, ubRepairPtsLeft, &fNothingLeftToRepair ); @@ -3459,83 +3731,151 @@ void HandleRepairBySoldier( SOLDIERTYPE *pSoldier ) } else { - fAnyOfSoldiersOwnItemsWereFixed = UnjamGunsOnSoldier( pSoldier, pSoldier, &ubRepairPtsLeft ); - - // repair items on self - // HEADROCK HAM B2.8: Experimental feature: Fixes LBEs last, as they don't actually require repairs. - for( bLoop = 0; bLoop < 4; bLoop++ ) + if (gGameExternalOptions.fAdditionalRepairMode) { - if ( bLoop == 0 ) + // 2Points: Use new repair algorithm + // Collect all items in need of repair and assign them priorities + RepairQueue itemsToFix; + + CollectRepairableItems(pSoldier, itemsToFix); + for(UINT8 teamIndex = gTacticalStatus.Team[gbPlayerNum].bFirstID; teamIndex < gTacticalStatus.Team[gbPlayerNum].bLastID; ++teamIndex) { - bLoopStart = SECONDHANDPOS; - // HEADROCK: New loop stage only checks second hand, to avoid LBEs. - bLoopEnd = SECONDHANDPOS; + // Ignore self, mercs in other sectors, etc. + if (CanCharacterRepairAnotherSoldiersStuff(pSoldier, MercPtrs[teamIndex])) + CollectRepairableItems(MercPtrs[teamIndex], itemsToFix); } - else if ( bLoop == 1 ) + + // Step through items, starting with the highest priority item + while (!itemsToFix.empty() && ubRepairPtsLeft > 0) { - // HEADROCK: Second check is for armor and headgear only. - bLoopStart = HELMETPOS; - bLoopEnd = HEAD2POS; - } - else if ( bLoop == 2 ) - { - // HEADROCK: Loop stage altered to run through inventory only - bLoopStart = UsingNewInventorySystem() == false ? BIGPOCKSTART : GUNSLINGPOCKPOS; - // CHRISL: Changed to dynamically determine max inventory locations. - bLoopEnd = (NUM_INV_SLOTS - 1); - } - else if ( bLoop == 3 ) - { - if (UsingNewInventorySystem() == true) + const RepairItem object = itemsToFix.top(); + itemsToFix.pop(); + + // Jammed gun; call unjam function first + if ( IsGunJammed(object.item) ) + UnjamGunsOnSoldier(const_cast (object.owner), pSoldier, &ubRepairPtsLeft); + + // Regular repair function + BOOLEAN itemRepaired = RepairObject( pSoldier, const_cast (object.owner), const_cast (object.item), &ubRepairPtsLeft ); + +#ifdef _DEBUG + if (itemRepaired) + ScreenMsg(FONT_ORANGE, MSG_BETAVERSION, L"Repaired: %s's %s in item slot %d [Dur: %d]. %d points left.", + object.owner->name, Item[object.item->usItem].szItemName, object.inventorySlot, GetMinimumStackDurability(object.item), ubRepairPtsLeft); +#endif + + // The following assumes that weapon/armor has higher priority than regular items! If the priorities are changed, this notification + // probably won't work reliably anymore. + + // The item has been repaired completely + if (GetMinimumStackDurability(object.item) == 100) { - // HEADROCK: Last loop fixes LBEs - bLoopStart = VESTPOCKPOS; - bLoopEnd = BPACKPOCKPOS; + // No items left in queue: All items have been repaired + if (itemsToFix.empty()) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, sRepairsDoneString[ 3 ], pSoldier->name ); + else { + // The current item was a weapon/armor + if ( (IsWeapon(object.item->usItem) || Item[object.item->usItem].usItemClass == IC_ARMOUR) && + // ...and the next item isn't: + (!IsWeapon(itemsToFix.top().item->usItem) && Item[itemsToFix.top().item->usItem].usItemClass != IC_ARMOUR) ) + { + + // All weapons & armor have been repaired + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, sRepairsDoneString[ 1 ], pSoldier->name ); + StopTimeCompression(); + } + } } - else + } + } + else + { + // Old repair algorithm + + INT8 bPocket =0; + BOOLEAN fNothingLeftToRepair = FALSE; + INT8 bLoop, bLoopStart, bLoopEnd; + BOOLEAN fAnyOfSoldiersOwnItemsWereFixed = FALSE; + OBJECTTYPE * pObj; + + fAnyOfSoldiersOwnItemsWereFixed = UnjamGunsOnSoldier( pSoldier, pSoldier, &ubRepairPtsLeft ); + + // repair items on self + // HEADROCK HAM B2.8: Experimental feature: Fixes LBEs last, as they don't actually require repairs. + for( bLoop = 0; bLoop < 4; bLoop++ ) + { + if ( bLoop == 0 ) { - // HEADROCK: In OIV, simply check everything again. bLoopStart = SECONDHANDPOS; + // HEADROCK: New loop stage only checks second hand, to avoid LBEs. + bLoopEnd = SECONDHANDPOS; + } + else if ( bLoop == 1 ) + { + // HEADROCK: Second check is for armor and headgear only. + bLoopStart = HELMETPOS; + bLoopEnd = HEAD2POS; + } + else if ( bLoop == 2 ) + { + // HEADROCK: Loop stage altered to run through inventory only + bLoopStart = UsingNewInventorySystem() == false ? BIGPOCKSTART : GUNSLINGPOCKPOS; + // CHRISL: Changed to dynamically determine max inventory locations. bLoopEnd = (NUM_INV_SLOTS - 1); } - } - - // now repair objects running from left hand to small pocket - for( bPocket = bLoopStart; bPocket <= bLoopEnd; bPocket++ ) - { - //CHRISL: These two conditions allow us to repair LBE pocket items at the same time as worn armor, while - // still letting us repair the item in our offhand first. - // HEADROCK HAM B2.8: No longer necessary, as I've artificially added new stages for this. LBE - // pockets are now repaired LAST. - //if(UsingNewInventorySystem() == true && bLoop == 0 && bPocket>SECONDHANDPOS && bPocketinv[ bPocket ]); - - if ( RepairObject( pSoldier, pSoldier, pObj, &ubRepairPtsLeft ) ) + else if ( bLoop == 3 ) { - fAnyOfSoldiersOwnItemsWereFixed = TRUE; + if (UsingNewInventorySystem() == true) + { + // HEADROCK: Last loop fixes LBEs + bLoopStart = VESTPOCKPOS; + bLoopEnd = BPACKPOCKPOS; + } + else + { + // HEADROCK: In OIV, simply check everything again. + bLoopStart = SECONDHANDPOS; + bLoopEnd = (NUM_INV_SLOTS - 1); + } + } - // quit looking if we're already out - if ( ubRepairPtsLeft == 0 ) - break; + // now repair objects running from left hand to small pocket + for( bPocket = bLoopStart; bPocket <= bLoopEnd; bPocket++ ) + { + //CHRISL: These two conditions allow us to repair LBE pocket items at the same time as worn armor, while + // still letting us repair the item in our offhand first. + // HEADROCK HAM B2.8: No longer necessary, as I've artificially added new stages for this. LBE + // pockets are now repaired LAST. + //if(UsingNewInventorySystem() == true && bLoop == 0 && bPocket>SECONDHANDPOS && bPocketinv[ bPocket ]); + + if ( RepairObject( pSoldier, pSoldier, pObj, &ubRepairPtsLeft ) ) + { + fAnyOfSoldiersOwnItemsWereFixed = TRUE; + + // quit looking if we're already out + if ( ubRepairPtsLeft == 0 ) + break; + } } } + + // if he fixed something of his, and now has no more of his own items to fix + if ( fAnyOfSoldiersOwnItemsWereFixed && !DoesCharacterHaveAnyItemsToRepair( pSoldier, -1 ) ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, sRepairsDoneString[ 0 ], pSoldier->name ); + + // let player react + StopTimeCompression(); + } + + + // repair items on others + RepairItemsOnOthers( pSoldier, &ubRepairPtsLeft ); } - - // if he fixed something of his, and now has no more of his own items to fix - if ( fAnyOfSoldiersOwnItemsWereFixed && !DoesCharacterHaveAnyItemsToRepair( pSoldier, -1 ) ) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, sRepairsDoneString[ 0 ], pSoldier->name ); - - // let player react - StopTimeCompression(); - } - - - // repair items on others - RepairItemsOnOthers( pSoldier, &ubRepairPtsLeft ); } // what are the total amount of pts used by character? @@ -3665,13 +4005,26 @@ void RestCharacter( SOLDIERTYPE *pSoldier ) // Night ops specialists sleep better during the day. Others sleep better during the night. if (NightTime()) { - bDivisor += 4-(2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS )); + if ( gGameOptions.fNewTraitSystem ) // SANDRO - Old/New traits + { + if ( !HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ) ) + bDivisor += 3; + } + else + bDivisor += 4-(2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT )); } else { - bDivisor += (2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS )); + if ( gGameOptions.fNewTraitSystem ) // SANDRO - Old/New traits + { + if ( HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ) ) + bDivisor += 3; + } + else + bDivisor += (2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT )); } + // Re-enforce limits bDivisor = __min(18, __max(4, bDivisor)); @@ -3736,8 +4089,10 @@ void FatigueCharacter( SOLDIERTYPE *pSoldier ) // fatigue character INT32 iPercentEncumbrance; INT32 iBreathLoss; - INT8 bMaxBreathLoss = 0, bDivisor = 1; + INT8 bDivisor = 1; INT16 sSectorModifier = 100; + float bMaxBreathLoss = 0; // SANDRO - changed to float + INT8 bMaxBreathTaken = 0; // vehicle or robot? @@ -3766,17 +4121,30 @@ void FatigueCharacter( SOLDIERTYPE *pSoldier ) // Night ops specialists tire faster during the day. Others tire faster during the night. if (NightTime()) { - bDivisor -= 4-(2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS )); + if ( gGameOptions.fNewTraitSystem ) // SANDRO - Old/New traits + { + if ( !HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ) ) + bDivisor -= 3; + } + else + bDivisor -= 4-(2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT )); } else { - bDivisor -= (2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS )); + if ( gGameOptions.fNewTraitSystem ) // SANDRO - Old/New traits + { + if ( HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ) ) + bDivisor -= 3; + } + else + bDivisor -= (2*NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT )); } + // Re-enforce limits bDivisor = __min(20, __max(6, bDivisor)); - bMaxBreathLoss = 50 / bDivisor; + bMaxBreathLoss = (float)(50 / bDivisor); // HEADROCK HAM 3.6: And make sure we allow no more than 18 hours of straight // work. (Actually, 16, but who's counting) @@ -3792,8 +4160,8 @@ void FatigueCharacter( SOLDIERTYPE *pSoldier ) iPercentEncumbrance = CalculateCarriedWeight( pSoldier ); if( iPercentEncumbrance > 100 ) { - iBreathLoss = (bMaxBreathLoss * iPercentEncumbrance / 100); - bMaxBreathLoss = (INT8)min( 127, iBreathLoss ); + iBreathLoss = (INT32)(bMaxBreathLoss * iPercentEncumbrance / 100); + bMaxBreathLoss = (float)min( 127, iBreathLoss ); } } @@ -3804,6 +4172,63 @@ void FatigueCharacter( SOLDIERTYPE *pSoldier ) bMaxBreathLoss = ( bMaxBreathLoss * 3 / 2 ); } + // SANDRO - STOMP traits + if( gGameOptions.fNewTraitSystem ) + { + // bonus for ranger travelling between sectors + if ( pSoldier->flags.fBetweenSectors && HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + { + bMaxBreathLoss = (bMaxBreathLoss * (100 - gSkillTraitValues.ubRABreathForTravellingReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ) ) / 100); + } + // primitive people get exhausted slower + if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_PRIMITIVE ) + { + switch ( pSoldier->bAssignment ) + { + case DOCTOR: + case REPAIR: + case TRAIN_TEAMMATE: + case TRAIN_TOWN: + break; + case TRAIN_BY_OTHER: + case TRAIN_SELF: + switch (pSoldier->bTrainStat) + { + case LEADERSHIP: + case MECHANICAL: + case MEDICAL: + case EXPLOSIVE_ASSIGN: + break; + default: + bMaxBreathLoss = (bMaxBreathLoss * 9 / 10); + break; + } + break; + default: + bMaxBreathLoss = (bMaxBreathLoss * 9 / 10); + break; + } + } + // Picifist actually gain morale, when on peaceful assignments + else if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_PACIFIST ) + { + switch ( pSoldier->bAssignment ) + { + case DOCTOR: + case REPAIR: + case TRAIN_TEAMMATE: + if ( Chance( 60 ) ) + HandleMoraleEvent( pSoldier, MORALE_PACIFIST_GAIN_NONCOMBAT, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); + break; + case TRAIN_BY_OTHER: + case TRAIN_SELF: + if ( Chance( 20 ) ) + HandleMoraleEvent( pSoldier, MORALE_PACIFIST_GAIN_NONCOMBAT, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); + break; + } + } + } + // HEADROCK HAM 3.5: Read adjustment from local sector facilities if (pSoldier->bSectorZ == 0) { @@ -3811,8 +4236,23 @@ void FatigueCharacter( SOLDIERTYPE *pSoldier ) bMaxBreathLoss = (bMaxBreathLoss * sSectorModifier) / 100; } - - pSoldier->bBreathMax -= bMaxBreathLoss; + ///////////////////////////////////// + // SANDRO + if (bMaxBreathLoss <= 0 ) + { + bMaxBreathLoss = 0; + } + // if breath loss is lower than one, handle it as a chance + else //if( bMaxBreathLoss < 1 ) + { + bMaxBreathTaken = (INT8)(bMaxBreathLoss); + bMaxBreathLoss = bMaxBreathLoss * 100; + bMaxBreathLoss = (float)(((INT32)(bMaxBreathLoss)) % 100); + if (Chance( (UINT32)(bMaxBreathLoss) ) ) + bMaxBreathTaken += 1; + } + pSoldier->bBreathMax -= bMaxBreathTaken; + ///////////////////////////////////// if( pSoldier->bBreathMax > 100 ) { @@ -4191,37 +4631,61 @@ INT16 GetBonusTrainingPtsDueToInstructor( SOLDIERTYPE *pInstructor, SOLDIERTYPE // check to see if student better than/equal to instructor's effective skill, if so, return 0 // don't use natural skill - if the guy's too doped up to tell what he know, student learns nothing until sobriety returns! - if( bTraineeSkill >= bTrainerEffSkill ) + ///////////////////////////////////////////////////////////////////////// + // SANDRO - Teaching Skill now increases the effective skill to determine if we can instruct other mercs + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pInstructor, TEACHING_NT )) + { + if( bTraineeSkill >= (bTrainerEffSkill + gSkillTraitValues.ubTGEffectiveSkillValueForTeaching) ) + return ( 0 ); + } + else if( bTraineeSkill >= bTrainerEffSkill ) { return ( 0 ); } - // calculate effective training pts - sTrainingPts = ( bTrainerEffSkill - bTraineeSkill ) * ( bTraineeEffWisdom + ( EffectiveWisdom( pInstructor ) + EffectiveLeadership( pInstructor ) ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor; - - // calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue) - *pusMaxPts = ( bTrainerNatSkill - bTraineeSkill ) * ( bTraineeNatWisdom + ( pInstructor->stats.bWisdom + pInstructor->stats.bLeadership ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor; - - // put in a minimum (that can be reduced due to instructor being tired?) - if (*pusMaxPts == 0) + // old/new teaching trait behaviour - SANDRO + if( gGameOptions.fNewTraitSystem ) { - // we know trainer is better than trainee, make sure they are at least 10 pts better - if ( bTrainerEffSkill > bTraineeSkill + 10 ) + // SANDRO - make difference between stats min 10, so if teaching trait is in place and instructor has lesser stat than trainee, the value doesn't go negative + // calculate effective training pts + sTrainingPts = max( 10, ( bTrainerEffSkill - bTraineeSkill )) * ( bTraineeEffWisdom + ( EffectiveWisdom( pInstructor ) + EffectiveLeadership( pInstructor ) ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor; + // calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue) + *pusMaxPts = max( 10, ( bTrainerNatSkill - bTraineeSkill )) * ( bTraineeNatWisdom + ( pInstructor->stats.bWisdom + pInstructor->stats.bLeadership ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor; + + // penalty for non-specialized mercs + bTrainingBonus = bTrainingBonus * (100 - gSkillTraitValues.bSpeedModifierTeachingOthers) / 100; + + // check for teaching skill bonuses + if ( HAS_SKILL_TRAIT( pInstructor, TEACHING_NT) ) { - sTrainingPts = 1; - *pusMaxPts = 1; + bTrainingBonus += gSkillTraitValues.ubTGBonusToTeachOtherMercs; } } + else + { + // calculate effective training pts + sTrainingPts = ( bTrainerEffSkill - bTraineeSkill ) * ( bTraineeEffWisdom + ( EffectiveWisdom( pInstructor ) + EffectiveLeadership( pInstructor ) ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor; + // calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue) + *pusMaxPts = ( bTrainerNatSkill - bTraineeSkill ) * ( bTraineeNatWisdom + ( pInstructor->stats.bWisdom + pInstructor->stats.bLeadership ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor; - // check for teaching skill bonuses - if( gMercProfiles[ pInstructor->ubProfile ].bSkillTrait == TEACHING ) - { - bTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain; - } - if( gMercProfiles[ pInstructor->ubProfile ].bSkillTrait2 == TEACHING ) - { - bTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain; + // put in a minimum (that can be reduced due to instructor being tired?) + if (*pusMaxPts <= 0) // stay safe + { + // we know trainer is better than trainee, make sure they are at least 10 pts better + if ( bTrainerEffSkill > bTraineeSkill + 10 ) + { + sTrainingPts = 1; + *pusMaxPts = 1; + } + } + + // check for teaching skill bonuses + if ( HAS_SKILL_TRAIT( pInstructor, TEACHING_OT) ) + { + bTrainingBonus += (gGameExternalOptions.ubTeachBonusToTrain * NUM_SKILL_TRAITS( pInstructor, TEACHING_OT)); + } } + ///////////////////////////////////////////////////////////////////////// // teaching bonus is counted as normal, but gun range bonus is not *pusMaxPts += ( ( ( bTrainingBonus + bOpinionFactor ) * *pusMaxPts ) / 100 ); @@ -4305,6 +4769,40 @@ INT16 GetSoldierTrainingPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, UINT16 *pus // calculate effective training pts sTrainingPts = __max( ( ( EffectiveWisdom( pSoldier ) * ( gGameExternalOptions.ubTrainingSkillMax - bSkill ) ) / gGameExternalOptions.ubSelfTrainingDivisor ), 1 ); + // SANDRO - STOMP traits + if ( gGameOptions.fNewTraitSystem ) + { + // Teaching trait helps to practise self a little + if ( HAS_SKILL_TRAIT( pSoldier, TEACHING_NT ) && pSoldier->bAssignment == TRAIN_SELF ) + { + // +25% + *pusMaxPts += (*pusMaxPts * gSkillTraitValues.ubTGBonusOnPractising / 100); + bTrainingBonus += gSkillTraitValues.ubTGBonusOnPractising; + //sTrainingPts += (sTrainingPts * gSkillTraitValues.ubTGBonusOnPractising / 100); + } + // bonus for practising for intellectuals + if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_INTELLECTUAL ) + { + // +10% + *pusMaxPts += (*pusMaxPts / 10); + bTrainingBonus += 10; + //sTrainingPts += (sTrainingPts / 10); + } + // bonus for practising for intellectuals + if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + switch (bTrainStat) + { + case MECHANICAL: + case MEDICAL: + case EXPLOSIVE_ASSIGN: + *pusMaxPts -= (*pusMaxPts / 20); + bTrainingBonus -= 5; + break; + } + } + } + // get special bonus if we're training marksmanship and we're in the gun range sector in Alma // HEADROCK HAM 3.5: Now reads from XML facilities, and works for all stats. if ( pSoldier->bSectorZ == 0 ) @@ -4387,6 +4885,40 @@ INT16 GetSoldierStudentPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, UINT16 *pusM // calculate effective training pts sTrainingPts = __max( ( ( EffectiveWisdom( pSoldier ) * ( gGameExternalOptions.ubTrainingSkillMax - bSkill ) ) / gGameExternalOptions.ubSelfTrainingDivisor ), 1 ); + // SANDRO - STOMP traits + if ( gGameOptions.fNewTraitSystem ) + { + // Teaching trait helps to practise self a little + if ( HAS_SKILL_TRAIT( pSoldier, TEACHING_NT ) && pSoldier->bAssignment == TRAIN_SELF ) + { + // +25% + *pusMaxPts += (*pusMaxPts * gSkillTraitValues.ubTGBonusOnPractising / 100); + bTrainingBonus += gSkillTraitValues.ubTGBonusOnPractising; + //sTrainingPts += (sTrainingPts * gSkillTraitValues.ubTGBonusOnPractising / 100); + } + // bonus for practising for intellectuals + if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_INTELLECTUAL ) + { + // +10% + *pusMaxPts += (*pusMaxPts / 10); + bTrainingBonus += 10; + //sTrainingPts += (sTrainingPts / 10); + } + // bonus for practising for intellectuals + if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + switch (bTrainStat) + { + case MECHANICAL: + case MEDICAL: + case EXPLOSIVE_ASSIGN: + *pusMaxPts -= (*pusMaxPts / 20); + bTrainingBonus -= 5; + break; + } + } + } + // get special bonus if we're training marksmanship and we're in the gun range sector in Alma // HEADROCK HAM 3.5: Now reads from XML facilities, and works for all stats. if ( pSoldier->bSectorZ == 0 ) @@ -4599,17 +5131,44 @@ INT16 GetTownTrainPtsForCharacter( SOLDIERTYPE *pTrainer, UINT16 *pusMaxPts ) sTotalTrainingPts = ( EffectiveWisdom( pTrainer ) + EffectiveLeadership ( pTrainer ) + ( 10 * EffectiveExpLevel ( pTrainer ) ) ) * gGameExternalOptions.ubTownMilitiaTrainingRate; // check for teaching bonuses - if( gMercProfiles[ pTrainer->ubProfile ].bSkillTrait == TEACHING ) + if( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO { - sTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain; + sTrainingBonus -= gSkillTraitValues.bSpeedModifierTrainingMilitia; // penalty for untrained mercs + + // bonus for teching trait + if ( HAS_SKILL_TRAIT( pTrainer, TEACHING_NT) ) + { + sTrainingBonus += gSkillTraitValues.ubTGBonusToTrainMilitia; + } + // +10% for Assertive people + if ( gMercProfiles[pTrainer->ubProfile].bCharacterTrait == CHAR_TRAIT_ASSERTIVE ) + { + sTrainingBonus += 10; + } + // -5% for Aggressive people + else if ( gMercProfiles[pTrainer->ubProfile].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + sTrainingBonus -= 5; + } + // +5% for Phlegmatic people + else if ( gMercProfiles[pTrainer->ubProfile].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC ) + { + sTrainingBonus += 5; + } + } - if( gMercProfiles[ pTrainer->ubProfile ].bSkillTrait2 == TEACHING ) + else { - sTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain; + if ( HAS_SKILL_TRAIT( pTrainer, TEACHING_OT) ) + { + sTrainingBonus += (gGameExternalOptions.ubTeachBonusToTrain * NUM_SKILL_TRAITS( pTrainer, TEACHING_OT)); + } } // RPCs get a small training bonus for being more familiar with the locals and their customs/needs than outsiders - if( pTrainer->ubProfile >= FIRST_RPC ) + //new profiles by Jazz + //if( pTrainer->ubProfile >= FIRST_RPC ) + if ( gProfilesRPC[pTrainer->ubProfile].ProfilId == pTrainer->ubProfile || gProfilesNPC[pTrainer->ubProfile].ProfilId == pTrainer->ubProfile ) { sTrainingBonus += gGameExternalOptions.ubRpcBonusToTrainMilitia; } @@ -4903,8 +5462,46 @@ void HandleHealingByNaturalCauses( SOLDIERTYPE *pSoldier ) // what percentage of health is he down to uiPercentHealth = ( pSoldier->stats.bLife * 100 ) / pSoldier->stats.bLifeMax; - // gain that many hundredths of life points back, divided by the activity level modifier - pSoldier->sFractLife += ( INT16 ) ((( uiPercentHealth / bActivityLevelDivisor ) * usFacilityModifier) / 100 ); + // SANDRO - experimental - increase health regenariton of soldiers when doctors are around + if ( gGameOptions.fNewTraitSystem ) + { + SOLDIERTYPE * pMedic = NULL; + UINT8 cnt; + UINT16 bRegenerationBonus = 0; + + cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; + for ( pMedic = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pMedic++) + { + if ( !(pMedic->bActive) || !(pMedic->bInSector) || ( pMedic->flags.uiStatusFlags & SOLDIER_VEHICLE ) || (pMedic->bAssignment == VEHICLE ) ) + { + continue; // NEXT!!! + } + if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 + && pMedic->ubID != pSoldier->ubID && HAS_SKILL_TRAIT( pMedic, DOCTOR_NT )) + { + bRegenerationBonus += NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ); + if (bRegenerationBonus >= gSkillTraitValues.ubDOMaxRegenBonuses) // how many doctor traits can help + { + bRegenerationBonus = gSkillTraitValues.ubDOMaxRegenBonuses; + break; + } + } + } + if (bRegenerationBonus > 0) + { + pSoldier->sFractLife += ( INT16 ) (((( uiPercentHealth / bActivityLevelDivisor ) * (100 + gSkillTraitValues.ubDONaturalRegenBonus * bRegenerationBonus) / 100 ) * usFacilityModifier ) / 100 ); + } + else + { + // gain that many hundredths of life points back, divided by the activity level modifier + pSoldier->sFractLife += ( INT16 ) ((( uiPercentHealth / bActivityLevelDivisor ) * usFacilityModifier) / 100 ); + } + } + else // original + { + // gain that many hundredths of life points back, divided by the activity level modifier + pSoldier->sFractLife += ( INT16 ) ((( uiPercentHealth / bActivityLevelDivisor ) * usFacilityModifier) / 100 ); + } // now update the real life values UpDateSoldierLife( pSoldier ); @@ -4918,6 +5515,15 @@ void UpDateSoldierLife( SOLDIERTYPE *pSoldier ) // update soldier life, make sure we don't go out of bounds pSoldier->stats.bLife += pSoldier->sFractLife / 100; + // SANDRO - when being healed normally, reduce insta-healable HPs value + if ( gGameOptions.fNewTraitSystem && pSoldier->iHealableInjury > 0 ) + { + pSoldier->iHealableInjury -= pSoldier->sFractLife; + + if (pSoldier->iHealableInjury < 0) + pSoldier->iHealableInjury = 0; + } + // keep remaining fract of life pSoldier->sFractLife %= 100; @@ -4927,6 +5533,7 @@ void UpDateSoldierLife( SOLDIERTYPE *pSoldier ) // reduce pSoldier->stats.bLife = pSoldier->stats.bLifeMax; pSoldier->sFractLife = 0; + pSoldier->iHealableInjury = 0; // check added by SANDRO } return; } @@ -7788,7 +8395,7 @@ void SquadMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) if( pSoldier->bOldAssignment == VEHICLE ) { - SetSoldierExitVehicleInsertionData( pSoldier, pSoldier->iVehicleId ); + SetSoldierExitVehicleInsertionData( pSoldier, pSoldier->iVehicleId, pSoldier->ubGroupID ); } //Clear any desired squad assignments -- seeing the player has physically changed it! @@ -8227,6 +8834,54 @@ void AssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) // set assignment for group SetAssignmentForList( ( INT8 ) PATIENT, 0 ); + + ///////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - added check for surgery + if( pSoldier->iHealableInjury >= 100 && gGameOptions.fNewTraitSystem ) // if we can heal at least one life point + { + SOLDIERTYPE * pMedic = NULL; + SOLDIERTYPE * pBestMedic = NULL; + UINT8 cnt; + INT8 bSlot; + + // Find the best doctor + cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; + for ( pMedic = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pMedic++) + { + if ( !(pMedic->bActive) || !(pMedic->bInSector) || ( pMedic->flags.uiStatusFlags & SOLDIER_VEHICLE ) || (pMedic->bAssignment == VEHICLE ) ) + continue; // is nowhere around! + + if (( pSoldier->ubID == pMedic->ubID ) || ( pMedic->bAssignment != DOCTOR )) + continue; // cannot make surgery on self or not on the right assignment! + + bSlot = FindMedKit( pMedic ); + if (bSlot == NO_SLOT) + continue;// no medical kit! + + if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && ( NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery )) + { + if (pBestMedic != NULL) + { + if (NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) > NUM_SKILL_TRAITS( pBestMedic, DOCTOR_NT )) + pBestMedic = pMedic; + } + else + { + pBestMedic = pMedic; + } + } + } + if (pBestMedic != NULL) + { + CHAR16 zStr[200]; + pAutomaticSurgeryDoctor = pBestMedic; + pAutomaticSurgeryPatient = pSoldier; + swprintf( zStr, New113Message[ MSG113_SURGERY_BEFORE_PATIENT_ASSIGNMENT ] ); + + DoMapMessageBox( MSG_BOX_BASIC_STYLE, zStr, MAP_SCREEN, MSG_BOX_FLAG_YESNO, SurgeryBeforePatientingRequesterCallback ); + } + } + ///////////////////////////////////////////////////////////////////////////////////////// } break; @@ -8317,9 +8972,21 @@ void AssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) fTeamPanelDirty = TRUE; fMapScreenBottomDirty = TRUE; - // set assignment for group SetAssignmentForList( ( INT8 ) DOCTOR, 0 ); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - added check for surgery + if( gGameOptions.fNewTraitSystem && ( GetNumberThatCanBeDoctored( pSoldier, HEALABLE_EVER, FALSE, FALSE, TRUE ) > 0 ) && + ( NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery ) ) + { + CHAR16 zStr[200]; + pAutomaticSurgeryDoctor = pSoldier; + swprintf( zStr, New113Message[ MSG113_SURGERY_BEFORE_DOCTOR_ASSIGNMENT ], GetNumberThatCanBeDoctored( pSoldier, HEALABLE_EVER, TRUE, TRUE, TRUE ) ); + + DoMapMessageBox( MSG_BOX_BASIC_STYLE, zStr, MAP_SCREEN, MSG_BOX_FLAG_YESNO, SurgeryBeforeDoctoringRequesterCallback ); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////// } else if( CanCharacterDoctorButDoesntHaveMedKit( pSoldier ) ) { @@ -8375,6 +9042,53 @@ void AssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) // set assignment for group SetAssignmentForList( ( INT8 ) PATIENT, 0 ); + ///////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - added check for surgery + if( pSoldier->iHealableInjury >= 100 && gGameOptions.fNewTraitSystem ) // if we can heal at least one life point + { + SOLDIERTYPE * pMedic = NULL; + SOLDIERTYPE * pBestMedic = NULL; + UINT8 cnt; + INT8 bSlot; + + // Find the best doctor + cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; + for ( pMedic = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pMedic++) + { + if ( !(pMedic->bActive) || !(pMedic->bInSector) || ( pMedic->flags.uiStatusFlags & SOLDIER_VEHICLE ) || (pMedic->bAssignment == VEHICLE ) ) + continue; // is nowhere around! + + if (( pSoldier->ubID == pMedic->ubID ) || ( pMedic->bAssignment != DOCTOR )) + continue; // cannot make surgery on self or not on the right assignment! + + bSlot = FindMedKit( pMedic ); + if (bSlot == NO_SLOT) + continue;// no medical kit! + + if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && ( NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery )) + { + if (pBestMedic != NULL) + { + if (NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) > NUM_SKILL_TRAITS( pBestMedic, DOCTOR_NT )) + pBestMedic = pMedic; + } + else + { + pBestMedic = pMedic; + } + } + } + if (pBestMedic != NULL) + { + CHAR16 zStr[200]; + pAutomaticSurgeryDoctor = pBestMedic; + pAutomaticSurgeryPatient = pSoldier; + swprintf( zStr, New113Message[ MSG113_SURGERY_BEFORE_PATIENT_ASSIGNMENT ] ); + + DoMapMessageBox( MSG_BOX_BASIC_STYLE, zStr, MAP_SCREEN, MSG_BOX_FLAG_YESNO, SurgeryBeforePatientingRequesterCallback ); + } + } + ///////////////////////////////////////////////////////////////////////////////////////// } break; @@ -10075,6 +10789,12 @@ BOOLEAN CanCharacterRepairRobot( SOLDIERTYPE *pSoldier ) return( FALSE ); } + // Only Technicians can repair the robot! Hehehe.. - SANDRO (well, externalized now) + if( gSkillTraitValues.ubTETraitsNumToRepairRobot > NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ) ) + { + return( FALSE ); + } + /* Assignment distance limits removed. Sep/11/98. ARM // if that sector is currently loaded, check distance to robot if( ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ ) ) @@ -11441,6 +12161,11 @@ void BandageBleedingDyingPatientsBeingTreated( ) if ( pSoldier->stats.bLife < OKLIFE ) { + // SANDRO - added to alter the value of insta-healable injuries for doctors + if (pSoldier->iHealableInjury > 0) + { + pSoldier->iHealableInjury -= ((OKLIFE - pSoldier->stats.bLife) * 100); + } pSoldier->stats.bLife = OKLIFE; } } @@ -11458,7 +12183,7 @@ void BandageBleedingDyingPatientsBeingTreated( ) usKitPts = TotalPoints( pKit ); if( usKitPts ) { - uiKitPtsUsed = VirtualSoldierDressWound( pDoctor, pSoldier, pKit, usKitPts, usKitPts ); + uiKitPtsUsed = VirtualSoldierDressWound( pDoctor, pSoldier, pKit, usKitPts, usKitPts, FALSE ); // SANDRO - added variable UseKitPoints( pKit, (UINT16)uiKitPtsUsed, pDoctor ); // if he is STILL bleeding or dying @@ -11502,7 +12227,7 @@ void ReEvaluateEveryonesNothingToDo() switch( pSoldier->bAssignment ) { case DOCTOR: - fNothingToDo = !CanCharacterDoctor( pSoldier ) || ( GetNumberThatCanBeDoctored( pSoldier, HEALABLE_EVER, FALSE, FALSE ) == 0 ); + fNothingToDo = !CanCharacterDoctor( pSoldier ) || ( GetNumberThatCanBeDoctored( pSoldier, HEALABLE_EVER, FALSE, FALSE, FALSE ) == 0 ); // SANDRO - added variable break; case PATIENT: @@ -12148,12 +12873,22 @@ UINT8 CalcSoldierNeedForSleep( SOLDIERTYPE *pSoldier ) ubNeedForSleep = 18; } - // reduce for Night Ops trait - // HEADROCK HAM 3.6: This is now split and applied depending on whether the merc is resting or working. - //ubNeedForSleep -= NUM_SKILL_TRAITS( pSoldier, NIGHTOPS ); + // reduce for Night Ops trait + // SANDRO - new traits + if (gGameOptions.fNewTraitSystem) + { + if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT )) + ubNeedForSleep -= gSkillTraitValues.ubNONeedForSleepReduction; - // reduce for Martial Arts trait - ubNeedForSleep -= NUM_SKILL_TRAITS( pSoldier, MARTIALARTS ); + if ( ubNeedForSleep < 4 ) + ubNeedForSleep = 4; + } + else + { + // HEADROCK HAM 3.6: This is now split and applied depending on whether the merc is resting or working. + //ubNeedForSleep -= NUM_SKILL_TRAITS( pSoldier, NIGHTOPS ); + ubNeedForSleep -= NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ); + } return( ubNeedForSleep ); } @@ -12826,7 +13561,7 @@ BOOLEAN BasicCanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier ) // Mobile Training allowed by INI settings? if (!gGameExternalOptions.gfmusttrainroaming || // Mobiles turned off? - GetWorldDay( ) < gGameExternalOptions.guiAllowMilitiaGroupsDelay) // Mobiles not yet available? + GetWorldDay( ) < gGameExternalOptions.guiAllowMilitiaGroupsDelay || !gGameExternalOptions.gfAllowMilitiaGroups) // Mobiles not yet available? { // No Mobile Militia training allowed! return ( FALSE ); @@ -12978,11 +13713,25 @@ BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier ) // Apply modifier for TEACHER trait, if that feature is activated if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) { - // Modifier applied once for each TEACHING level. - for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING ); i++ ) + // Read BASE leadership + usEffectiveLeadership = pSoldier->stats.bLeadership; + + if ( gGameOptions.fNewTraitSystem ) // SANDRO - old/new traits { - // This is a percentage modifier. - usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; + if (HAS_SKILL_TRAIT( pSoldier, TEACHING_NT )) + { + // bonus from Teaching trait + usEffectiveLeadership = (usEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 ); + } + } + else + { + // Modifier applied once for each TEACHING level. + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING_OT ); i++ ) + { + // This is a percentage modifier. + usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; + } } } @@ -12995,9 +13744,17 @@ BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier ) } } + INT8 bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ); + SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR(pSoldier->sSectorX, pSoldier->sSectorY) ] ); + //////////////////////////////////////////////// // Check whether controlled town sectors already have full militia + // HEADROCK HAM 4: This check is no longer required. We can manually restrict mobiles from entering a city + // after being created, so we should be able to train them if we need them straight away. + + /* + INT32 iCounter = 0; INT8 bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ); SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR(pSoldier->sSectorX, pSoldier->sSectorY) ] ); @@ -13044,6 +13801,7 @@ BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier ) // At least one city sector is controlled but not full of garrison militia. Can't train mobiles! return (FALSE); } + */ ////////////////////////////////////////////// // HEADROCK HAM 3.5: Militia Training Facility @@ -13113,11 +13871,22 @@ BOOLEAN CanCharacterTrainMilitiaWithErrorReport( SOLDIERTYPE *pSoldier ) // Apply modifier for TEACHER trait, if that feature is activated if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) { - // Modifier applied once for each TEACHING level. - for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING ); i++ ) + if ( gGameOptions.fNewTraitSystem ) // SANDRO - old/new traits { - // This is a percentage modifier. - usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; + if (HAS_SKILL_TRAIT( pSoldier, TEACHING_NT )) + { + // bonus from Teaching trait + usEffectiveLeadership = (usEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 ); + } + } + else + { + // Modifier applied once for each TEACHING level. + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING_OT ); i++ ) + { + // This is a percentage modifier. + usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; + } } usEffectiveLeadership = __min(100,usEffectiveLeadership); } @@ -13256,11 +14025,22 @@ BOOLEAN CanCharacterTrainMobileMilitiaWithErrorReport( SOLDIERTYPE *pSoldier ) // Apply modifier for TEACHER trait, if that feature is activated if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) { - // Modifier applied once for each TEACHING level. - for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING ); i++ ) + if ( gGameOptions.fNewTraitSystem ) // SANDRO - old/new traits { - // This is a percentage modifier. - usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; + if (HAS_SKILL_TRAIT( pSoldier, TEACHING_NT )) + { + // bonus from Teaching trait + usEffectiveLeadership = (usEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 ); + } + } + else + { + // Modifier applied once for each TEACHING level. + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pSoldier, TEACHING_OT ); i++ ) + { + // This is a percentage modifier. + usEffectiveLeadership = (usEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100; + } } usEffectiveLeadership = __min(100,usEffectiveLeadership); } @@ -13299,9 +14079,16 @@ BOOLEAN CanCharacterTrainMobileMilitiaWithErrorReport( SOLDIERTYPE *pSoldier ) return (FALSE); } + INT8 bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ); + SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR(pSoldier->sSectorX, pSoldier->sSectorY) ] ); + //////////////////////////////////////////////// // Check whether controlled town sectors already have full militia + // HEADROCK HAM 4: This check is no longer necessary. We can manually restrict mobiles from moving into a city + // in-game, so you can train mobiles straight away if you need them. + /* + INT8 bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ); SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR(pSoldier->sSectorX, pSoldier->sSectorY) ] ); UINT8 ubUnfullSectorsFound = 0; @@ -13350,6 +14137,8 @@ BOOLEAN CanCharacterTrainMobileMilitiaWithErrorReport( SOLDIERTYPE *pSoldier ) return (FALSE); } + */ + ////////////////////////////////////////// // Capacity and Garrison checks in nearby sectors UINT16 pMoveDir[4][3]; @@ -14667,7 +15456,7 @@ void ResetAllExpensiveFacilityAssignments() pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ]; // Is character doing facility work? - UINT8 ubAssignmentIndex = GetSoldierFacilityAssignmentIndex( pSoldier ); + INT8 ubAssignmentIndex = GetSoldierFacilityAssignmentIndex( pSoldier ); if( ubAssignmentIndex != -1 ) { UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated; @@ -15327,3 +16116,209 @@ void HandleShadingOfLinesForFacilityAssignmentMenu( void ) } return; } + +// SANDRO - function for automatic surgery button callback +void SurgeryBeforeDoctoringRequesterCallback( UINT8 bExitValue ) +{ + if( bExitValue == MSG_BOX_RETURN_YES ) + { + if (MakeAutomaticSurgeryOnAllPatients( pAutomaticSurgeryDoctor ) > 0) + { + DoScreenIndependantMessageBox( L"Healed!" , MSG_BOX_FLAG_OK, NULL ); + } + else + { + DoScreenIndependantMessageBox( L"NOT Healed!" , MSG_BOX_FLAG_OK, NULL ); + } + pAutomaticSurgeryDoctor = NULL; + + } +} + +// SANDRO - function for automatic surgery button callback +void SurgeryBeforePatientingRequesterCallback( UINT8 bExitValue ) +{ + if( bExitValue == MSG_BOX_RETURN_YES ) + { + if( (CanSoldierBeHealedByDoctor( pAutomaticSurgeryPatient, pAutomaticSurgeryDoctor, FALSE, HEALABLE_EVER, FALSE, FALSE, TRUE ) == TRUE ) && + (MakeAutomaticSurgery( pAutomaticSurgeryPatient, pAutomaticSurgeryDoctor ) == TRUE) ) + { + DoScreenIndependantMessageBox( L"Healed!" , MSG_BOX_FLAG_OK, NULL ); + } + else + { + DoScreenIndependantMessageBox( L"NOT Healed!" , MSG_BOX_FLAG_OK, NULL ); + } + pAutomaticSurgeryDoctor = NULL; + + } +} +// SANDRO - function for automatic surgery on all patients +INT16 MakeAutomaticSurgeryOnAllPatients( SOLDIERTYPE * pDoctor ) +{ + int cnt; + SOLDIERTYPE *pTeamSoldier = NULL; + UINT8 ubNumberOfPeopleHealed = 0; + + AssertNotNIL(pDoctor); + + // go through list of characters, find all who are patients/doctors healable by this doctor + for ( cnt = 0, pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pDoctor->bTeam ].bLastID; cnt++,pTeamSoldier++) + { + if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_EVER, FALSE, FALSE, TRUE ) == TRUE ) + { + if( MakeAutomaticSurgery( pTeamSoldier, pDoctor ) == TRUE ) + { + // increment number of doctorable patients/doctors + ubNumberOfPeopleHealed++; + } + } + } + + return( ubNumberOfPeopleHealed ); +} +// SANDRO - automatic surgery +BOOLEAN MakeAutomaticSurgery( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pDoctor ) +{ + UINT16 usKitPts; + UINT32 uiPointsUsed; + OBJECTTYPE *pKit = NULL; + INT8 bSlot, cnt; + INT32 bLifeToReturn = 0; + + if ( gSkillTraitValues.ubDONumberTraitsNeededForSurgery > NUM_SKILL_TRAITS( pDoctor, DOCTOR_NT ) ) + { + return( FALSE ); + } + + cnt = 0; + while( pSoldier->iHealableInjury >= 100 ) + { + bSlot = FindMedKit( pDoctor ); + if ( bSlot != NO_SLOT ) + { + pKit = &pDoctor->inv[ bSlot ]; + } + else + { + break; + } + usKitPts = TotalPoints( pKit ); + + uiPointsUsed = VirtualSoldierDressWound( pDoctor, pSoldier, pKit, usKitPts, usKitPts, TRUE ); + UseKitPoints( pKit, (UINT16)uiPointsUsed, pDoctor ); + + cnt++; + if( cnt > 30 ) + break; + } + + if ( pSoldier->iHealableInjury < 100 ) + { + pSoldier->iHealableInjury = 0; + return( TRUE ); + } + else + { + return( FALSE ); + } + +} + +// SANDRO - added a function to write down to our records, how many militia we trained +void RecordNumMilitiaTrainedForMercs( INT16 sX, INT16 sY, INT8 bZ, UINT8 ubMilitiaTrained, BOOLEAN fMobile ) +{ + + UINT16 cnt = 0; + SOLDIERTYPE * pTrainer; + UINT16 usTotalLeadershipValue = 0; + UINT8 usTrainerEffectiveLeadership = 0; + + // First, get total leadership value of all trainers + for ( pTrainer = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++, pTrainer++) + { + if (pTrainer->bActive && pTrainer->stats.bLife >= OKLIFE && pTrainer->sSectorX == sX && pTrainer->sSectorY == sY && pTrainer->bSectorZ == bZ && + ( (!fMobile && pTrainer->bAssignment == TRAIN_TOWN) || (fMobile && pTrainer->bAssignment == TRAIN_MOBILE) ) ) + { + usTrainerEffectiveLeadership = EffectiveLeadership( pTrainer ); + + if ( gGameOptions.fNewTraitSystem ) //old/new traits + { + // -10% penalty for untrained mercs + usTrainerEffectiveLeadership = (usTrainerEffectiveLeadership * (100 - gSkillTraitValues.bSpeedModifierTrainingMilitia) / 100); + + if (HAS_SKILL_TRAIT( pTrainer, TEACHING_NT )) + { + // bonus from Teaching trait + usTrainerEffectiveLeadership = __min(100,(usTrainerEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 )); + } + } + // Effective leadership is modified by an INI-based percentage, once for every TEACHING trait level. + else if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) + { + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pTrainer, TEACHING_OT ); i++ ) + { + // percentage-based. + usTrainerEffectiveLeadership = __min(100,((usTrainerEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100)); + } + } + + if (gGameExternalOptions.fLeadershipAffectsMilitiaQuantity) + { + usTrainerEffectiveLeadership = __max(usTrainerEffectiveLeadership, gGameExternalOptions.ubMinimumLeadershipToTrainMilitia); + if (usTrainerEffectiveLeadership > gGameExternalOptions.ubReqLeadershipForFullTraining) + usTrainerEffectiveLeadership = __min( 100, (gGameExternalOptions.ubReqLeadershipForFullTraining + ((usTrainerEffectiveLeadership - gGameExternalOptions.ubReqLeadershipForFullTraining)/2))); + + usTrainerEffectiveLeadership = __max( 0, (usTrainerEffectiveLeadership - gGameExternalOptions.ubMinimumLeadershipToTrainMilitia)); + } + + // Add to the total amount + usTotalLeadershipValue += __min(100,usTrainerEffectiveLeadership); + } + } + // Now we have to run again and percentually award points towards militia trained + cnt = 0; + for ( pTrainer = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++, pTrainer++) + { + if (pTrainer->bActive && pTrainer->stats.bLife >= OKLIFE && pTrainer->sSectorX == sX && pTrainer->sSectorY == sY && pTrainer->bSectorZ == bZ && + ( (!fMobile && pTrainer->bAssignment == TRAIN_TOWN) || (fMobile && pTrainer->bAssignment == TRAIN_MOBILE) ) ) + { + usTrainerEffectiveLeadership = EffectiveLeadership( pTrainer ); + + if ( gGameOptions.fNewTraitSystem ) //old/new traits + { + // -10% penalty for untrained mercs + usTrainerEffectiveLeadership = (usTrainerEffectiveLeadership * (100 - gSkillTraitValues.bSpeedModifierTrainingMilitia) / 100); + + if (HAS_SKILL_TRAIT( pTrainer, TEACHING_NT )) + { + // bonus from Teaching trait + usTrainerEffectiveLeadership = __min(100,(usTrainerEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 )); + } + } + // Effective leadership is modified by an INI-based percentage, once for every TEACHING trait level. + else if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) + { + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pTrainer, TEACHING_OT ); i++ ) + { + // percentage-based. + usTrainerEffectiveLeadership = __min(100,((usTrainerEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100)); + } + } + + if (gGameExternalOptions.fLeadershipAffectsMilitiaQuantity) + { + usTrainerEffectiveLeadership = __max(usTrainerEffectiveLeadership, gGameExternalOptions.ubMinimumLeadershipToTrainMilitia); + if (usTrainerEffectiveLeadership > gGameExternalOptions.ubReqLeadershipForFullTraining) + usTrainerEffectiveLeadership = __min( 100, (gGameExternalOptions.ubReqLeadershipForFullTraining + ((usTrainerEffectiveLeadership - gGameExternalOptions.ubReqLeadershipForFullTraining)/2))); + + usTrainerEffectiveLeadership = __max( 0, (usTrainerEffectiveLeadership - gGameExternalOptions.ubMinimumLeadershipToTrainMilitia)); + } + + if( usTrainerEffectiveLeadership > 0 ) + { + gMercProfiles[ pTrainer->ubProfile ].records.usMilitiaTrained += (UINT16)((double)((double)(ubMilitiaTrained * usTrainerEffectiveLeadership) / usTotalLeadershipValue) + 0.5); + } + } + } +} diff --git a/Strategic/Assignments.h b/Strategic/Assignments.h index 984ef17e..5424d12c 100644 --- a/Strategic/Assignments.h +++ b/Strategic/Assignments.h @@ -28,45 +28,47 @@ // Assignments Defines -enum{ - SQUAD_1 =0, - SQUAD_2, - SQUAD_3, - SQUAD_4, - SQUAD_5, - SQUAD_6, - SQUAD_7, - SQUAD_8, - SQUAD_9, - SQUAD_10, - SQUAD_11, - SQUAD_12, - SQUAD_13, - SQUAD_14, - SQUAD_15, - SQUAD_16, - SQUAD_17, - SQUAD_18, - SQUAD_19, - SQUAD_20, - ON_DUTY, - DOCTOR, - PATIENT, - VEHICLE, - IN_TRANSIT, - REPAIR, - TRAIN_SELF, - TRAIN_TOWN, - TRAIN_MOBILE, // HEADROCK HAM 3.6: Training mobile militia. - TRAIN_TEAMMATE, - TRAIN_BY_OTHER, - FACILITY_STAFF, // HEADROCK HAM 3.6: Operating a facility for strategic gain. - FACILITY_REST, // HEADROCK HAM 3.6: Facility equivalent of resting (no assignment) - ASSIGNMENT_DEAD, - ASSIGNMENT_UNCONCIOUS, // unused - ASSIGNMENT_POW, - ASSIGNMENT_HOSPITAL, - ASSIGNMENT_EMPTY, +enum +{ + SQUAD_1 = 0, + SQUAD_2, + SQUAD_3, + SQUAD_4, + SQUAD_5, + SQUAD_6, + SQUAD_7, + SQUAD_8, + SQUAD_9, + SQUAD_10, + SQUAD_11, + SQUAD_12, + SQUAD_13, + SQUAD_14, + SQUAD_15, + SQUAD_16, + SQUAD_17, + SQUAD_18, + SQUAD_19, + SQUAD_20, + ON_DUTY, + DOCTOR, + PATIENT, + VEHICLE, + IN_TRANSIT, + REPAIR, + TRAIN_SELF, + TRAIN_TOWN, + TRAIN_MOBILE, // HEADROCK HAM 3.6: Training mobile militia. + TRAIN_TEAMMATE, + TRAIN_BY_OTHER, + FACILITY_STAFF, // HEADROCK HAM 3.6: Operating a facility for strategic gain. + FACILITY_REST, // HEADROCK HAM 3.6: Facility equivalent of resting (no assignment) + ASSIGNMENT_DEAD, + ASSIGNMENT_UNCONCIOUS, // unused + ASSIGNMENT_POW, + ASSIGNMENT_HOSPITAL, + ASSIGNMENT_EMPTY, + NUM_ASSIGNMENTS, }; #define NO_ASSIGNMENT 127 //used when no pSoldier->ubDesiredSquad @@ -370,6 +372,9 @@ extern INT8 gubFacilityInSubmenu; extern UINT8 gubFacilityLineForSubmenu; extern SOLDIERTYPE *gpFacilityStaffer; +// SANDRO - function to award record points for militia training +void RecordNumMilitiaTrainedForMercs( INT16 sX, INT16 sY, INT8 sZ, UINT8 ubMilitiaTrained, BOOLEAN fMobile ); + #endif diff --git a/Strategic/Auto Resolve.cpp b/Strategic/Auto Resolve.cpp index a0512dfa..23744657 100644 --- a/Strategic/Auto Resolve.cpp +++ b/Strategic/Auto Resolve.cpp @@ -67,6 +67,7 @@ #include "MilitiaSquads.h" // #include "Strategic AI.h" #include "interface Dialogue.h" + #include "AIInternals.h" // added by SANDRO #endif #include "Reinforcement.h" @@ -727,6 +728,7 @@ void RefreshMerc( SOLDIERTYPE *pSoldier ) { pSoldier->stats.bLife = pSoldier->stats.bLifeMax; pSoldier->bBleeding = 0; + pSoldier->iHealableInjury = 0; // added by SANDRO pSoldier->bBreath = pSoldier->bBreathMax = 100; pSoldier->sBreathRed = 0; if( gpAR->pRobotCell) @@ -1381,21 +1383,41 @@ void ExpandWindow() } -UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OBJECTTYPE *pKit, INT16 sKitPts, INT16 sStatus ) +////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - This whole procedure was merged with the surgery ability of the doctor trait +UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OBJECTTYPE *pKit, INT16 sKitPts, INT16 sStatus, BOOLEAN fOnSurgery ) { UINT32 uiDressSkill, uiPossible, uiActual, uiMedcost, uiDeficiency, uiAvailAPs, uiUsedAPs; UINT8 bBelowOKlife, bPtsLeft; + INT8 bInitialBleeding; - if( pVictim->bBleeding < 1 ) + if( pVictim->bBleeding < 1 && !fOnSurgery ) return 0; // nothing to do, shouldn't have even been called! if ( pVictim->stats.bLife == 0 ) return 0; + if (fOnSurgery && pVictim->ubID == pSoldier->ubID) // cannot make surgery on self + return 0; - // calculate wound-dressing skill (3x medical, 2x equip,1x level, 1x dex) - uiDressSkill = ( ( 3 * EffectiveMedical( pSoldier ) ) + // medical knowledge - ( 2 * sStatus) + // state of medical kit - (10 * EffectiveExpLevel( pSoldier ) ) + // battle injury experience - EffectiveDexterity( pSoldier ) ) / 7; // general "handiness" + bInitialBleeding = pVictim->bBleeding; + + if ( !gGameOptions.fNewTraitSystem && fOnSurgery) // cannot make surgery if not new traits + fOnSurgery = FALSE; + + // calculate wound-dressing skill (3x medical, 2x equip, 1x level, 1x dex) + if ( gGameOptions.fNewTraitSystem ) + { + uiDressSkill = ( ( 7 * EffectiveMedical( pSoldier ) ) + // medical knowledge + ( sStatus) + // state of medical kit + (10 * EffectiveExpLevel( pSoldier ) ) + // battle injury experience + EffectiveDexterity( pSoldier ) ) / 10; // general "handiness" + } + else + { + uiDressSkill = ( ( 3 * EffectiveMedical( pSoldier ) ) + // medical knowledge + ( 2 * sStatus) + // state of medical kit + (10 * EffectiveExpLevel( pSoldier ) ) + // battle injury experience + EffectiveDexterity( pSoldier ) ) / 7; // general "handiness" + } // try to use every AP that the merc has left uiAvailAPs = pSoldier->bActionPoints; @@ -1413,9 +1435,16 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB if (!uiPossible) return 0; - if (Item[pSoldier->inv[0].usItem].medicalkit ) // using the GOOD medic stuff + if (Item[pSoldier->inv[0].usItem].medicalkit && !(fOnSurgery) ) // using the GOOD medic stuff uiPossible += ( uiPossible / 2); // add extra 50 % + // Doctor trait improves basic bandaging ability + if (!(fOnSurgery) && gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, DOCTOR_NT )) + { + uiPossible = uiPossible * (100 - gSkillTraitValues.bSpeedModifierBandaging) / 100; + uiPossible += ( uiPossible * gSkillTraitValues.ubDOBandagingSpeedPercent * NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT ) / 100); + } + uiActual = uiPossible; // start by assuming maximum possible // figure out how far below OKLIFE the victim is @@ -1432,7 +1461,11 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB { // then add how many healing pts we need to stop bleeding (1x cost) uiDeficiency += ( pVictim->bBleeding - bBelowOKlife ); } - + // On surgery, alter this by amount of life we can heal + if ( fOnSurgery ) + { + uiDeficiency += (pVictim->iHealableInjury / 100); + } // now, make sure we weren't going to give too much if ( uiActual > uiDeficiency) // if we were about to apply too much uiActual = uiDeficiency; // reduce actual not to waste anything @@ -1440,13 +1473,20 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB // now make sure we HAVE that much if( Item[pKit->usItem].medicalkit ) { - uiMedcost = uiActual / 2; // cost is only half + if (fOnSurgery) + uiMedcost = (uiActual * gSkillTraitValues.usDOSurgeryMedBagConsumption ) /100; // surgery drains the kit a lot + else + uiMedcost = (uiActual + 1) / 2; // cost is only half, rounded up + if ( uiMedcost == 0 && uiActual > 0) uiMedcost = 1; - if ( uiMedcost > (UINT32)sKitPts ) // if we can't afford this + if ( uiMedcost > (UINT32)sKitPts ) // if we can't afford this { uiMedcost = sKitPts; // what CAN we afford? - uiActual = uiMedcost * 2; // give double this as aid + if (fOnSurgery) // surgery check + uiActual = (uiMedcost * 100 )/ gSkillTraitValues.usDOSurgeryMedBagConsumption; + else + uiActual = uiMedcost * 2; // give double this as aid } } else @@ -1466,7 +1506,15 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB { // if we have enough points to bring him all the way to OKLIFE this turn if ( bPtsLeft >= (2 * bBelowOKlife ) ) - { // raise life to OKLIFE + { + // insta-healable injury check + if (pVictim->iHealableInjury > 0) + { + pVictim->iHealableInjury -= ((OKLIFE - pVictim->stats.bLife) * 100); + if (pVictim->iHealableInjury < 0) + pVictim->iHealableInjury = 0; + } + // raise life to OKLIFE pVictim->stats.bLife = OKLIFE; // reduce bleeding by the same number of life points healed up pVictim->bBleeding -= bBelowOKlife; @@ -1475,6 +1523,13 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB } else { + // insta-healable injury check + if (pVictim->iHealableInjury > 0) + { + pVictim->iHealableInjury -= (( bPtsLeft / 2) * 100); + if (pVictim->iHealableInjury < 0) + pVictim->iHealableInjury = 0; + } pVictim->stats.bLife += ( bPtsLeft / 2); pVictim->bBleeding -= ( bPtsLeft / 2); bPtsLeft = bPtsLeft % 2; // if ptsLeft was odd, ptsLeft = 1 @@ -1496,6 +1551,99 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB } } + // SURGERY + // first return the real life back, then bandage the rest if possible + if (fOnSurgery && gGameOptions.fNewTraitSystem) // double check for new traits + { + INT32 iLifeReturned = 0; + UINT16 usReturnDamagedStatRate = 0; + // find out if we will repair any stats... + if ( NumberOfDamagedStats( pVictim ) > 0 ) + { + usReturnDamagedStatRate = ((gSkillTraitValues.usDORepairStatsRateBasic + gSkillTraitValues.usDORepairStatsRateOnTop * NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT ))); + usReturnDamagedStatRate -= max( 0, ((usReturnDamagedStatRate * gSkillTraitValues.ubDORepStPenaltyIfAlsoHealing ) / 100)); + + // ... in which case, reduce the points + bPtsLeft = max(0, ((bPtsLeft * ( 100 - gSkillTraitValues.ubDOHealingPenaltyIfAlsoStatRepair )) / 100)); + } + + // Important note! : HealableInjury is always stores the total HPs the victim is missing, not the amount which we will heal, + // so we always take a portion of patient's damage here, reduce the HealableInjury by this portion, while only healing a portion of this portion in actual HPs; + // this means the rest of HPs will remain as "unhealable", the patient will miss X HPs but has no HealableInjury on self.. + if (bPtsLeft >= (pVictim->iHealableInjury/100)) + { + iLifeReturned = pVictim->iHealableInjury * (gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop * NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT ))/100; + + pVictim->iHealableInjury = 0; + // keep the rest of the points to bandaging if neccessary + if (pVictim->bBleeding > 0) + { + bPtsLeft = max(0, (bPtsLeft - (iLifeReturned / 100))); + bPtsLeft += (bPtsLeft/2); // we use medical bag so add the bonus for that. + } + else + { + bPtsLeft = 0; + } + + // add to record - another surgery undergoed + if ( pVictim->ubProfile != NO_PROFILE && iLifeReturned >= 100 ) + gMercProfiles[ pVictim->ubProfile ].records.usTimesSurgeryUndergoed++; + + // add to record - another surgery made + if ( pSoldier->ubProfile != NO_PROFILE && iLifeReturned >= 100 ) + gMercProfiles[ pSoldier->ubProfile ].records.usSurgeriesMade++; + } + else + { + iLifeReturned = bPtsLeft * (gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop * NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT )); + + pVictim->iHealableInjury -= (bPtsLeft * 100); + bPtsLeft = 0; + } + // repair the stats here! + if ( usReturnDamagedStatRate > 0 ) + { + RegainDamagedStats( pVictim, (iLifeReturned * usReturnDamagedStatRate / 100) ); + } + + // some paranoya checks for sure + if ((pVictim->stats.bLife + (iLifeReturned / 100)) <= pVictim->stats.bLifeMax) + { + pVictim->stats.bLife += (iLifeReturned/100); + if (pVictim->bBleeding >= (iLifeReturned/100)) + { + pVictim->bBleeding -= (iLifeReturned/100); + uiMedcost += (iLifeReturned / 200); // add medkit points cost for unbandaged part + } + else + { + pVictim->bBleeding = 0; + uiMedcost += max( 0, (((iLifeReturned/100) - pVictim->bBleeding) / 2)); // add medkit points cost for unbandaged part + } + } + else // this shouldn't even happen, but we still want to have it here for sure + { + pVictim->stats.bLife = pVictim->stats.bLifeMax; + pVictim->iHealableInjury = 0; + pVictim->bBleeding = 0; + } + // Reduce max breath based on life returned + if ( (pVictim->bBreathMax - (((iLifeReturned/100) * gSkillTraitValues.usDOSurgeryMaxBreathLoss )/ 100)) <= BREATHMAX_ABSOLUTE_MINIMUM ) + { + pVictim->bBreathMax = BREATHMAX_ABSOLUTE_MINIMUM; + } + else + { + pVictim->bBreathMax -= (((iLifeReturned/100) * gSkillTraitValues.usDOSurgeryMaxBreathLoss )/ 100); + } + + if (pVictim->iHealableInjury > ((pVictim->stats.bLifeMax - pVictim->stats.bLife)*100)) + pVictim->iHealableInjury = ((pVictim->stats.bLifeMax - pVictim->stats.bLife)*100); + else if (pVictim->iHealableInjury < 0) + pVictim->iHealableInjury = 0; + } + // if any healing points remain, apply that to any remaining bleeding (1/1) // DON'T spend any APs/kit pts to cure bleeding until merc is no longer dying //if ( bPtsLeft && pVictim->bBleeding && !pVictim->dying) @@ -1513,24 +1661,47 @@ UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OB } } // if there are any ptsLeft now, then we didn't actually get to use them - uiActual -= bPtsLeft; + uiActual = max(0, (uiActual - bPtsLeft)); // usedAPs equals (actionPts) * (%of possible points actually used) uiUsedAPs = ( uiActual * uiAvailAPs ) / uiPossible; - if (Item[pSoldier->inv[0].usItem].medicalkit ) // using the GOOD medic stuff + if (Item[pSoldier->inv[0].usItem].medicalkit && !(fOnSurgery)) // using the GOOD medic stuff uiUsedAPs = ( uiUsedAPs * 2) / 3; // reverse 50% bonus by taking 2/3rds - if ( uiActual / 2) - // MEDICAL GAIN (actual / 2): Helped someone by giving first aid - StatChange(pSoldier,MEDICALAMT,( (UINT16)(uiActual / 2) ),FALSE); + // surgery is harder so cost more BPs + if (fOnSurgery) + DeductPoints( pSoldier, (INT16)uiUsedAPs, (INT16)( uiUsedAPs * 15 ) ); + else + DeductPoints( pSoldier, (INT16)uiUsedAPs, (INT16)( ( uiUsedAPs * APBPConstants[BP_PER_AP_LT_EFFORT]) ) ); - if ( uiActual / 4) - // DEXTERITY GAIN (actual / 4): Helped someone by giving first aid - StatChange(pSoldier,DEXTAMT,(UINT16)( ( uiActual / 4) ),FALSE); + // surgery is harder so gives more exp + if (fOnSurgery) + { + // MEDICAL GAIN (actual / 2): Helped someone by giving first aid + StatChange(pSoldier, MEDICALAMT, (UINT16)(uiActual + 2), FALSE); + + // DEXTERITY GAIN (actual / 6): Helped someone by giving first aid + StatChange(pSoldier, DEXTAMT, (UINT16)((uiActual / 3) + 2), FALSE); + } + else + { + if ( uiActual / 2) + // MEDICAL GAIN (actual / 2): Helped someone by giving first aid + StatChange(pSoldier,MEDICALAMT,( (UINT16)(uiActual / 2) ),FALSE); + + if ( uiActual / 4) + // DEXTERITY GAIN (actual / 4): Helped someone by giving first aid + StatChange(pSoldier,DEXTAMT,(UINT16)( ( uiActual / 4) ),FALSE); + } + + // merc records - bandaging + if( bInitialBleeding > 1 && pVictim->bBleeding == 0 && pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usMercsBandaged++; return uiMedcost; } +////////////////////////////////////////////////////////////////////////////////////////////////////// OBJECTTYPE* FindMedicalKit() { @@ -1581,7 +1752,7 @@ UINT32 AutoBandageMercs() continue; break; } - uiPointsUsed = VirtualSoldierDressWound( gpMercs[ i ].pSoldier, gpMercs[ i ].pSoldier, pKit, usKitPts, usKitPts ); + uiPointsUsed = VirtualSoldierDressWound( gpMercs[ i ].pSoldier, gpMercs[ i ].pSoldier, pKit, usKitPts, usKitPts, FALSE ); // changed by SANDRO UseKitPoints( pKit, (UINT16)uiPointsUsed, gpMercs[ i ].pSoldier ); uiCurrPointsUsed += uiPointsUsed; cnt++; @@ -1605,12 +1776,13 @@ UINT32 AutoBandageMercs() if( gpMercs[ i ].pSoldier->stats.bMedical > gpMercs[ iBest ].pSoldier->stats.bMedical ) { iBest = i; - } + } } } for( i = 0; i < gpAR->ubMercs; i++ ) { + cnt = 0; // SANDRO - added safety check while( gpMercs[ i ].pSoldier->bBleeding && gpMercs[ i ].pSoldier->stats.bLife ) { //This merc needs medical attention if( !pKit ) @@ -1629,10 +1801,15 @@ UINT32 AutoBandageMercs() fComplete = FALSE; continue; } - uiPointsUsed = VirtualSoldierDressWound( gpMercs[ iBest ].pSoldier, gpMercs[ i ].pSoldier, pKit, usKitPts, usKitPts ); + uiPointsUsed = VirtualSoldierDressWound( gpMercs[ iBest ].pSoldier, gpMercs[ i ].pSoldier, pKit, usKitPts, usKitPts, FALSE ); UseKitPoints( pKit, (UINT16)uiPointsUsed, gpMercs[ i ].pSoldier ); uiParallelPointsUsed += uiPointsUsed; fComplete = TRUE; + + // SANDRO - added safety check + cnt++; + if( cnt > 500 ) + break; } } if( fComplete ) @@ -1941,6 +2118,7 @@ static void ARCreateMilitia( UINT8 mclass, INT32 i, INT16 sX, INT16 sY) { // reset counter of how many mortars this team has rolled ResetMortarsOnTeamCount(); + ResetNumSquadleadersInArmyGroup(); // added by SANDRO if( !gpBattleGroup ) { //AssertMsg(0, "No battle group set while creating militia"); @@ -2370,8 +2548,40 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Autoresolve2"); else if( gpAR->ubBattleStatus == BATTLE_VICTORY ) { //merc is alive, so group them at the center gridno. gpMercs[ i ].pSoldier->ubStrategicInsertionCode = INSERTION_CODE_CENTER; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - records - autoresolve battles + if( gpMercs[ i ].pSoldier->ubProfile != NO_PROFILE ) + { + // if we ran before the battle was over but the others won in the end, we still get retreated counter, no victory + if ( gpMercs[ i ].uiFlags & CELL_RETREATED || gpMercs[ i ].uiFlags & CELL_RETREATING ) + { + gMercProfiles[ gpMercs[ i ].pSoldier->ubProfile ].records.usBattlesRetreated++; + } + else + { + gMercProfiles[ gpMercs[ i ].pSoldier->ubProfile ].records.usBattlesAutoresolve++; + if ( gMercProfiles[ gpMercs[ i ].pSoldier->ubProfile ].records.usLargestBattleFought < gpAR->ubEnemies ) + { + gMercProfiles[ gpMercs[ i ].pSoldier->ubProfile ].records.usLargestBattleFought = gpAR->ubEnemies; + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } - gMercProfiles[ gpMercs[ i ].pSoldier->ubProfile ].usBattlesFought++; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - times retreated counter + else if( gpAR->ubBattleStatus == BATTLE_RETREAT ) + { + if( gpMercs[ i ].uiFlags & CELL_RETREATED || gpMercs[ i ].uiFlags & CELL_RETREATING ) + { + if( gpMercs[ i ].pSoldier->ubProfile != NO_PROFILE && !AM_A_ROBOT( gpMercs[ i ].pSoldier ) ) + { + gMercProfiles[ gpMercs[ i ].pSoldier->ubProfile ].records.usBattlesRetreated++; + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + } } for( i = 0; i < gpAR->iNumMercFaces; i++ ) @@ -3610,6 +3820,8 @@ void CalculateAttackValues() gpAR->usPlayerAttack = 0; gpAR->usPlayerDefence = 0; + UINT8 uiEffectiveLevelExp = 0; // added by SANDRO + //if( gpAR->ubEnemies ) //{ // //bonus equals 20 if good guys outnumber bad guys 2 to 1. @@ -3648,7 +3860,12 @@ void CalculateAttackValues() //bExpLevel adds a bonus of 7% per level after 2, level 1 soldiers get a 7% decrease //usBonus += 7 * (pSoldier->stats.bExpLevel-2); - usBonus += EXP_BONUS * (pSoldier->stats.bExpLevel-5); + // SANDRO - STOMP traits - Squadleaders bonus to effective level + uiEffectiveLevelExp = pSoldier->stats.bExpLevel; + if ( gGameOptions.fNewTraitSystem ) + uiEffectiveLevelExp = min(10,(uiEffectiveLevelExp + (gSkillTraitValues.ubSLEffectiveLevelInRadius * GetSquadleadersCountInVicinity( pSoldier, TRUE, TRUE )))); + usBonus += EXP_BONUS * (uiEffectiveLevelExp-5); + usBonus += gpAR->ubPlayerDefenceAdvantage; pCell->usAttack = pCell->usAttack * usBonus / 100; pCell->usDefence = pCell->usDefence * usBonus / 100; @@ -3692,7 +3909,12 @@ void CalculateAttackValues() usBonus = 100 + gpAR->ubPlayerLeadership/10;// + sOutnumberBonus; //bExpLevel adds a bonus of 7% per level after 2, level 1 soldiers get a 7% decrease //usBonus += 7 * (pSoldier->stats.bExpLevel-2); - usBonus += EXP_BONUS * (pSoldier->stats.bExpLevel-5); + // SANDRO - STOMP traits - Squadleaders bonus to effective level + uiEffectiveLevelExp = pSoldier->stats.bExpLevel; + if ( gGameOptions.fNewTraitSystem ) + uiEffectiveLevelExp = min(10,(uiEffectiveLevelExp + (gSkillTraitValues.ubSLEffectiveLevelInRadius * GetSquadleadersCountInVicinity( pSoldier, TRUE, TRUE )))); + usBonus += EXP_BONUS * (uiEffectiveLevelExp-5); + usBonus += gpAR->ubPlayerDefenceAdvantage; pCell->usAttack = pCell->usAttack * usBonus / 100; pCell->usDefence = pCell->usDefence * usBonus / 100; @@ -3751,7 +3973,12 @@ void CalculateAttackValues() usBonus = 100 + gpAR->ubPlayerLeadership/10;// + sOutnumberBonus; //bExpLevel adds a bonus of 7% per level after 2, level 1 soldiers get a 7% decrease //usBonus += 7 * (pSoldier->stats.bExpLevel-2); - usBonus += EXP_BONUS * (pSoldier->stats.bExpLevel-5); + // SANDRO - STOMP traits - Squadleaders bonus to effective level + uiEffectiveLevelExp = pSoldier->stats.bExpLevel; + if ( gGameOptions.fNewTraitSystem ) + uiEffectiveLevelExp = min(10,(uiEffectiveLevelExp + (gSkillTraitValues.ubSLEffectiveLevelInRadius * GetSquadleadersCountInVicinity( pSoldier, TRUE, TRUE )))); + usBonus += EXP_BONUS * (uiEffectiveLevelExp-5); + usBonus += gpAR->ubEnemyDefenceAdvantage; pCell->usAttack = pCell->usAttack * usBonus / 100; pCell->usDefence = pCell->usDefence * usBonus / 100; @@ -3942,7 +4169,7 @@ BOOLEAN FireAShot( SOLDIERCELL *pAttacker ) PlayAutoResolveSample( Weapon[ pItem->usItem ].sSound, RATE_11025, 50, 1, MIDDLEPAN ); if( pAttacker->uiFlags & CELL_MERC ) { - gMercProfiles[ pAttacker->pSoldier->ubProfile ].usShotsFired++; + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usShotsFired++; // MARKSMANSHIP GAIN: Attacker fires a shot StatChange( pAttacker->pSoldier, MARKAMT, 3, FALSE ); @@ -4020,6 +4247,61 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) usDefence = (UINT16)(pTarget->usDefence + PreRandom((INT16)(gGameExternalOptions.iAutoResolveLuckFactor*1000.0) - pTarget->usDefence )); else usDefence = (UINT16)(950 + PreRandom( 50 )); + + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Iincrease Militia Strength in autoresolve battles + // because the attack and defense is limited to max 1000, rather than only increasing the attack of milita, + // decrease the defense of target - so +100% bonus means +50% attack of attacker and -50% defense of target + + //if militita is attacking increase attack by half and decrease the defense of enemy + if (pAttacker->pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaAutoresolveStrength != 0) + { + usAttack += (usAttack * gGameExternalOptions.sGreenMilitiaAutoresolveStrength /200); + usDefence -= (usDefence * gGameExternalOptions.sGreenMilitiaAutoresolveStrength /200); + } + else if (pAttacker->pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaAutoresolveStrength != 0) + { + usAttack += (usAttack * gGameExternalOptions.sRegularMilitiaAutoresolveStrength /200); + usDefence -= (usDefence * gGameExternalOptions.sRegularMilitiaAutoresolveStrength /200); + } + else if (pAttacker->pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaAutoresolveStrength != 0) + { + usAttack += (usAttack * gGameExternalOptions.sVeteranMilitiaAutoresolveStrength /200); + usDefence -= (usDefence * gGameExternalOptions.sVeteranMilitiaAutoresolveStrength /200); + } + else if (pAttacker->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveOffenseBonus != 0) + { + usAttack += (usAttack * gGameExternalOptions.sMercsAutoresolveOffenseBonus /200); + usDefence -= (usDefence * gGameExternalOptions.sMercsAutoresolveOffenseBonus /200); + } + + //if enemy is attacking decrease his attack by half and increase the defense of militia by half + if (pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaAutoresolveStrength != 0) + { + usDefence += (usDefence * gGameExternalOptions.sGreenMilitiaAutoresolveStrength /200); + usAttack -= (usAttack * gGameExternalOptions.sGreenMilitiaAutoresolveStrength /200); + } + else if (pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaAutoresolveStrength != 0) + { + usDefence += (usDefence * gGameExternalOptions.sRegularMilitiaAutoresolveStrength /200); + usAttack -= (usAttack * gGameExternalOptions.sRegularMilitiaAutoresolveStrength /200); + } + else if (pTarget->pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaAutoresolveStrength != 0) + { + usDefence += (usDefence * gGameExternalOptions.sVeteranMilitiaAutoresolveStrength /200); + usAttack -= (usAttack * gGameExternalOptions.sVeteranMilitiaAutoresolveStrength /200); + } + else if (pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0) + { + usDefence += (usDefence * gGameExternalOptions.sMercsAutoresolveDeffenseBonus /200); + usAttack -= (usAttack * gGameExternalOptions.sMercsAutoresolveDeffenseBonus /200); + } + + // reapair values + usAttack = max(0, min(1000, usAttack )); + usDefence = max(0, min(1000, usDefence )); + /////////////////////////////////////////////////////////////////////////////////////////// + if( pAttacker->uiFlags & CELL_FEMALECREATURE ) { pAttacker->bWeaponSlot = HANDPOS; @@ -4105,6 +4387,17 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) ubLocation = AIM_SHOT_TORSO; ubAccuracy = (UINT8)((usAttack - usDefence + PreRandom( usDefence - pTarget->usDefence ) )/10); iImpact = BulletImpact( pAttacker->pSoldier, pTarget->pSoldier, ubLocation, ubImpact, ubAccuracy, NULL ); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - increased mercs' offense/deffense rating + if (pAttacker->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveOffenseBonus != 0) + { + iImpact += (iImpact * gGameExternalOptions.sMercsAutoresolveOffenseBonus /150); + } + else if (pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0 && (iImpact > 3)) + { + iImpact = max( 3, ((iImpact * (100 - (gGameExternalOptions.sMercsAutoresolveDeffenseBonus / 2))) /100)); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// if ( bAttackIndex == -1 ) { @@ -4146,7 +4439,7 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) //switch items tempItem = pAttacker->pSoldier->inv[ HANDPOS ]; pAttacker->pSoldier->inv[ HANDPOS ] = pAttacker->pSoldier->inv[ pAttacker->bWeaponSlot ]; //CTD - iImpact = HTHImpact( pAttacker->pSoldier, pTarget->pSoldier, ubAccuracy, (BOOLEAN)(fKnife | fClaw) ); + iImpact = HTHImpact( pAttacker->pSoldier, pTarget->pSoldier, ubAccuracy, (BOOLEAN)(fKnife || fClaw) ); pAttacker->pSoldier->inv[ pAttacker->bWeaponSlot ] = pAttacker->pSoldier->inv[ HANDPOS ]; pAttacker->pSoldier->inv[ HANDPOS ] = tempItem; } @@ -4154,6 +4447,17 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) { iImpact = HTHImpact( pAttacker->pSoldier, pTarget->pSoldier, ubAccuracy, (BOOLEAN)(fKnife || fClaw) ); } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - increased mercs' offense/deffense rating + if (pAttacker->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveOffenseBonus != 0) + { + iImpact += (iImpact * gGameExternalOptions.sMercsAutoresolveOffenseBonus /150); + } + else if (pTarget->uiFlags & CELL_MERC && gGameExternalOptions.sMercsAutoresolveDeffenseBonus != 0 && (iImpact > 3)) + { + iImpact = max( 3, ((iImpact * (100 - (gGameExternalOptions.sMercsAutoresolveDeffenseBonus / 2))) /100)); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // WANNE: Why is impact here always set to 0? The impact was calculated a few lines before! //iImpact = 0; @@ -4166,13 +4470,14 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) if( pAttacker->uiFlags & CELL_MERC ) { //Attacker is a player, so increment the number of shots that hit. - gMercProfiles[ pAttacker->pSoldier->ubProfile ].usShotsHit++; + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usShotsHit++; // MARKSMANSHIP GAIN: Attacker's shot hits StatChange( pAttacker->pSoldier, MARKAMT, 6, FALSE ); // in addition to 3 for taking a shot } if( pTarget->uiFlags & CELL_MERC ) { //Target is a player, so increment the times he has been wounded. - gMercProfiles[ pTarget->pSoldier->ubProfile ].usTimesWounded++; + if( iImpact > 1 ) + gMercProfiles[ pTarget->pSoldier->ubProfile ].records.usTimesWoundedStabbed++; // EXPERIENCE GAIN: Took some damage StatChange( pTarget->pSoldier, EXPERAMT, ( UINT16 )( 5 * ( iImpact / 10 ) ), FALSE ); } @@ -4190,7 +4495,34 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) { //soldier has been killed if( pAttacker->uiFlags & CELL_MERC ) { //Player killed the enemy soldier -- update his stats as well as any assisters. - gMercProfiles[ pAttacker->pSoldier->ubProfile ].usKills++; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - experimental - more specific statistics of mercs + switch(pTarget->pSoldier->ubSoldierClass) + { + case SOLDIER_CLASS_ELITE : + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsElites++; + break; + case SOLDIER_CLASS_ARMY : + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsRegulars++; + break; + case SOLDIER_CLASS_ADMINISTRATOR : + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsAdmins++; + break; + case SOLDIER_CLASS_CREATURE : + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++; + break; + default : + if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) ) + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsCreatures++; + else if ( TANK( pTarget->pSoldier ) ) // we hardly can kill a tank in autoresolve, but well.. who knows.. + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsTanks++; + else if ( pTarget->pSoldier->bTeam == CIV_TEAM && !pTarget->pSoldier->aiData.bNeutral && pTarget->pSoldier->bSide != gbPlayerNum ) + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsHostiles++; + else + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usKillsOthers++; + break; + } + ///////////////////////////////////////////////////////////////////////////////////// gStrategicStatus.usPlayerKills++; } else if( pAttacker->uiFlags & CELL_MILITIA ) @@ -4203,6 +4535,15 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) PlayAutoResolveSample( (UINT8)HEADCR_1, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); } } + /////////////////////////////////////////////////////////////// + // SANDRO - added the insta-healable value for doctor trait + else if ((IS_MERC_BODY_TYPE( pTarget->pSoldier ) || IS_CIV_BODY_TYPE( pTarget->pSoldier )) && ( gGameOptions.fNewTraitSystem )) + { + pTarget->pSoldier->iHealableInjury += ((pTarget->pSoldier->stats.bLife - iNewLife) * 100); + if (pTarget->pSoldier->iHealableInjury > ((pTarget->pSoldier->stats.bLifeMax - pTarget->pSoldier->stats.bLife) * 100)) + pTarget->pSoldier->iHealableInjury = ((pTarget->pSoldier->stats.bLifeMax - pTarget->pSoldier->stats.bLife) * 100); + } + /////////////////////////////////////////////////////////////// //Adjust the soldiers stats based on the damage. pTarget->pSoldier->stats.bLife = (INT8)max( iNewLife, 0 ); if( pTarget->uiFlags & CELL_MERC && gpAR->pRobotCell) @@ -4218,6 +4559,10 @@ void AttackTarget( SOLDIERCELL *pAttacker, SOLDIERCELL *pTarget ) } if( !pTarget->pSoldier->stats.bLife ) { + // SANDRO - added check to erase insta-healable amount of HPs if dead + if (pTarget->pSoldier->iHealableInjury > 0) + { pTarget->pSoldier->iHealableInjury = 0; } + gpAR->fRenderAutoResolve = TRUE; #ifdef INVULNERABILITY if( 1 ) @@ -4294,13 +4639,14 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index ) if( pAttacker->uiFlags & CELL_MERC ) { //Attacker is a player, so increment the number of shots that hit. - gMercProfiles[ pAttacker->pSoldier->ubProfile ].usShotsHit++; + gMercProfiles[ pAttacker->pSoldier->ubProfile ].records.usShotsHit++; // MARKSMANSHIP GAIN: Attacker's shot hits StatChange( pAttacker->pSoldier, MARKAMT, 6, FALSE ); // in addition to 3 for taking a shot } if( pTarget->uiFlags & CELL_MERC && pTarget->usHitDamage[ index ] ) { //Target is a player, so increment the times he has been wounded. - gMercProfiles[ pTarget->pSoldier->ubProfile ].usTimesWounded++; + if( pTarget->usHitDamage[index] > 1 ) + gMercProfiles[ pTarget->pSoldier->ubProfile ].records.usTimesWoundedShot++; // EXPERIENCE GAIN: Took some damage StatChange( pTarget->pSoldier, EXPERAMT, ( UINT16 )( 5 * ( pTarget->usHitDamage[ index ] / 10 ) ), FALSE ); } @@ -4337,7 +4683,34 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index ) { if( pKiller->uiFlags & CELL_MERC ) { - gMercProfiles[ pKiller->pSoldier->ubProfile ].usKills++; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + switch(pTarget->pSoldier->ubSoldierClass) + { + case SOLDIER_CLASS_ELITE : + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsElites++; + break; + case SOLDIER_CLASS_ARMY : + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsRegulars++; + break; + case SOLDIER_CLASS_ADMINISTRATOR : + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsAdmins++; + break; + case SOLDIER_CLASS_CREATURE : + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsCreatures++; + break; + default : + if ( CREATURE_OR_BLOODCAT( pTarget->pSoldier ) ) + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsCreatures++; + else if ( TANK( pTarget->pSoldier ) ) // we hardly can kill a tank in autoresolve, but well.. who knows.. + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsTanks++; + else if ( pTarget->pSoldier->bTeam == CIV_TEAM && !pTarget->pSoldier->aiData.bNeutral && pTarget->pSoldier->bSide != gbPlayerNum ) + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsHostiles++; + else + gMercProfiles[ pKiller->pSoldier->ubProfile ].records.usKillsOthers++; + break; + } + ///////////////////////////////////////////////////////////////////////////////////// gStrategicStatus.usPlayerKills++; // EXPERIENCE CLASS GAIN: Earned a kill StatChange( pKiller->pSoldier, EXPERAMT, ( UINT16 )( 10 * pTarget->pSoldier->pathing.bLevel ), FALSE ); @@ -4350,7 +4723,22 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index ) { if( pAssister1->uiFlags & CELL_MERC ) { - gMercProfiles[ pAssister1->pSoldier->ubProfile ].usAssists++; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if( pKiller ) + { + if( pKiller->uiFlags & CELL_MERC && pKiller->pSoldier->bTeam == gbPlayerNum ) + gMercProfiles[ pAssister1->pSoldier->ubProfile ].records.usAssistsMercs++; + else if ( pKiller->pSoldier->bTeam == MILITIA_TEAM ) + gMercProfiles[ pAssister1->pSoldier->ubProfile ].records.usAssistsMilitia++; + else + gMercProfiles[ pAssister1->pSoldier->ubProfile ].records.usAssistsOthers++; + } + else + { + gMercProfiles[ pAssister1->pSoldier->ubProfile ].records.usAssistsOthers++; + } + ///////////////////////////////////////////////////////////////////////////////////// // EXPERIENCE CLASS GAIN: Earned an assist StatChange( pAssister1->pSoldier, EXPERAMT, ( UINT16 )( 5 * pTarget->pSoldier->pathing.bLevel ), FALSE ); } @@ -4361,7 +4749,22 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index ) { if( pAssister2->uiFlags & CELL_MERC ) { - gMercProfiles[ pAssister2->pSoldier->ubProfile ].usAssists++; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if( pKiller ) + { + if( pKiller->uiFlags & CELL_MERC && pKiller->pSoldier->bTeam == gbPlayerNum ) + gMercProfiles[ pAssister2->pSoldier->ubProfile ].records.usAssistsMercs++; + else if ( pKiller->pSoldier->bTeam == MILITIA_TEAM ) + gMercProfiles[ pAssister2->pSoldier->ubProfile ].records.usAssistsMilitia++; + else + gMercProfiles[ pAssister2->pSoldier->ubProfile ].records.usAssistsOthers++; + } + else + { + gMercProfiles[ pAssister2->pSoldier->ubProfile ].records.usAssistsOthers++; + } + ///////////////////////////////////////////////////////////////////////////////////// // EXPERIENCE CLASS GAIN: Earned an assist StatChange( pAssister2->pSoldier, EXPERAMT, ( UINT16 )( 5 * pTarget->pSoldier->pathing.bLevel ), FALSE ); } @@ -4396,6 +4799,15 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index ) return; #endif } + /////////////////////////////////////////////////////////////// + // SANDRO - added the insta-healable value for doctor trait + else if ((IS_MERC_BODY_TYPE( pTarget->pSoldier ) || IS_CIV_BODY_TYPE( pTarget->pSoldier )) && ( gGameOptions.fNewTraitSystem )) + { + pTarget->pSoldier->iHealableInjury += ((pTarget->pSoldier->stats.bLife - iNewLife) * 100); + if (pTarget->pSoldier->iHealableInjury > ((pTarget->pSoldier->stats.bLifeMax - pTarget->pSoldier->stats.bLife) * 100)) + pTarget->pSoldier->iHealableInjury = ((pTarget->pSoldier->stats.bLifeMax - pTarget->pSoldier->stats.bLife) * 100); + } + /////////////////////////////////////////////////////////////// //Adjust the soldiers stats based on the damage. pTarget->pSoldier->stats.bLife = (INT8)max( iNewLife, 0 ); if( pTarget->uiFlags & CELL_MERC && gpAR->pRobotCell) @@ -4409,6 +4821,10 @@ void TargetHitCallback( SOLDIERCELL *pTarget, INT32 index ) pTarget->pSoldier->bBleeding = (INT8)(pTarget->pSoldier->stats.bLifeMax - pTarget->pSoldier->stats.bLife); if( !pTarget->pSoldier->stats.bLife ) { + // SANDRO - added check to erase insta-healable amount of HPs if dead + if (pTarget->pSoldier->iHealableInjury > 0) + { pTarget->pSoldier->iHealableInjury = 0; } + gpAR->fRenderAutoResolve = TRUE; if( pTarget->uiFlags & CELL_MERC ) { @@ -4504,6 +4920,7 @@ BOOLEAN IsBattleOver() { gpMercs[ i ].pSoldier->DoMercBattleSound( BATTLE_SOUND_DIE1 ); gpMercs[ i ].pSoldier->stats.bLife = 0; + gpMercs[ i ].pSoldier->iHealableInjury = 0; // added by SANDRO gpAR->ubAliveMercs--; } } diff --git a/Strategic/Campaign Init.cpp b/Strategic/Campaign Init.cpp index 872fcbfb..9f9ec7c6 100644 --- a/Strategic/Campaign Init.cpp +++ b/Strategic/Campaign Init.cpp @@ -20,7 +20,7 @@ #endif #include "connect.h" -#include "VFS/vfs.h" +#include #include "XMLWriter.h" #include "UndergroundInit.h" @@ -434,7 +434,8 @@ void BuildUndergroundSectorInfoList() TrashUndergroundSectorInfo(); - if (LetLuaBuildUndergroundSectorInfoList()) + //if (LetLuaBuildUndergroundSectorInfoList()) + g_luaUnderground.InitializeSectorList(); // lua script succeeded return; diff --git a/Strategic/Campaign Types.h b/Strategic/Campaign Types.h index 6e21924d..eb52db81 100644 --- a/Strategic/Campaign Types.h +++ b/Strategic/Campaign Types.h @@ -210,7 +210,7 @@ typedef struct FACILITYRISKTYPE { // The risks involved with perfoming an assignment at a specific facility. - UINT8 ubChance; // Chance out of X that this risk will trigger every hour. X is INI-defined and is normally 1000. + UINT16 usChance; // Chance out of X that this risk will trigger every hour. X is INI-defined and is normally 1000. INT8 bBaseEffect; // Base result. If negative, result will always be negative. If positive, result will always be positive. // If 0, result can be either negative or positive. UINT8 ubRange; // Range of deviation for the base effect. @@ -480,6 +480,9 @@ typedef struct UNDERGROUND_SECTORINFO UINT8 ubCreatureHabitat; //determines how creatures live in this sector (see creature spreading.c) UINT8 ubElitesInBattle, ubTroopsInBattle, ubAdminsInBattle, ubCreaturesInBattle; + // adding these (should not change struct layout due to padding) + UINT8 ubMusicMode, ubUnsed; + UINT32 uiNumberOfWorldItemsInTempFileThatCanBeSeenByPlayer; INT8 bPadding[36]; //no padding left! @@ -492,4 +495,12 @@ extern std::vector SectorInfo; extern UNDERGROUND_SECTORINFO *gpUndergroundSectorInfoHead; +enum CreateMusic +{ + CM_COMPAT, + CM_AUTO, + CM_NEVER, + CM_ALWAYS, +}; + #endif \ No newline at end of file diff --git a/Strategic/Creature Spreading.cpp b/Strategic/Creature Spreading.cpp index 19d76ae7..a40f8760 100644 --- a/Strategic/Creature Spreading.cpp +++ b/Strategic/Creature Spreading.cpp @@ -33,6 +33,7 @@ #include "Map Information.h" #endif +#include "Strategic Mines.h" #include "connect.h" @@ -106,7 +107,7 @@ //When either in a cave level with blue lights or there is a creature presence, then //we override the normal music with the creature music. The conditions are maintained //inside the function PrepareCreaturesForBattle() in this module. -BOOLEAN gfUseCreatureMusic = FALSE; +//BOOLEAN gfUseCreatureMusic = FALSE; // moved to music control.cpp BOOLEAN gfCreatureMeanwhileScenePlayed = FALSE; enum { @@ -148,7 +149,7 @@ extern UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSect extern void BuildUndergroundSectorInfoList(); void DeleteCreatureDirectives(); -extern MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ]; +//extern MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ]; CREATURE_DIRECTIVE* NewDirective( UINT8 ubSectorID, UINT8 ubSectorZ, UINT8 ubCreatureHabitat ) { @@ -329,26 +330,35 @@ void InitCreatureQuest() memset( fMineInfectible, 1, sizeof( BOOLEAN ) * 4 ); if( gMineStatus[ MINE_DRASSEN ].fAttackedHeadMiner || - gMineStatus[ MINE_DRASSEN ].uiOreRunningOutPoint || - StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_D13 ) ].fEnemyControlled ) + //gMineStatus[ MINE_DRASSEN ].uiOreRunningOutPoint || + !gMineStatus[ MINE_DRASSEN ].fInfectible || + //StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_D13 ) ].fEnemyControlled + StrategicMap[ gMineStatus[MINE_DRASSEN].StrategicIndex() ].fEnemyControlled + ) { //If head miner was attacked, ore will/has run out, or enemy controlled fMineInfectible[ 0 ] = FALSE; } if( gMineStatus[ MINE_CAMBRIA ].fAttackedHeadMiner || - gMineStatus[ MINE_CAMBRIA ].uiOreRunningOutPoint || - StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_H8 ) ].fEnemyControlled ) + //gMineStatus[ MINE_CAMBRIA ].uiOreRunningOutPoint || + !gMineStatus[ MINE_CAMBRIA ].fInfectible || + //StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_H8 ) ].fEnemyControlled ) + StrategicMap[ gMineStatus[MINE_CAMBRIA].StrategicIndex() ].fEnemyControlled ) { //If head miner was attacked, ore will/has run out, or enemy controlled fMineInfectible[ 1 ] = FALSE; } if( gMineStatus[ MINE_ALMA ].fAttackedHeadMiner || - gMineStatus[ MINE_ALMA ].uiOreRunningOutPoint || - StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_I14 ) ].fEnemyControlled ) + //gMineStatus[ MINE_ALMA ].uiOreRunningOutPoint || + !gMineStatus[ MINE_ALMA ].fInfectible || + //StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_I14 ) ].fEnemyControlled ) + StrategicMap[ gMineStatus[MINE_ALMA].StrategicIndex() ].fEnemyControlled ) { //If head miner was attacked, ore will/has run out, or enemy controlled fMineInfectible[ 2 ] = FALSE; } if( gMineStatus[ MINE_GRUMM ].fAttackedHeadMiner || - gMineStatus[ MINE_GRUMM ].uiOreRunningOutPoint || - StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_H3 ) ].fEnemyControlled ) + //gMineStatus[ MINE_GRUMM ].uiOreRunningOutPoint || + !gMineStatus[ MINE_GRUMM ].fInfectible || + //StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( SEC_H3 ) ].fEnemyControlled ) + StrategicMap[ gMineStatus[MINE_GRUMM].StrategicIndex() ].fEnemyControlled ) { //If head miner was attacked, ore will/has run out, or enemy controlled fMineInfectible[ 3 ] = FALSE; } @@ -786,7 +796,7 @@ void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) { case SEC_D13: //DRASSEN gsCreatureInsertionCode = INSERTION_CODE_GRIDNO; - gsCreatureInsertionGridNo = 20703; + gsCreatureInsertionGridNo = 20703;//dnl!!! break; case SEC_C13: gsCreatureInsertionCode = INSERTION_CODE_SOUTH; @@ -796,7 +806,7 @@ void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) break; case SEC_H3: //GRUMM gsCreatureInsertionCode = INSERTION_CODE_GRIDNO; - gsCreatureInsertionGridNo = 10303; + gsCreatureInsertionGridNo = 10303; //dnl!!! break; case SEC_H2: gsCreatureInsertionCode = INSERTION_CODE_EAST; @@ -812,7 +822,7 @@ void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) break; case SEC_H8: //CAMBRIA gsCreatureInsertionCode = INSERTION_CODE_GRIDNO; - gsCreatureInsertionGridNo = 13005; + gsCreatureInsertionGridNo = 13005; //dnl!!! break; case SEC_G8: gsCreatureInsertionCode = INSERTION_CODE_SOUTH; @@ -828,7 +838,7 @@ void ChooseTownSectorToAttack( UINT8 ubSectorID, BOOLEAN fOverrideTest ) break; case SEC_I14: //ALMA gsCreatureInsertionCode = INSERTION_CODE_GRIDNO; - gsCreatureInsertionGridNo = 9726; + gsCreatureInsertionGridNo = 9726; //dnl!!! break; case SEC_I13: gsCreatureInsertionCode = INSERTION_CODE_EAST; @@ -940,7 +950,7 @@ void CreatureAttackTown( UINT8 ubSectorID, BOOLEAN fOverrideTest ) case CREATURE_BATTLE_CODE_TACTICALLYADD: if (is_networked) { - if(is_server && CREATURE_ENABLED==1) + if(is_server && gCreatureEnabled == 1) PrepareCreaturesForBattle(); } else @@ -1215,35 +1225,56 @@ BOOLEAN PrepareCreaturesForBattle() if( !gubCreatureBattleCode ) { ubNumColors = LightGetColors( LColors ); + + if (! gbWorldSectorZ ) + { + UseCreatureMusic(LColors->peBlue); + return FALSE; //Creatures don't attack overworld with this battle code. + } + + pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + if( !pSector ) + { + return FALSE; + } + //if( ubNumColors != 1 ) // ScreenMsg( FONT_RED, MSG_ERROR, L"This map has more than one light color -- KM, LC : 1" ); //By default, we only play creature music in the cave levels (the creature levels all consistently //have blue lights while human occupied mines have red lights. We always play creature music //when creatures are in the level. - if( LColors->peBlue ) - gfUseCreatureMusic = TRUE; - else - gfUseCreatureMusic = FALSE; + BOOLEAN fCreatures = pSector->ubNumCreatures > 0; - if( !gbWorldSectorZ ) - return FALSE; //Creatures don't attack overworld with this battle code. - pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); - if( !pSector ) + switch (pSector->ubMusicMode) + { + case CM_AUTO: + UseCreatureMusic(fCreatures); + break; + case CM_NEVER: + UseCreatureMusic(FALSE); + break; + case CM_ALWAYS: + UseCreatureMusic(TRUE); + break; + case CM_COMPAT: + default: + UseCreatureMusic(LColors->peBlue || fCreatures); + break; + } + + if( !fCreatures ) { return FALSE; } - if( !pSector->ubNumCreatures ) - { - return FALSE; - } - gfUseCreatureMusic = TRUE; //creatures are here, so play creature music + //gfUseCreatureMusic = TRUE; //creatures are here, so play creature music ubCreatureHabitat = pSector->ubCreatureHabitat; ubNumCreatures = pSector->ubNumCreatures; } else { //creatures are attacking a town sector - gfUseCreatureMusic = TRUE; + //gfUseCreatureMusic = TRUE; + UseCreatureMusic(TRUE); SetMusicMode( MUSIC_TACTICAL_NOTHING ); ubCreatureHabitat = MINE_EXIT; ubNumCreatures = gubNumCreaturesAttackingTown; @@ -1401,6 +1432,8 @@ void CreatureNightPlanning() void CheckConditionsForTriggeringCreatureQuest( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) { + +// move to Scripts/StrategicTownLoyalty.lua UINT8 ubValidMines = 0; if( !(gGameOptions.ubGameStyle == STYLE_SCIFI) || !gGameExternalOptions.fEnableCrepitus) return; //No scifi, no creatures... @@ -1452,7 +1485,8 @@ BOOLEAN SaveCreatureDirectives( HWFILE hFile ) { return( FALSE ); } - FileWrite( hFile, &gfUseCreatureMusic, 1, &uiNumBytesWritten ); + BOOLEAN fUseCreatureMusic = UsingCreatureMusic(); + FileWrite( hFile, &fUseCreatureMusic, 1, &uiNumBytesWritten ); if( uiNumBytesWritten != sizeof( BOOLEAN ) ) { return( FALSE ); @@ -1486,11 +1520,13 @@ BOOLEAN LoadCreatureDirectives( HWFILE hFile, UINT32 uiSavedGameVersion ) return( FALSE ); } - FileRead( hFile, &gfUseCreatureMusic, 1, &uiNumBytesRead ); + BOOLEAN fUseCreatureMusic; + FileRead( hFile, &fUseCreatureMusic, 1, &uiNumBytesRead ); if( uiNumBytesRead != sizeof( BOOLEAN ) ) { return( FALSE ); } + UseCreatureMusic(fUseCreatureMusic); if( uiSavedGameVersion >= 82 ) { @@ -1535,7 +1571,7 @@ BOOLEAN LoadCreatureDirectives( HWFILE hFile, UINT32 uiSavedGameVersion ) void ForceCreaturesToAvoidMineTemporarily( UINT8 ubMineIndex ) { - gMineStatus[ MINE_GRUMM ].usValidDayCreaturesCanInfest = (UINT16)(GetWorldDay() + 2); + gMineStatus[ ubMineIndex ].usValidDayCreaturesCanInfest = (UINT16)(GetWorldDay() + 2); } BOOLEAN PlayerGroupIsInACreatureInfestedMine() diff --git a/Strategic/Creature Spreading.h b/Strategic/Creature Spreading.h index e6532901..6aae1b5b 100644 --- a/Strategic/Creature Spreading.h +++ b/Strategic/Creature Spreading.h @@ -20,7 +20,7 @@ void CheckConditionsForTriggeringCreatureQuest( INT16 sSectorX, INT16 sSectorY, void ForceCreaturesToAvoidMineTemporarily( UINT8 ubMineIndex ); -extern BOOLEAN gfUseCreatureMusic; +//extern BOOLEAN gfUseCreatureMusic; BOOLEAN MineClearOfMonsters( UINT8 ubMineIndex ); @@ -55,4 +55,6 @@ void DetermineCreatureTownCompositionBasedOnTacticalInformation( UINT8 *pubNumCr BOOLEAN PlayerGroupIsInACreatureInfestedMine(); +extern INT32 giLairID; + #endif \ No newline at end of file diff --git a/Strategic/Facilities.cpp b/Strategic/Facilities.cpp index 08fea50b..85a55ce1 100644 --- a/Strategic/Facilities.cpp +++ b/Strategic/Facilities.cpp @@ -281,7 +281,7 @@ INT16 GetSectorModifier( SOLDIERTYPE *pSoldier, UINT8 ubModifierType ) case FACILITY_SLEEP_MOD: case FACILITY_KIT_DEGRADE_MOD: case FACILITY_MINE_INCOME_MOD: - Result = 100 + ((100-Result) + (100-sCurrent)); + Result = 100 + ((Result-100) + (sCurrent-100)); break; case FACILITY_MAX_MORALE: @@ -517,7 +517,7 @@ void UpdateSkyriderCostModifier() ubCounter++; continue; } - UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); + UINT8 ubAssignmentType = (UINT8)GetSoldierFacilityAssignmentIndex( pSoldier ); // Is character using a facility? if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) && @@ -580,7 +580,7 @@ void UpdateFacilityUsageCosts( ) ubCounter++; continue; } - UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); + UINT8 ubAssignmentType = (UINT8)GetSoldierFacilityAssignmentIndex( pSoldier ); // Is character using a facility? if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) && @@ -715,7 +715,7 @@ INT32 MineIncomeModifierFromFacility( UINT8 ubMine ) ubCounter++; continue; } - UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); + UINT8 ubAssignmentType = (UINT8)GetSoldierFacilityAssignmentIndex( pSoldier ); // Is character using a facility? if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) && @@ -816,6 +816,9 @@ INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier ) case EXPLOSIVE_ASSIGN: bAssignmentIndex = FAC_PRACTICE_EXPLOSIVES; break; + default: + bAssignmentIndex = -1; + break; } break; case TRAIN_TEAMMATE: @@ -848,6 +851,9 @@ INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier ) case EXPLOSIVE_ASSIGN: bAssignmentIndex = FAC_TRAINER_EXPLOSIVES; break; + default: + bAssignmentIndex = -1; + break; } break; case TRAIN_BY_OTHER: @@ -880,6 +886,9 @@ INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier ) case EXPLOSIVE_ASSIGN: bAssignmentIndex = FAC_STUDENT_EXPLOSIVES; break; + default: + bAssignmentIndex = -1; + break; } break; case FACILITY_STAFF: @@ -890,6 +899,7 @@ INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier ) break; default: bAssignmentIndex = -1; + break; } return (bAssignmentIndex); @@ -901,12 +911,12 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil { INT16 Result = 0; - UINT8 ubChance; + INT32 iChance; INT8 bBaseEffect; UINT8 ubRange; // Read risk data directly from facility array. - ubChance = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].ubChance; + iChance = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].usChance; bBaseEffect = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].bBaseEffect; ubRange = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].ubRange; @@ -931,24 +941,24 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil } /////////////// - INT8 bAbsoluteMaxResult; - INT8 bAbsoluteMinResult; + INT16 sAbsoluteMaxResult; + INT16 sAbsoluteMinResult; // Calculate absolute maximum variance. The result can never be outside these. if (bBaseEffect < 0) { - bAbsoluteMaxResult = __min((bBaseEffect + ubRange), -1); - bAbsoluteMinResult = bBaseEffect - ubRange; + sAbsoluteMaxResult = __min((bBaseEffect + ubRange), -1); + sAbsoluteMinResult = bBaseEffect - ubRange; } else if (bBaseEffect > 0) { - bAbsoluteMaxResult = bBaseEffect + ubRange; - bAbsoluteMinResult = __max(1, (bBaseEffect - ubRange)); + sAbsoluteMaxResult = bBaseEffect + ubRange; + sAbsoluteMinResult = __max(1, (bBaseEffect - ubRange)); } else { - bAbsoluteMaxResult = bBaseEffect + ubRange; - bAbsoluteMinResult = bBaseEffect - ubRange; + sAbsoluteMaxResult = bBaseEffect + ubRange; + sAbsoluteMinResult = bBaseEffect - ubRange; } INT8 bCombinedStats; @@ -995,7 +1005,7 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubLeadership * 0.4) + (ubExpLevel * 4)); break; case RISK_FATIGUE: - bCombinedStats = (INT8)__min(100, (ubAgility * 0.1) + (ubStrength * 0.3) + (ubHealth * 0.2) + (ubExpLevel * 5)); + bCombinedStats = (INT8)__min(100, (ubAgility * 0.1) + (ubStrength * 0.3) + (ubHealth * 0.2) + (ubExpLevel * 4)); break; case RISK_DRUNK: bCombinedStats = (INT8)__min(100, (ubWisdom * 0.5) + (ubHealth * 0.3) + (ubExpLevel * 2)); @@ -1008,15 +1018,15 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil break; } - if (bCombinedStats == 100) + if (bCombinedStats >= 100) { // Character is as skilled as possible. Automatic "best" result. - return (bAbsoluteMaxResult); + return (sAbsoluteMaxResult); } - if (bCombinedStats == 0) + if (bCombinedStats <= 0) { // Character is completely inept? Strange. Automatic "worst" result. - return (bAbsoluteMinResult); + return (sAbsoluteMinResult); } // we now have a range of 0 to 100. Let's apply an externalized modifier of 0 to -100. @@ -1026,20 +1036,23 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil if (bBaseEffect > 0 ) { // Chance increases with good stats, decreased with bad stats. - ubChance = ubChance + ((bCombinedStats * ubChance) / 100 ); + iChance = iChance + ((bCombinedStats * iChance) / 100 ); } else if (bBaseEffect < 0 ) { // Chance decreases with good stats, increases with bad stats. - ubChance = ubChance - ((bCombinedStats * ubChance) / 100 ); + iChance = iChance - ((bCombinedStats * iChance) / 100 ); } else { // Chance is unaffected } + // Limit iChance into a 0 to 50000 range. + iChance = __max(0, __min(iChance, 50000)); + // Alright, let's see if the event is triggered. - if (PreRandom(gGameExternalOptions.usFacilityEventRarity)>ubChance) + if (PreRandom(gGameExternalOptions.usFacilityEventRarity)>(UINT32)iChance) { // Chance failed to trigger. return (0); @@ -1052,8 +1065,8 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil // We use this to move the Base Effect point from its original location, effectively giving us a better // or worse result based on our stats. bBaseEffect += (bCombinedStats * (ubRange+1)) / 100; - bBaseEffect = __min(bBaseEffect, bAbsoluteMaxResult); - bBaseEffect = __max(bBaseEffect, bAbsoluteMinResult); + bBaseEffect = __min(bBaseEffect, sAbsoluteMaxResult); + bBaseEffect = __max(bBaseEffect, sAbsoluteMinResult); // The deviation is also affected by our stats. ubRange -= abs((bCombinedStats * (ubRange+1)) / 100); // If the Base Effect has moved any, then the range shrinks accordingly. @@ -1067,13 +1080,14 @@ INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacil Result = bBaseEffect + ((PreRandom((ubRange*2)+1)) - ubRange); // Naturally, the character can't ever breach the range of possible results as defined by the facility data. - Result = __min(Result, bAbsoluteMaxResult); - Result = __max(Result, bAbsoluteMinResult); + Result = __min(Result, sAbsoluteMaxResult); + Result = __max(Result, sAbsoluteMinResult); return (Result); } } + void HandleHourlyRisks() { INT32 iCounter = 0; @@ -1104,11 +1118,11 @@ void HandleRisksForSoldier( SOLDIERTYPE *pSoldier ) UINT8 ubFacilityType = 0; UINT8 ubAssignmentType = 0; - if (pSoldier->sFacilityTypeOperated != -1) + if (pSoldier->sFacilityTypeOperated != -1 && GetSoldierFacilityAssignmentIndex( pSoldier ) != -1) { // Soldier is working at a specific facility. Risks associated with this specific facility and assignment // have priority. - ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); + ubAssignmentType = (UINT8)GetSoldierFacilityAssignmentIndex( pSoldier ); ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated; HandleRisksForSoldierFacilityAssignment( pSoldier, ubFacilityType, ubAssignmentType ); } @@ -1145,7 +1159,7 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac { fBadResult = FALSE; - if (gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[iCounter].ubChance > 0) + if (gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[iCounter].usChance > 0) { if (iCounter == RISK_LOYALTY_LOCAL) { @@ -1174,11 +1188,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bStrength = __max(1,pSoldier->stats.bStrength + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bStrength - 1)) + Result = -1*(pSoldier->stats.bStrength - 1); + pSoldier->stats.bStrength += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1207,11 +1240,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bAgility = __max(1,pSoldier->stats.bAgility + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bAgility - 1)) + Result = -1*(pSoldier->stats.bAgility - 1); + pSoldier->stats.bAgility += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( AGIL_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( AGIL_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1240,11 +1292,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bDexterity = __max(1,pSoldier->stats.bDexterity + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bDexterity - 1)) + Result = -1*(pSoldier->stats.bDexterity - 1); + pSoldier->stats.bDexterity += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1273,11 +1344,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bWisdom = __max(1,pSoldier->stats.bWisdom + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bWisdom - 1)) + Result = -1*(pSoldier->stats.bWisdom - 1); + pSoldier->stats.bWisdom += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1306,12 +1396,31 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bLifeMax = __max(1,pSoldier->stats.bLifeMax + Result); - gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeHealthTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( HEALTH_INCREASE ); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bLifeMax - 1)) + Result = -1*(pSoldier->stats.bLifeMax - 1); + pSoldier->stats.bLifeMax += Result; pSoldier->stats.bLife += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_HEALTH ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeHealthTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( HEALTH_INCREASE ); + } + // Update Profile + gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax; + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// if (pSoldier->stats.bLife < OKLIFE) { HandleTakeDamageDeath( pSoldier, 0, TAKE_DAMAGE_BLOODLOSS ); @@ -1360,11 +1469,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bMarksmanship = __max(1,pSoldier->stats.bMarksmanship + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bMarksmanship - 1)) + Result = -1*(pSoldier->stats.bMarksmanship - 1); + pSoldier->stats.bMarksmanship += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_MARKSMANSHIP ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeMarksmanshipTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( MRK_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bMarksmanship = pSoldier->stats.bMarksmanship; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeMarksmanshipTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( MRK_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1393,11 +1521,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bLeadership = __max(1,pSoldier->stats.bLeadership + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bLeadership - 1)) + Result = -1*(pSoldier->stats.bLeadership - 1); + pSoldier->stats.bLeadership += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_LEADERSHIP ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeLeadershipTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( LDR_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bLeadership = pSoldier->stats.bLeadership; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeLeadershipTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( LDR_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1426,11 +1573,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bMechanical = __max(1,pSoldier->stats.bMechanical + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bMechanical - 1)) + Result = -1*(pSoldier->stats.bMechanical - 1); + pSoldier->stats.bMechanical += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_MECHANICAL ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeMechanicalTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( MECH_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bMechanical = pSoldier->stats.bMechanical; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeMechanicalTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( MECH_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1459,11 +1625,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bMedical = __max(1,pSoldier->stats.bMedical + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bMedical - 1)) + Result = -1*(pSoldier->stats.bMedical - 1); + pSoldier->stats.bMedical += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_MEDICAL ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeMedicalTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( MED_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bMedical = pSoldier->stats.bMedical; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeMedicalTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( MED_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1492,11 +1677,30 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else { // Soldier is suffering direct stat damage. - pSoldier->stats.bExplosive = __max(1,pSoldier->stats.bExplosive + Result); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable + if ( (-1*Result) > (pSoldier->stats.bExplosive - 1)) + Result = -1*(pSoldier->stats.bExplosive - 1); + pSoldier->stats.bExplosive += Result; + if ( gGameOptions.fNewTraitSystem && (Result <= 0) ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_EXPLOSIVES ] -= Result; + } + else + { + // make this stat RED for a while... + pSoldier->timeChanges.uiChangeExplosivesTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( EXP_INCREASE ); + } + // Update Profile gMercProfiles[ pSoldier->ubProfile ].bExplosive = pSoldier->stats.bExplosive; - // make this stat RED for a while... - pSoldier->timeChanges.uiChangeExplosivesTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( EXP_INCREASE ); + + // merc records - stat damaged + if( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + /////////////////////////////////////////////////////////////////////////////////////////// fBadResult = TRUE; // Log message @@ -1521,6 +1725,9 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac pSoldier->SoldierTakeDamage( 0, abs(Result), abs(Result), TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, FALSE ); fBadResult = TRUE; + // SANDRO - add to merc records - facility accidents counter + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + if (pSoldier->stats.bLife > 0) { if (pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD) @@ -1564,10 +1771,16 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac pSoldier->aiData.bMorale = __min(100,__max(0, pSoldier->aiData.bMorale + Result)); pSoldier->aiData.bStrategicMoraleMod = __min(50,__max(-50, pSoldier->aiData.bStrategicMoraleMod + Result)); RefreshSoldierMorale( pSoldier ); + // SANDRO - add to merc records - facility accidents counter + if ( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; break; case RISK_FATIGUE: pSoldier->bBreathMax = __min(100,__max(0, pSoldier->bBreathMax + Result)); pSoldier->bBreath = pSoldier->bBreathMax; + // SANDRO - add to merc records - facility accidents counter + if ( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; break; case RISK_DRUNK: @@ -1612,23 +1825,87 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac // Keel over... DeductPoints( pSoldier, 0, 10000 ); + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable // Permanently lower certain stats... - pSoldier->stats.bWisdom = __max(1, pSoldier->stats.bWisdom-5); - pSoldier->stats.bDexterity = __max(1, pSoldier->stats.bDexterity-5); - pSoldier->stats.bStrength = __max(1, pSoldier->stats.bStrength-5); + if ( gGameOptions.fNewTraitSystem ) + { + // WISDOM decrease + if ( pSoldier->stats.bWisdom > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] += 5; + pSoldier->stats.bWisdom -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] += (pSoldier->stats.bWisdom - 1); + pSoldier->stats.bWisdom = 1; + } + // DEXTERITY decrease + if ( pSoldier->stats.bDexterity > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] += 5; + pSoldier->stats.bDexterity -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] += (pSoldier->stats.bDexterity - 1); + pSoldier->stats.bDexterity = 1; + } + // STRENGTH decrease + if ( pSoldier->stats.bStrength > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] += 5; + pSoldier->stats.bStrength -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] += (pSoldier->stats.bStrength - 1); + pSoldier->stats.bStrength = 1; + } + // AGILITY decrease + if ( pSoldier->stats.bAgility > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] += 5; + pSoldier->stats.bAgility -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] += (pSoldier->stats.bAgility - 1); + pSoldier->stats.bAgility = 1; + } + } + else // old system + { + pSoldier->stats.bAgility = __max(1, pSoldier->stats.bWisdom-5); + pSoldier->stats.bDexterity = __max(1, pSoldier->stats.bDexterity-5); + pSoldier->stats.bStrength = __max(1, pSoldier->stats.bStrength-5); + pSoldier->stats.bAgility = __max(1, pSoldier->stats.bAgility-5); + + // make those stats RED for a while... + // SANDRO - we don't need to do this with new system, as we simply show all damaged stats in red until healed + pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); + pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); + pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( AGIL_INCREASE ); + } // export stat changes to profile gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom; gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity; gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength; - - // make those stats RED for a while... - pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); - pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); - pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility; + + fBadResult = TRUE; // stop the time, call a doctor, we had a heart attack! + + // merc records - stat damaged + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } break; case RISK_LOYALTY_LOCAL: @@ -1646,6 +1923,10 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else swprintf( sString, gzFacilityErrorMessage[24], pTownNames[ubTownID], pSoldier->name, gFacilityTypes[ubFacilityType].szFacilityName ); ScreenMsg( usColor, MSG_INTERFACE, sString ); + + // SANDRO - add to merc records - facility accidents counter + if ( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; } break; case RISK_LOYALTY_GLOBAL: @@ -1664,6 +1945,10 @@ void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFac else swprintf( sString, gzFacilityErrorMessage[26], pSoldier->name, szSectorGrid, gFacilityTypes[ubFacilityType].szFacilityName ); ScreenMsg( usColor, MSG_INTERFACE, sString ); + + // SANDRO - add to merc records - facility accidents counter + if ( Result < 0 ) + gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++; } break; default: @@ -1692,11 +1977,11 @@ INT32 GetTotalFacilityHourlyCosts( BOOLEAN fPositive ) // Is character truly valid? if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && - pSoldier->bSectorZ == 0 && + pSoldier->bSectorZ == 0 && pSoldier != NULL && pSoldier->stats.bLife >= OKLIFE && !(pSoldier->flags.fMercAsleep) ) { - UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); + INT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); if (ubAssignmentType == -1) { // Skip this character. @@ -1704,15 +1989,15 @@ INT32 GetTotalFacilityHourlyCosts( BOOLEAN fPositive ) continue; } - UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY); - UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated; + //UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY); + INT16 ubFacilityType = pSoldier->sFacilityTypeOperated; - if (!fPositive && // We want facilities that cost money to operate + if (!fPositive && ubFacilityType != -1 && // We want facilities that cost money to operate gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour > 0) // This facility costs money { iTotal += gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour; } - else if (fPositive && // We want facilities that GENERATE money + else if (fPositive && ubFacilityType != -1 && // We want facilities that GENERATE money gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour < 0) { // Flip the value to positive diff --git a/Strategic/Game Clock.cpp b/Strategic/Game Clock.cpp index 8520df5d..1cf5797a 100644 --- a/Strategic/Game Clock.cpp +++ b/Strategic/Game Clock.cpp @@ -27,6 +27,8 @@ #include "GameSettings.h" #endif +#include "LuaInitNPCs.h" + //#define DEBUG_GAME_CLOCK extern BOOLEAN gfFadeOut; @@ -247,6 +249,10 @@ void AdvanceClock( UINT8 ubWarpCode ) guiDay = ( guiGameClock / NUM_SEC_IN_DAY ); guiHour = ( guiGameClock - ( guiDay * NUM_SEC_IN_DAY ) ) / NUM_SEC_IN_HOUR; guiMin = ( guiGameClock - ( ( guiDay * NUM_SEC_IN_DAY ) + ( guiHour * NUM_SEC_IN_HOUR ) ) ) / NUM_SEC_IN_MIN; + + uiHourLua = guiHour; + uiDayLua = guiDay; + uiMinLua = guiMin; swprintf( WORLDTIMESTR, L"%s %d, %02d:%02d", gpGameClockString[ STR_GAMECLOCK_DAY_NAME ], guiDay, guiHour, guiMin ); diff --git a/Strategic/Game Event Hook.cpp b/Strategic/Game Event Hook.cpp index 0dd606c2..1fcb6ba5 100644 --- a/Strategic/Game Event Hook.cpp +++ b/Strategic/Game Event Hook.cpp @@ -206,7 +206,7 @@ BOOLEAN ExecuteStrategicEvent( STRATEGICEVENT *pEvent ) DailyUpdateOfMercSite( (UINT16)GetWorldDay() ); break; case EVENT_DAY3_ADD_EMAIL_FROM_SPECK: - if(!bMercDayOne) + if ( gGameExternalOptions.fMercDayOne == FALSE && gGameExternalOptions.fAllMercsAvailable == FALSE ) { AddEmail(MERC_INTRO, MERC_INTRO_LENGTH, SPECK_FROM_MERC, GetWorldTotalMin( ), -1 ); } diff --git a/Strategic/Game Init.cpp b/Strategic/Game Init.cpp index 90996dfc..70ae65f2 100644 --- a/Strategic/Game Init.cpp +++ b/Strategic/Game Init.cpp @@ -63,12 +63,20 @@ #include "Interface Panels.h" // HEADROCK HAM 3.6: Include for adding facility debt reset #include "Facilities.h" + // HEADROCK HAM 4: Include for initializing Manual Restrictions + #include "MilitiaSquads.h" #include "Map Screen Interface Map Inventory.h"//dnl ch51 081009 #endif #include "Vehicles.h" #include "text.h" #include "connect.h" +#include "XML.h" +#include "mercs.h" +#include "aim.h" + +#include "LuaInitNPCs.h" + class OBJECTTYPE; class SOLDIERTYPE; @@ -85,7 +93,11 @@ extern UNDERGROUND_SECTORINFO* FindUnderGroundSector( INT16 sMapX, INT16 sMapY, UINT8 gubScreenCount=0; void InitNPCs( void ) -{ +{ + LetLuaGameInit(1); + + #if 0 + MERCPROFILESTRUCT * pProfile; // add the pilot at a random location! @@ -264,6 +276,9 @@ void InitNPCs( void ) // set up Devin so he will be placed ASAP gMercProfiles[ DEVIN ].bNPCData = 3; + +#endif + } void InitBloodCatSectors() @@ -320,7 +335,7 @@ void InitBloodCatSectors() } else { - THROWEXCEPTION(L"At least one Bloodcat Lair must be defined in BloodcatPlacements.XML!"); + SGP_THROW(L"At least one Bloodcat Lair must be defined in BloodcatPlacements.XML!"); } /* @@ -430,6 +445,9 @@ void InitStrategicLayer( void ) // HEADROCK HAM 3.6: Initialize facilities. InitFacilities(); + // HEADROCK HAM 4: Initialize Manual Mobile Militia Restrictions. + InitManualMobileRestrictions(); + // free up any leave list arrays that were left allocated ShutDownLeaveList( ); // re-set up leave list arrays for dismissed mercs @@ -460,11 +478,8 @@ void ShutdownStrategicLayer() } BOOLEAN InitNewGame( BOOLEAN fReset ) -{ - INT32 iStartingCash; - +{ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"InitNewGame"); -// static fScreenCount = 0; if( fReset ) { @@ -507,6 +522,7 @@ BOOLEAN InitNewGame( BOOLEAN fReset ) } DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"InitNewGame: init arms dealers"); + //Initialize the Arms Dealers and Bobby Rays inventory if( gubScreenCount == 0 ) { @@ -516,11 +532,82 @@ BOOLEAN InitNewGame( BOOLEAN fReset ) } DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"InitNewGame: clearing messages"); + // clear tactical ClearTacticalMessageQueue( ); // clear mapscreen messages - if(!is_networked)FreeGlobalMessageList(); //hayden + if(!is_networked) + FreeGlobalMessageList(); //hayden + + // Do not hide any person names + if ( gGameExternalOptions.fIndividualHiddenPersonNames == FALSE ) + { + for (int i=0;i<500;i++) + { + zHiddenNames[i].Hidden = FALSE; + } + } + else + { + // Hide individual person names depending on HiddenNames.xml + LoadHiddenNames(); + } + + // ------------------------ + // Camo Faces + // ------------------------ + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + for (int i=0;i<255;i++) + { + gCamoFace[i].gCamoface = FALSE; + gCamoFace[i].gUrbanCamoface = FALSE; + gCamoFace[i].gDesertCamoface = FALSE; + gCamoFace[i].gSnowCamoface = FALSE; + } + + if ( !gGameOptions.fNewTraitSystem ) // SANDRO - only with old traits, we get the camo instantly + { + for(int uiLoop=0; uiLoop< NUM_PROFILES; uiLoop++) + { + if ( ProfileHasSkillTrait( uiLoop, CAMOUFLAGED_OT ) > 0 ) + { + gCamoFace[uiLoop].gCamoface = TRUE; + } + } + } + } + + // ------------------------ + // Reset mercs profiles + // ------------------------ + UINT8 i; + + for(i=0; i 0 ) + { + gCamoFace[uiLoop].gCamoface = TRUE; + } +// else if ( gMercProfiles[uiLoop].bSkillTrait == CAMOUFLAGED_URBAN || gMercProfiles[uiLoop].bSkillTrait2 == CAMOUFLAGED_URBAN ) +// { +// gCamoFace[uiLoop].gUrbanCamoface = TRUE; +// } +// else if ( gMercProfiles[uiLoop].bSkillTrait == CAMOUFLAGED_DESERT || gMercProfiles[uiLoop].bSkillTrait2 == CAMOUFLAGED_DESERT ) +// { +// gCamoFace[uiLoop].gDesertCamoface = TRUE; +// } +// else if ( gMercProfiles[uiLoop].bSkillTrait == CAMOUFLAGED_SNOW || gMercProfiles[uiLoop].bSkillTrait2 == CAMOUFLAGED_SNOW ) +// { +// gCamoFace[uiLoop].gSnowCamoface = TRUE; +// } + } + } + + } + + //Legion by Jazz + if ( gGameExternalOptions.fIndividualHiddenPersonNames == FALSE ) + { + for (int i=0;i<500;i++) + { + zHiddenNames[i].Hidden = FALSE; + } + } + else + { + //Restart Game and New Game + LoadHiddenNames(); + } + SoundStopAll( ); @@ -1016,4 +1041,8 @@ void ReStartingGame() gubCheatLevel = STARTING_CHEAT_LEVEL; else gubCheatLevel = 0; + + //Lua + IniLuaGlobal(); + } \ No newline at end of file diff --git a/Strategic/Hourly Update.cpp b/Strategic/Hourly Update.cpp index b6304498..69e0f447 100644 --- a/Strategic/Hourly Update.cpp +++ b/Strategic/Hourly Update.cpp @@ -21,6 +21,8 @@ #include "Strategic AI.h" #endif +#include "Luaglobal.h" +#include "LuaInitNPCs.h" #include "SaveLoadGame.h" #include "GameSettings.h" #include "connect.h" @@ -130,6 +132,10 @@ void HandleQuarterHourUpdate() void HourlyQuestUpdate( void ) { UINT32 uiHour = GetWorldHour(); + +#ifdef LUA_HOURLY_QUEST_UPDATE + LetLuaHourlyQuestUpdate(0); +#else // brothel if ( uiHour == 4 ) @@ -184,6 +190,7 @@ void HourlyQuestUpdate( void ) SetFactFalse( FACT_MUSEUM_OPEN ); } +#endif } #define BAR_TEMPTATION 4 @@ -246,7 +253,7 @@ void HourlyLarryUpdate( void ) if ( usTemptation < BAR_TEMPTATION && GetCurrentBalance() >= Item[ ALCOHOL ].usPrice ) { if ( pSoldier->bSectorZ == 0 && - ( ( pSoldier->sSectorX == 13 && pSoldier->sSectorY == MAP_ROW_B) || + ( ( pSoldier->sSectorX == 13 && pSoldier->sSectorY == MAP_ROW_D) || ( pSoldier->sSectorX == 13 && pSoldier->sSectorY == MAP_ROW_C) || ( pSoldier->sSectorX == 5 && pSoldier->sSectorY == MAP_ROW_C) || ( pSoldier->sSectorX == 6 && pSoldier->sSectorY == MAP_ROW_C) || diff --git a/Strategic/LuaInitNPCs.cpp b/Strategic/LuaInitNPCs.cpp new file mode 100644 index 00000000..13dedd15 --- /dev/null +++ b/Strategic/LuaInitNPCs.cpp @@ -0,0 +1,10646 @@ +#include +#include +#include + +#include "Lua Interpreter.h" +#include "Strategic Mines.h" +#include "BobbyRMailOrder.h" +#include "Tactical Save.h" +#include "connect.h" +#include "FileMan.h" +#include "GameSettings.h" +#include "Game Init.h" +#include "interface Dialogue.h" +#include "opplist.h" +#include "Strategic All.h" +#include "pits.h" +#include "Game Event Hook.h" +#include "Creature Spreading.h" +#include "Luaglobal.h" +#include "Quests.h" +#include "ai.h" +#include "Game Clock.h" +#include "interface Dialogue.h" +#include "Map Screen Helicopter.h" +#include "NPC.h" +#include "Strategic AI.h" +#include "Tactical Save.h" +#include "Items.h" +#include "Handle Items.h" +#include "Overhead.h" +#include "LuaInitNPCs.h" +#include "ShopKeeper Interface.h" +#include "Explosion Control.h" +#include "soldier tile.h" +#include "Soldier Profile.h" +#include "Soldier Functions.h" +#include "soldier tile.h" +#include "Action Items.h" +#include "AIInternals.h" +#include "Handle Doors.h" +#include "soldier profile type.h" +#include "history.h" +#include "Merc Hiring.h" + +#include "LOS.h" +#include "Music Control.h" + +#include "Intro.h" +#include "End Game.h" +#include "Queen Command.h" +#include "gamescreen.h" +#include "Arms Dealer Init.h" + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +} + +#include "lua_state.h" +#include "lua_function.h" +#include +//-------------------------- UB ------------------------------ +extern BOOLEAN gfDoneWithSplashScreen; +extern UINT32 iStringToUseLua; +extern INT8 Test; + +void FatigueCharacter( SOLDIERTYPE *pSoldier ); + +static int l_AddCustomEmail (lua_State *L); + +static int l_WhoIsThere2 (lua_State *L); + +static int l_GuaranteeAtLeastXItemsOfIndex(lua_State *L); +static int l_gMercProfileGearset(lua_State *L); + +static int l_FindUnderGroundSector(lua_State *L); +static int l_AddEnemyToUnderGroundSector(lua_State *L); +static int l_FindUnderGroundSectorVisited(lua_State *L); + +//static int l_EnterTacticalInFinalSector(lua_State *L); + +static int l_ReStartingGame(lua_State *L); + +//Intro +static int l_DisplaySirtechSplashScreen(lua_State *L); +static int l_gfIntroScreenExit(lua_State *L); +static int l_gfEnteringMapScreen(lua_State *L); +static int l_gfDoneWithSplashScreen(lua_State *L); +static int l_guiIntroExitScreen(lua_State *L); +static int l_gbIntroScreenMode(lua_State *L); +static int l_iStringToUse(lua_State *L); +static int l_StopVideo(lua_State *L); +static int l_StartVideo(lua_State *L); + +UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ ); + +BOOLEAN LoadLuaGlobalFromLoadGameFile( HWFILE hFile ); +BOOLEAN SaveLuaGlobalToSaveGameFile( HWFILE hFile ); + +BOOLEAN LetHandleLoyaltyChangeForNPCAction(UINT8 ubNPCProfileId , UINT8 Init); +BOOLEAN LuaHandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , UINT8 Init); +BOOLEAN LetLuaHandleEarlyMorningEvents(UINT8 Init); +BOOLEAN LetLuaHourlyQuestUpdate(UINT8 Init); +BOOLEAN LetLuaMyCustomHandleAtNewGridNo(UINT8 bNewSide, UINT8 ProfileId, UINT8 Init); +BOOLEAN LetLuaPerformItemAction(UINT32 Action, INT32 sGridNo, UINT8 InitFunction); +BOOLEAN LetLuaGameInit(UINT8 Init); +BOOLEAN LetLuaInterfaceDialogue( UINT8 ubNPC, UINT8 InitFunction); +BOOLEAN LuaHandlePlayerTeamMemberDeath(UINT8 ProfileId, UINT8 Init); +BOOLEAN LuaHandleNPCTeamMemberDeath(UINT8 ProfileId, UINT8 Init); +BOOLEAN LuaCheckForKingpinsMoneyMissing( BOOLEAN fFirstCheck, UINT8 Init); +BOOLEAN LuaHandleQuestCodeOnSectorExit( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init); +BOOLEAN LuaHandleQuestCodeOnSectorEntry( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init); +BOOLEAN LuaHandleDelayedItemsArrival( UINT32 uiReason, UINT8 Init); +BOOLEAN LetLuaHandleNPCSystemEvent( UINT32 uiEvent, UINT8 Init); + +BOOLEAN LuaCheckFact ( UINT16 usFact, UINT8 ubProfileID , UINT32 Init); +BOOLEAN LuaHandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum , UINT8 InitFunction); + + +//AI ACTION + +static int l_ACTION_ITEM_OPEN_DOOR (lua_State *L); +static int l_ACTION_ITEM_CLOSE_DOOR (lua_State *L); +//static int l_ACTION_ITEM_BLOW_UP (lua_State *L); +static int l_ACTION_ITEM_SMALL_PIT (lua_State *L); +static int l_ACTION_ITEM_LARGE_PIT (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_DOOR (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_ACTION1 (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_ACTION2 (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_ACTION3 (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_ACTION4 (lua_State *L); +static int l_ACTION_ITEM_ENTER_BROTHEL (lua_State *L); +static int l_ACTION_ITEM_EXIT_BROTHEL (lua_State *L); +static int l_ACTION_ITEM_KINGPIN_ALARM (lua_State *L); +static int l_ACTION_ITEM_SEX (lua_State *L); +static int l_ACTION_ITEM_REVEAL_ROOM (lua_State *L); +static int l_ACTION_ITEM_LOCAL_ALARM (lua_State *L); +static int l_ACTION_ITEM_GLOBAL_ALARM (lua_State *L); +static int l_ACTION_ITEM_KLAXON (lua_State *L); +static int l_ACTION_ITEM_UNLOCK_DOOR (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_LOCK (lua_State *L); +static int l_ACTION_ITEM_UNTRAP_DOOR (lua_State *L); +static int l_ACTION_ITEM_TOGGLE_PRESSURE_ITEMS (lua_State *L); +static int l_ACTION_ITEM_MUSEUM_ALARM (lua_State *L); +static int l_ACTION_ITEM_BLOODCAT_ALARM (lua_State *L); + +static int l_SetGlobalLuaBool (lua_State *L); +static int l_SetGlobalLuaVal (lua_State *L); + +static int l_SetGlobalLuaBoolFalse (lua_State *L); +static int l_SetGlobalLuaBoolTrue (lua_State *L); + +static int l_GetGlobalLuaVal (lua_State *L); + +static int l_CheckGlobalLuaBool (lua_State *L); +static int l_CheckGlobalLuaVal (lua_State *L); + +static int l_AddNPC(lua_State *L); +static int l_AddAlternateSector(lua_State *L); +static int l_AddAltUnderGroundSector(lua_State *L); + +static int l_IncrementTownLoyalty(lua_State *L); +static int l_IncrementTownLoyaltyEverywhere(lua_State *L); +static int l_DecrementTownLoyalty(lua_State *L); +static int l_SetTownLoyalty(lua_State *L); +static int l_Merc_Is_Dead (lua_State *L); +static int l_SetFactFalse(lua_State *L); +static int l_SetFactTrue(lua_State *L); +static int l_CheckFact (lua_State *L); +static int l_SetMoneyInSoldierProfile(lua_State *L); +static int l_CheckForMissingHospitalSupplies(lua_State *L); +static int l_RemoveObjectFromSoldierProfile(lua_State *L); +static int l_bThreatenDefaultResponseUsedRecently(lua_State *L); +static int l_bRecruitDefaultResponseUsedRecently(lua_State *L); +static int l_bFriendlyOrDirectDefaultResponseUsedRecently(lua_State *L); +static int l_ubMiscFlags2Set(lua_State *L); +static int l_ubMiscFlags2Check(lua_State *L); +static int l_ubMiscFlags1Set(lua_State *L); +static int l_ubMiscFlags1Check(lua_State *L); +static int l_bNPCData(lua_State *L); +static int l_bNPCData2(lua_State *L); +static int l_CheckNPCSector (lua_State *L); +static int l_ubLastDateSpokenTot (lua_State *L); +static int l_fNPCData (lua_State *L); +static int l_bLife (lua_State *L); +static int l_iBalance(lua_State *L); +static int l_fNPCData2 (lua_State *L); +static int l_fuiMoney (lua_State *L); +static int l_SetuiMoney(lua_State *L); +static int l_StartQuest(lua_State *L); +static int l_EndQuest(lua_State *L); +static int l_HospitalTempBalance(lua_State *L); +static int l_HospitalRefund(lua_State *L); +static int l_HospitalPriceModifier(lua_State *L); +static int l_gfPlayerTeamSawJoey(lua_State *L); +static int l_AddNPCTOSECTOR(lua_State *L); +static int l_AddAltUnderGroundSectorNew(lua_State *L); +static int l_AddAlternateSectorNew(lua_State *L); +static int l_TriggerNPCRecord(lua_State *L); +static int l_TriggerNPCRecordImmediately(lua_State *L); +static int l_SetCharacterSectorX (lua_State *L); +static int l_SetCharacterSectorY (lua_State *L); +static int l_SetCharacterSectorZ (lua_State *L); + +static int l_GetCharacterSectorX (lua_State *L); +static int l_GetCharacterSectorY (lua_State *L); +static int l_GetCharacterSectorZ (lua_State *L); + +static int l_SetPendingNewScreenSEXSCREEN (lua_State *L); +static int l_CheckCharacterSectorX (lua_State *L); +static int l_CheckCharacterSectorY (lua_State *L); +static int l_CheckCharacterSectorZ (lua_State *L); +static int l_CheckNPCSectorNew (lua_State *L); +static int l_GetWorldHour (lua_State *L); +static int l_FindItemSoldier (lua_State *L); + +static int l_CheckNPCWoundedbyPlayer (lua_State *L); +static int l_CheckNPCWounded (lua_State *L); +static int l_CheckNPCInOkayHealth (lua_State *L); +static int l_CheckNPCBleeding (lua_State *L); +static int l_CheckNPCWithin (lua_State *L); + +static int l_CheckGuyVisible (lua_State *L); +static int l_CheckNPCAt (lua_State *L); +static int l_CheckNPCIsEnemy (lua_State *L); +//static int l_CheckIfMercIsNearNPC (lua_State *L); +static int l_NumWoundedMercsNearby (lua_State *L); +static int l_NumMercsNear (lua_State *L); +static int l_CheckNPCIsEPC (lua_State *L); +static int l_NPCInRoom (lua_State *L); +static int l_NPCInRoomRange (lua_State *L); +static int l_PCInSameRoom (lua_State *L); +static int l_NumMalesPresent (lua_State *L); +static int l_FemalePresent (lua_State *L); +static int l_CheckPlayerHasHead (lua_State *L); +static int l_CheckNPCSectorBool (lua_State *L); +static int l_AIMMercWithin (lua_State *L); +static int l_CheckNPCCowering (lua_State *L); +static int l_CheckNPCIsUnderFire (lua_State *L); +static int l_NPCHeardShot (lua_State *L); +static int l_InTownSectorWithTrainingLoyalty (lua_State *L); +//static int l_CheckFact (lua_State *L); +static int l_gubQuest (lua_State *L); +static int l_UnRecruitEPC (lua_State *L); +static int l_MakeHostile (lua_State *L); + +static int l_PythSpacesAway (lua_State *L); +static int l_FindSoldierTeam (lua_State *L); +static int l_ubWhatKindOfMercAmI (lua_State *L); + +static int l_SetUpHelicopterForPlayer (lua_State *L); +static int l_GetGridoProfileID (lua_State *L); + +static int lh_getIntegerFromTable(lua_State *L, const char * fieldname); +static std::string lh_getStringFromTable(lua_State *L, const char * fieldname); +static int lh_getBooleanFromTable(lua_State *L, const char * fieldname); +static bool locationStringToCoordinates_AltSector(std::string loc, UINT8* x, UINT8* y); +static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z); + +static int l_FindSoldierByProfileID (lua_State *L);; +static int l_TileIsOutOfBoundsClosestPC (lua_State *L); + +static int l_SetgfBoxerFought (lua_State *L); +static int l_EVENT_StopMerc (lua_State *L); + +static int l_SetEnterCombatMode (lua_State *L); + +static int l_PlayerInARoom (lua_State *L); + +static int l_GetWorldMinutesInDay (lua_State *L); + +static int l_ExecuteStrategicAIAction (lua_State *L); + +static int l_AddToShouldBecomeHostileOrSayQuoteList(lua_State *L); + +static int l_AddPreReadEmail (lua_State *L); +static int l_AddEmail (lua_State *L); + +static int l_EVENT_SoldierGotHit (lua_State *L); +static int l_EVENT_InitNewSoldierAnim (lua_State *L); + +static int l_ChangeNpcToDifferentSector (lua_State *L); + +static int l_CreateItem (lua_State *L); +static int l_CreateMoney (lua_State *L); + +static int l_RecruitRPC (lua_State *L); +static int l_RecruitEPC (lua_State *L); +static int l_CheckNPCIsRPC (lua_State *L); + +static int l_gTacticalStatus(lua_State *L); + +static int l_CheckCombatMode (lua_State *L); + +static int l_EnterShopKeeperInterfaceScreen (lua_State *L); +static int l_SetOffBombsByFrequency (lua_State *L); + +static int l_TeleportSoldier (lua_State *L); + +static int l_Action_door (lua_State *L); + +static int l_Action_door_open (lua_State *L); +static int l_Action_door_close (lua_State *L); + +//maps +static int l_SetRender (lua_State *L); +static int l_ConvertGridNoToXY (lua_State *L); +static int l_AddStructToHead (lua_State *L); +static int l_RemoveStruct (lua_State *L); +static int l_ApplyMapChangesToMapTempFile (lua_State *L); + +static int l_NPCGotoGridNo (lua_State *L); + +static int l_fEnemyControlled (lua_State *L); +static int l_fCivGroupHostile (lua_State *L); +static int l_ItemTypeExistsAtLocation (lua_State *L); + +static int l_SetSoldierSide (lua_State *L); +static int l_CheckSoldierSide (lua_State *L); +static int l_CheckSoldierNeutral (lua_State *L); +static int l_CheckSoldierCivilianGroup (lua_State *L); +static int l_CheckSoldierubProfile (lua_State *L); +static int l_ChangeSoldierTeam (lua_State *L); +static int l_CheckSoldierInSector (lua_State *L); +static int l_CheckSoldierActive (lua_State *L); +static int l_RecalculateOppCntsDueToNoLongerNeutral (lua_State *L); +static int l_CheckForPotentialAddToBattleIncrement (lua_State *L); +static int l_SetSoldierOrders (lua_State *L); + + +static int l_SetCivGroupHostile (lua_State *L); +static int l_GetLastID (lua_State *L); +static int l_GetFirstID (lua_State *L); +static int l_GetDirection (lua_State *L); + +//merc +static int l_CheckMercPtrsInCivilianGroup (lua_State *L); +static int l_CheckMercPtsrInSector (lua_State *L); +static int l_CheckMercPtrsActive (lua_State *L); +static int l_CheckMercPtsrubIDSeenubID2 (lua_State *L); + +static int l_MakeMercPtrsHostile (lua_State *L); + +static int l_SetEnterCombatModeTeam (lua_State *L); + + +static int l_SoldierTo3DLocationLineOfSightTest(lua_State *L); +static int l_CancelAIAction(lua_State *L); +static int l_RESETTIMECOUNTER(lua_State *L); +static int l_SetNextActionData(lua_State *L); +static int l_SetNextAction(lua_State *L); +static int l_CheckAction(lua_State *L); +static int l_SetAlertStatus(lua_State *L); +static int l_SetNoiseVolume(lua_State *L); +static int l_SetNoiseGridno(lua_State *L); +static int l_SetNewSituation(lua_State *L); +static int l_TriggerNPCWithIHateYouQuote(lua_State *L); +static int l_CheckSoldierNoiseVolume(lua_State *L); +static int l_CheckSoldierAlertStatus(lua_State *L); +static int l_TacticalStatusTeamActive(lua_State *L); + +static int l_ToggleActionItemsByFrequency (lua_State *L); + +static int l_PlayJA2Sample (lua_State *L); + +static int l_ActionInProgress(lua_State *L); + +static int l_AnimMercPtsrInSector (lua_State *L); +static int l_SetNewSituationMercPtsr (lua_State *L); + +static int l_gubPublicNoiseVolume(lua_State *L); +static int l_gsPublicNoiseGridNo(lua_State *L); + +static int l_Add3X3Pit (lua_State *L); +static int l_Add5X5Pit (lua_State *L); +static int l_SearchForOtherMembersWithinPitRadiusAndMakeThemFall (lua_State *L); +static int l_TogglePressureActionItemsInGridNo(lua_State *L); + +static int l_TacticalStatusTeamHuman (lua_State *L); +static int l_WearGasMaskIfAvailable (lua_State *L); +static int l_MakeNoise(lua_State *L); + +static int l_WorldLevelDataTerrainID(lua_State *L); + +static int l_SetOffPanicBombs (lua_State *L); + +static int l_ubID (lua_State *L); + +static int l_SetProfileFaceData (lua_State *L); +static int l_GetProfileFaceData (lua_State *L); + +static int l_ClosestPC (lua_State *L); +static int l_TileIsOutOfBounds (lua_State *L); +static int l_AnimMercPtsrSoldierGotHit (lua_State *L); + +static int l_HandleNPCGotoGridNo(lua_State *L); +static int l_HandleNPCDoAction(lua_State *L); +static int l_HandleNPCClosePanel(lua_State *L); +static int l_HandleNPCTriggerNPC(lua_State *L); +static int l_IS_CIV_BODY_TYPE (lua_State *L); +static int l_SetOffBombsInGridNo (lua_State *L); +static int l_ActivateSwitchInGridNo(lua_State *L); + +static int l_UpdateAndDamageSAMIfFound(lua_State *L); +static int l_DoesSAMExistHere(lua_State *L); +static int l_UpdateSAMDoneRepair(lua_State *L); +static int l_ActiveTimedBombExists(lua_State *L); +static int l_RemoveAllActiveTimedBombs(lua_State *L); + +static int l_CheckSoldierBodyType (lua_State *L); +static int l_GetSoldierBodyType (lua_State *L); +static int l_SetSoldierBodyType (lua_State *L); + +static int l_ChangeMercPtrsTeam (lua_State *L); + +static int l_AnimMercPtsrfAIFlags (lua_State *L); +static int l_AnimMercPtsrbNextAction (lua_State *L); +static int l_AnimMercPtsrusNextActionData (lua_State *L); +static int l_AnimMercPtsrsAbsoluteFinalDestination (lua_State *L); +static int l_AnimMercPtsrubStrategicInsertionCode (lua_State *L); +static int l_AnimMercPtsrusStrategicInsertionData (lua_State *L); + +static int l_SetMusicMode (lua_State *L); +static int l_MusicPlay (lua_State *L); +static int l_MusicSetVolume (lua_State *L); +static int l_MusicGetVolume (lua_State *L); +//static int l_MusicStop (lua_State *L); +//static int l_MusicFadeOut (lua_State *L); +//static int l_MusicFadeIn (lua_State *L); +static int l_SetSoundEffectsVolume (lua_State *L); +static int l_SetSpeechVolume (lua_State *L); +static int l_GetSoundEffectsVolume (lua_State *L); +static int l_GetSpeechVolume (lua_State *L); + +static int l_SetMercProfiles(lua_State *L); + +static int l_PauseGame (lua_State *L); + +static int l_SetInvestigateSector (lua_State *L); +static int l_CheckInvestigateSector (lua_State *L); + +static int l_AddTransactionToPlayersBook (lua_State *L); +static int l_GetWorldTotalMin (lua_State *L); + +static int l_GetStartingCashNovice (lua_State *L); +static int l_GetStartingCashExperienced (lua_State *L); +static int l_GetStartingCashExpert (lua_State *L); +static int l_GetStartingCashInsane (lua_State *L); + +static int l_DeleteTalkingMenu (lua_State *L); + +static int l_PlayerMercsInSector (lua_State *L); +static int l_GetPlayerMercsInSector (lua_State *L); +static int l_PlayerGroupsInSector (lua_State *L); +static int l_GetPlayerGroupsInSector(lua_State *L); + +static int l_SetSoldierNonNeutral(lua_State *L); + +static int l_bNeutral(lua_State *L); + +static int l_AffectAllTownsLoyaltyByDistanceFrom (lua_State *L); + +static int l_InitCreatureQuest (lua_State *L); + +static int l_bAttitude(lua_State *L); + +static int l_DecrementTownLoyaltyEverywhere(lua_State *L); + +static int l_GetSoldierTeam (lua_State *L); + +static int l_WhichBuddy (lua_State *L); + +//Object +static int l_SetgWorldItemsExists(lua_State *L); +static int l_gWorldItemsExists(lua_State *L); +static int l_gWorldItemsObjectItem(lua_State *L); +static int l_gWorldItemsObjectDataMoney(lua_State *L); + +static int l_AddHistoryToPlayersLog(lua_State *L); +static int l_AddFutureDayStrategicEvent(lua_State *L); + +static int l_GetiBalance(lua_State *L); + +static int l_CreateItemToPool (lua_State *L); +static int l_CreateToUnLoadedSector (lua_State *L); + +static int l_AddSameDayStrategicEvent(lua_State *L); + +static int l_FunctionCheckForKingpinsMoneyMissing(lua_State *L); + +static int l_MoveItemPools(lua_State *L); +static int l_GetNumberOfWorldItemsFromTempItemFile(lua_State *L); + +static int l_gubFact(lua_State *L); + +static int l_GetgubFact(lua_State *L); + +static int l_GetTacticalStatusEnemyInSector (lua_State *L); + +static int l_CountNumberOfBobbyPurchasesThatAreInTransit(lua_State *L); + +static int l_CheckForNewShipment(lua_State *L); + +static int l_CheckTalkerStrong(lua_State *L); + +static int l_CheckTalkerFemale(lua_State *L); + + +static int l_IssueHeadMinerQuote(lua_State *L); +static int l_GetHeadMinersMineIndex(lua_State *L); +static int l_PlayerSpokeToHeadMiner(lua_State *L); +static int l_IsHisMineRunningOut(lua_State *L); +static int l_IsHisMineEmpty(lua_State *L); +static int l_IsHisMineDisloyal(lua_State *L); +static int l_IsHisMineInfested(lua_State *L); +static int l_IsHisMineLostAndRegained(lua_State *L); +static int l_IsHisMineAtMaxProduction(lua_State *L); +static int l_ResetQueenRetookMine(lua_State *L); + +static int l_GetiFirstArrivalDelay (lua_State *L); +static int l_GetubDefaultArrivalSectorX (lua_State *L); +static int l_GetubDefaultArrivalSectorY (lua_State *L); + +static int l_SetiFirstArrivalDelay (lua_State *L); +static int l_SetubDefaultArrivalSectorX (lua_State *L); +static int l_SetubDefaultArrivalSectorY (lua_State *L); + +static int l_SectorEnemy(lua_State *L); + +static int l_ResetHistoryFact(lua_State *L); +static int l_SetHistoryFact(lua_State *L); + +static int l_TacticalCharacterDialogue(lua_State *L); + +static int l_DeleteMercInventory(lua_State *L); + +static int l_IsMercDead(lua_State *L); +static int l_IsMercHireable(lua_State *L); +static int l_NumberOfMercsOnPlayerTeam(lua_State *L); +static int l_GetMercArrivalTimeOfDay(lua_State *L); +static int l_StrategicPythSpacesAway(lua_State *L); + +static int l_ItemExistsAtLocation(lua_State *L); + +static int l_Merc_Status (lua_State *L); + +static int l_Get_Merc_Status (lua_State *L); + +static int l_SetbLife (lua_State *L); +static int l_GetbLifeMax (lua_State *L); + +static int l_HasHisMineBeenProducingForPlayerForSomeTime (lua_State *L); + +static int l_AnotherFightPossible (lua_State *L); + +static int l_PredictDailyIncomeFromAMine(lua_State *L); + +static int l_SetGroupSectorValue(lua_State *L); +static int l_SetGroupNextSectorValue(lua_State *L); + +static int l_FadeOutGameScreen(lua_State *L); + +static int l_FadeInGameScreen(lua_State *L); + +static int l_SetCurrentWorldSector(lua_State *L); +static int l_EnterSector(lua_State *L); + +static int l_GetTownIdForSector(lua_State *L); +static int l_UpdateMercsInSector(lua_State *L); +static int l_CheckIfEntireTownHasBeenLiberated(lua_State *L); +static int l_CheckIfEntireTownHasBeenLost(lua_State *L); +static int l_DidFirstBattleTakePlaceInThisTown(lua_State *L); +static int l_SetTheFirstBattleSector(lua_State *L); +static int l_AdjustLoyaltyForCivsEatenByMonsters(lua_State *L); +static int l_IsTownUnderCompleteControlByPlayer(lua_State *L); +static int l_GetNumberOfWholeTownsUnderControl(lua_State *L); + +static int l_GetusTotalDaysServed(lua_State *L); +static int l_SetusTotalDaysServed(lua_State *L); + +static int l_GetTownLoyaltyfLiberatedAlready(lua_State *L); +static int l_GetTownLoyaltyfStarted(lua_State *L); +static int l_GetTownLoyaltyubRating(lua_State *L); +static int l_GetTownLoyaltysChange(lua_State *L); + +static int l_SetTownLoyaltyfLiberatedAlready(lua_State *L); +static int l_SetTownLoyaltyfStarted(lua_State *L); +static int l_SetTownLoyaltyubRating(lua_State *L); +static int l_SetTownLoyaltysChange(lua_State *L); + +static int l_GetgfTownUsesLoyalty(lua_State *L); +static int l_SetgfTownUsesLoyalty(lua_State *L); + +static int l_GetgMercProfilesbTown(lua_State *L); +static int l_SetgMercProfilesbTown(lua_State *L); + +static int l_GetTimeQuestWasStarted (lua_State *L); + +static int l_RepairmanIsFixingItemsButNoneAreDoneYet(lua_State *L); + +static int l_SECTOR(lua_State *L); +static int l_SectorInfoBloodCats(lua_State *L); + +static int l_SpokenToHeadMiner(lua_State *L); +static int l_GetIdOfMineForSector(lua_State *L); +static int l_CALCULATE_STRATEGIC_INDEX(lua_State *L); + +static int l_CheckTalkerUnpropositionedFemale(lua_State *L); +static int l_BoxerExists(lua_State *L); + +static int l_CurrentPlayerProgressPercentage(lua_State *L); + +static int l_UnderGroundSectorVisited(lua_State *L); + +static int l_fTurnTimeLimit(lua_State *L); + +static int l_InitFace(lua_State *L); + +static int l_WhoIs(lua_State *L); + +static int l_SetHandleGlobalLoyaltyEvent (lua_State *L); + + +using namespace std; + +UINT16 idProfil; +UINT32 uiHourLua; +UINT32 uiDayLua; +UINT32 uiMinLua; + +UINT16 PROFILLUA_sSectorX; +UINT16 PROFILLUA_sSectorY; +UINT8 PROFILLUA_bSectorZ; +UINT8 PROFILLUA_Level; +UINT8 PROFILLUA_ubID; +UINT32 PROFILLUA_sGridNo; +UINT8 PROFILLUA_ubDirectiono; +UINT8 PROFILLUA_bTeam; + +UINT8 PROFILLUA2_ubProfile; +UINT16 PROFILLUA2_sSectorX; +UINT16 PROFILLUA2_sSectorY; +UINT8 PROFILLUA2_bSectorZ; +UINT32 PROFILLUA2_sGridNo; +UINT8 PROFILLUA2_ubID; + +LUA_GLOBAL gLuaGlobal[1000]; + +ACTION_ITEM_VALUES ActionItemsValues[500]; + +void IniLuaGlobal() +{ +UINT32 i; + + for (i= 0; i<=1000; i++ ) + { + gLuaGlobal[i].fGlobalLuaBool = FALSE; + gLuaGlobal[i].iGlobalLuaVal = 0; + } +} + +void IniGlobal_0(lua_State *L) +{ + + lua_pushinteger(L, PROFILLUA_sSectorX); + lua_setglobal(L, "ProfileIdsSectorX"); + + lua_pushinteger(L, PROFILLUA_sSectorY); + lua_setglobal(L, "ProfileIdsSectorY"); + + lua_pushinteger(L, PROFILLUA_bSectorZ); + lua_setglobal(L, "ProfileIdbSectorZ"); + + lua_pushinteger(L, PROFILLUA_Level); + lua_setglobal(L, "ProfileIdLevel"); + + lua_pushinteger(L, PROFILLUA_ubID); + lua_setglobal(L, "ProfileIdubID"); + + lua_pushinteger(L, PROFILLUA_sGridNo); + lua_setglobal(L, "ProfileIdsGridNo"); + + lua_pushinteger(L, PROFILLUA_ubDirectiono); + lua_setglobal(L, "ProfileIdubDirectiono"); + + lua_pushinteger(L, PROFILLUA_bTeam); + lua_setglobal(L, "ProfileIdbTeam"); + +} + +void IniGlobal_1(lua_State *L) +{ + lua_pushinteger(L, PROFILLUA2_ubProfile); + lua_setglobal(L, "ProfileId"); + + lua_pushinteger(L, PROFILLUA2_sSectorX); + lua_setglobal(L, "ProfileIdsSectorX"); + + lua_pushinteger(L, PROFILLUA2_sSectorY); + lua_setglobal(L, "ProfileIdsSectorY"); + + lua_pushinteger(L, PROFILLUA2_bSectorZ); + lua_setglobal(L, "ProfileIdbSectorZ"); + + lua_pushinteger(L, PROFILLUA2_ubID); + lua_setglobal(L, "ProfileIdubID"); + + lua_pushinteger(L, PROFILLUA2_sGridNo); + lua_setglobal(L, "ProfileIdsGridNo"); + +} +void IniFunction(lua_State *L) +{ + + //Sector + lua_register(L, "AddAlternateSector", l_AddAlternateSector); + lua_register(L, "AddAltUnderGroundSector", l_AddAltUnderGroundSector); + lua_register(L, "AddAltSector", l_AddAlternateSector); + lua_register(L, "AddAltUGSector", l_AddAltUnderGroundSector); + lua_register(L, "AddAltSectorNew", l_AddAlternateSectorNew); + lua_register(L, "AddAltUGSectorNew", l_AddAltUnderGroundSectorNew); + + //Loyalty + lua_register(L, "IncrementTownLoyalty", l_IncrementTownLoyalty); + lua_register(L, "IncrementTownLoyaltyEverywhere", l_IncrementTownLoyaltyEverywhere); + lua_register(L, "DecrementTownLoyalty", l_DecrementTownLoyalty); + lua_register(L, "SetTownLoyalty", l_SetTownLoyalty); + lua_register(L, "InTownSectorWithTrainingLoyalty",l_InTownSectorWithTrainingLoyalty); + + //Merc - Add + + lua_register(L, "SetMercProfiles", l_SetMercProfiles); + lua_register(L, "AddNPC", l_AddNPC); + lua_register(L, "AddNPCtoSector", l_AddNPCTOSECTOR); + lua_register(L, "ChangeNpcToDifferentSector", l_ChangeNpcToDifferentSector); + + //Merc - Check + lua_register(L, "CheckNPCSector", l_CheckNPCSector); + lua_register(L, "CheckLastDateSpokenTot", l_ubLastDateSpokenTot); + lua_register(L, "CheckNPCData1", l_fNPCData); + lua_register(L, "CheckNPCLife", l_bLife); + lua_register(L, "CheckNPCData2", l_fNPCData2); + lua_register(L, "CheckMoney", l_fuiMoney); + lua_register(L, "CheckCharacterSectorX", l_CheckCharacterSectorX); + lua_register(L, "CheckCharacterSectorY", l_CheckCharacterSectorY); + lua_register(L, "CheckNPCinSector", l_CheckNPCSectorNew); + lua_register(L, "CheckMiscFlags2", l_ubMiscFlags2Check); + lua_register(L, "CheckMiscFlags1", l_ubMiscFlags1Check); + lua_register(L, "CheckMercIsDead", l_Merc_Is_Dead); + lua_register(L, "MercIsDead", l_Merc_Is_Dead); + lua_register(L, "CheckNPCWounded",l_CheckNPCWounded); + lua_register(L, "CheckNPCWoundedByPlayer",l_CheckNPCWoundedbyPlayer); + lua_register(L, "CheckNPCInOkayHealth",l_CheckNPCInOkayHealth); + lua_register(L, "CheckNPCBleeding",l_CheckNPCBleeding); + lua_register(L, "CheckNPCWithin",l_CheckNPCWithin); + lua_register(L, "CheckGuyVisible",l_CheckGuyVisible); + lua_register(L, "CheckNPCAt",l_CheckNPCAt); + lua_register(L, "CheckNPCIsEnemy",l_CheckNPCIsEnemy); +// lua_register(L, "CheckIfMercIsNearNPC",l_CheckIfMercIsNearNPC); + lua_register(L, "CheckNPCIsEPC",l_CheckNPCIsEPC); + lua_register(L, "CheckNPCIsRPC",l_CheckNPCIsRPC); + lua_register(L, "NPCInRoom",l_NPCInRoom); + lua_register(L, "NPCInRoomRange",l_NPCInRoomRange); + lua_register(L, "PCInSameRoom",l_PCInSameRoom); + lua_register(L, "InARoom", l_PlayerInARoom); + lua_register(L, "FemalePresent",l_FemalePresent); + lua_register(L, "CheckPlayerHasHead",l_CheckPlayerHasHead); + lua_register(L, "CheckNPCSectorBool",l_CheckNPCSectorBool); + lua_register(L, "AIMMercWithin",l_AIMMercWithin); + lua_register(L, "CheckNPCCowering",l_CheckNPCCowering); + lua_register(L, "CheckNPCIsUnderFire",l_CheckNPCIsUnderFire); + lua_register(L, "NPCHeardShot",l_NPCHeardShot); + lua_register(L, "CheckSoldierSide", l_CheckSoldierSide); + lua_register(L, "CheckSoldierNeutral", l_CheckSoldierNeutral); + lua_register(L, "CheckSoldierCivilianGroup", l_CheckSoldierCivilianGroup); + lua_register(L, "CheckSoldierubProfile", l_CheckSoldierubProfile); + lua_register(L, "ChangeSoldierTeam", l_ChangeSoldierTeam); + lua_register(L, "CheckSoldierInSector", l_CheckSoldierInSector); + lua_register(L, "CheckSoldierActive", l_CheckSoldierActive); + lua_register(L, "CheckForPotentialAddToBattleIncrement", l_CheckForPotentialAddToBattleIncrement); + + lua_register(L, "CheckFPAddBattleIncrement", l_CheckForPotentialAddToBattleIncrement); + + lua_register(L, "CheckAction", l_CheckAction); + lua_register(L, "CheckSoldierNoiseVolume", l_CheckSoldierNoiseVolume); + lua_register(L, "CheckSoldierAlertStatus", l_CheckSoldierAlertStatus); + + //Merc - set + lua_register(L, "SetThreatenDefaultResponseUsedRecently", l_bThreatenDefaultResponseUsedRecently); + lua_register(L, "SetRecruitDefaultResponseUsedRecently", l_bRecruitDefaultResponseUsedRecently); + lua_register(L, "SetFriendlyOrDirectDefaultResponseUsedRecently", l_bFriendlyOrDirectDefaultResponseUsedRecently); + + //nowe + lua_register(L, "SetTDRUsedRecently", l_bThreatenDefaultResponseUsedRecently); + lua_register(L, "SetRDRUsedRecently", l_bRecruitDefaultResponseUsedRecently); + lua_register(L, "SetFDRUsedRecently", l_bFriendlyOrDirectDefaultResponseUsedRecently); + + lua_register(L, "SetMiscFlags2", l_ubMiscFlags2Set); + lua_register(L, "SetMiscFlags1", l_ubMiscFlags1Set); + lua_register(L, "SetNPCData1", l_bNPCData); + lua_register(L, "SetNPCData2", l_bNPCData2); + lua_register(L, "SetNPCBalance", l_iBalance); + lua_register(L, "SetMoney", l_SetuiMoney); + lua_register(L, "SetCharacterSectorZ", l_SetCharacterSectorZ); + lua_register(L, "SetCharacterSectorX", l_SetCharacterSectorX); + lua_register(L, "SetCharacterSectorY", l_SetCharacterSectorY); + lua_register(L, "SetMoneyInSoldierProfile", l_SetMoneyInSoldierProfile); + lua_register(L, "SetAlertStatus", l_SetAlertStatus); + lua_register(L, "SetNoiseVolume", l_SetNoiseVolume); + lua_register(L, "SetNoiseGridno", l_SetNoiseGridno); + lua_register(L, "SetNewSituation", l_SetNewSituation); + lua_register(L, "SetNextActionData", l_SetNextActionData); + lua_register(L, "SetNextAction", l_SetNextAction); + lua_register(L, "SetProfileFaceData", l_SetProfileFaceData ); + lua_register(L, "SetSoldierSide", l_SetSoldierSide); + lua_register(L, "SetSoldierOrders", l_SetSoldierOrders); + + //Merc - Get + lua_register(L, "GetDirection", l_GetDirection); //new + lua_register(L, "GetNPCGridNo", l_GetGridoProfileID); + lua_register(L, "GetProfileFaceData", l_GetProfileFaceData ); + + //Merc - tiggers + lua_register(L, "TriggerNPCRecord", l_TriggerNPCRecord); + lua_register(L, "TriggerNPCRecordImmediately", l_TriggerNPCRecordImmediately); + lua_register(L, "TriggerNPCWithIHateYouQuote", l_TriggerNPCWithIHateYouQuote); + + //Merc - other + lua_register(L, "FindItemSoldier",l_FindItemSoldier); + lua_register(L, "UnRecruitEPC",l_UnRecruitEPC); + lua_register(L, "MakeHostile",l_MakeHostile); + lua_register(L, "PythSpacesAway",l_PythSpacesAway); + lua_register(L, "RemoveObjectFromSoldierProfile", l_RemoveObjectFromSoldierProfile); + lua_register(L, "TeleportSoldier", l_TeleportSoldier); + lua_register(L, "DeadSoldier", l_EVENT_SoldierGotHit); + lua_register(L, "FindSoldierByProfileID", l_FindSoldierByProfileID); + lua_register(L, "TileIsOutOfBoundsClosestPC", l_TileIsOutOfBoundsClosestPC); + lua_register(L, "RecruitRPC", l_RecruitRPC); + lua_register(L, "RecruitEPC", l_RecruitEPC); + lua_register(L, "NPCGotoGridNo", l_NPCGotoGridNo); + lua_register(L, "RecalculateOppCntsDueToNoLongerNeutral", l_RecalculateOppCntsDueToNoLongerNeutral); + lua_register(L, "ActionStopMerc", l_EVENT_StopMerc); + lua_register(L, "AddToShouldBecomeHostileOrSayQuoteList", l_AddToShouldBecomeHostileOrSayQuoteList); + lua_register(L, "EnterGroupCombatMode", l_SetEnterCombatMode); + lua_register(L, "InitNewSoldierAnim", l_EVENT_InitNewSoldierAnim); + lua_register(L, "EnterShopKeeperInterfaceScreen", l_EnterShopKeeperInterfaceScreen); + lua_register(L, "SoldierTo3DLocationLineOfSightTest", l_SoldierTo3DLocationLineOfSightTest); + lua_register(L, "CancelAIAction", l_CancelAIAction); + lua_register(L, "RESETTIMECOUNTER", l_RESETTIMECOUNTER); + lua_register(L, "ClosestPC", l_ClosestPC ); + lua_register(L, "TileIsOutOfBounds", l_TileIsOutOfBounds ); + + //Team + lua_register(L, "FindSoldierTeam",l_FindSoldierTeam); + lua_register(L, "WhatKindOfMercAmI",l_ubWhatKindOfMercAmI); + +// lua_register(L, "ActionInProgress", l_ActionInProgress); + + +// lua_register(L, "MakeCivHostile", l_MakeCivHostile); //new + + //Fact and Quest + lua_register(L, "SetFactTrue", l_SetFactTrue); + lua_register(L, "SetFactFalse", l_SetFactFalse); + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckQuest", l_gubQuest); + lua_register(L, "StartQuest", l_StartQuest); + lua_register(L, "EndQuest", l_EndQuest); + + //Other + //lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "HospitalTempBalance", l_HospitalTempBalance); + lua_register(L, "HospitalRefund", l_HospitalRefund); + lua_register(L, "HospitalPriceModifier", l_HospitalPriceModifier); + lua_register(L, "PlayerTeamSawJoey", l_gfPlayerTeamSawJoey); + lua_register(L, "SetUpHelicopterForPlayer", l_SetUpHelicopterForPlayer); + lua_register(L, "MakeNoise", l_MakeNoise ); + lua_register(L, "WorldLevelDataTerrainID", l_WorldLevelDataTerrainID ); + + //Action - Bomb + lua_register(L, "SetOffBombsByFrequency", l_SetOffBombsByFrequency); + lua_register(L, "SetOffBombs", l_SetOffBombsByFrequency); + lua_register(L, "ToggleActionItemsByFrequency", l_ToggleActionItemsByFrequency); + + //Action - other + lua_register(L, "ActionDoor", l_Action_door); + lua_register(L, "ActionDoorOpen", l_Action_door_open); + lua_register(L, "ActionDoorClose", l_Action_door_close); + lua_register(L, "Add3X3Pit", l_Add3X3Pit ); + lua_register(L, "Add5X5Pit", l_Add5X5Pit ); + lua_register(L, "SearchForOtherMembersWithinPitRadiusAndMakeThemFall", l_SearchForOtherMembersWithinPitRadiusAndMakeThemFall ); + lua_register(L, "TogglePressureActionItemsInGridNo", l_TogglePressureActionItemsInGridNo ); + + //Global + lua_register(L, "SetGlobalBool", l_SetGlobalLuaBool); + lua_register(L, "SetGlobalVal", l_SetGlobalLuaVal); + lua_register(L, "SetGlobalTrue", l_SetGlobalLuaBoolTrue); + lua_register(L, "SetGlobalFalse", l_SetGlobalLuaBoolFalse); + lua_register(L, "CheckGlobalBool", l_CheckGlobalLuaBool); + lua_register(L, "CheckGlobalVal", l_CheckGlobalLuaVal); + lua_register(L, "GetGlobalVal", l_GetGlobalLuaVal); + + //Maps + lua_register(L, "SetRender", l_SetRender); + lua_register(L, "ConvertGridNoToXY", l_ConvertGridNoToXY); + lua_register(L, "AddStructToHead", l_AddStructToHead); + lua_register(L, "RemoveStruct", l_RemoveStruct); + lua_register(L, "ApplyMapChangesToMapTempFile", l_ApplyMapChangesToMapTempFile); + lua_register(L, "SectorEnemyControlled", l_fEnemyControlled); + lua_register(L, "ItemTypeExistsAtLocation", l_ItemTypeExistsAtLocation); + + //Time + lua_register(L, "GetWorldMinutesInDay", l_GetWorldMinutesInDay); + lua_register(L, "GetWorldHour", l_GetWorldHour); + lua_register(L, "ExecuteStrategicAIAction", l_ExecuteStrategicAIAction); + + //Email + lua_register(L, "AddPreReadEmail", l_AddPreReadEmail); + lua_register(L, "AddEmail", l_AddEmail); + + //Items + lua_register(L, "CreateItem", l_CreateItem); + lua_register(L, "CreateMoney", l_CreateMoney); + + //AI ACTION + lua_register(L, "ACTION_ITEM_OPEN_DOOR", l_ACTION_ITEM_OPEN_DOOR); + lua_register(L, "ACTION_ITEM_CLOSE_DOOR", l_ACTION_ITEM_CLOSE_DOOR ); + //lua_register(L, "ACTION_ITEM_BLOW_UP", l_ACTION_ITEM_BLOW_UP ); + lua_register(L, "ACTION_ITEM_SMALL_PIT", l_ACTION_ITEM_SMALL_PIT ); + lua_register(L, "ACTION_ITEM_LARGE_PIT", l_ACTION_ITEM_LARGE_PIT ); + lua_register(L, "ACTION_ITEM_TOGGLE_DOOR", l_ACTION_ITEM_TOGGLE_DOOR ); + lua_register(L, "ACTION_ITEM_TOGGLE_ACTION1", l_ACTION_ITEM_TOGGLE_ACTION1 ); + lua_register(L, "ACTION_ITEM_TOGGLE_ACTION2", l_ACTION_ITEM_TOGGLE_ACTION2 ); + lua_register(L, "ACTION_ITEM_TOGGLE_ACTION3", l_ACTION_ITEM_TOGGLE_ACTION3 ); + lua_register(L, "ACTION_ITEM_TOGGLE_ACTION4", l_ACTION_ITEM_TOGGLE_ACTION4); + lua_register(L, "ACTION_ITEM_ENTER_BROTHEL", l_ACTION_ITEM_ENTER_BROTHEL ); + lua_register(L, "ACTION_ITEM_EXIT_BROTHEL", l_ACTION_ITEM_EXIT_BROTHEL ); + lua_register(L, "ACTION_ITEM_KINGPIN_ALARM", l_ACTION_ITEM_KINGPIN_ALARM ); + lua_register(L, "ACTION_ITEM_SEX", l_ACTION_ITEM_SEX); + lua_register(L, "ACTION_ITEM_REVEAL_ROOM", l_ACTION_ITEM_REVEAL_ROOM); + lua_register(L, "ACTION_ITEM_LOCAL_ALARM", l_ACTION_ITEM_LOCAL_ALARM); + lua_register(L, "ACTION_ITEM_GLOBAL_ALARM", l_ACTION_ITEM_GLOBAL_ALARM); + lua_register(L, "ACTION_ITEM_KLAXON", l_ACTION_ITEM_KLAXON); + lua_register(L, "ACTION_ITEM_UNLOCK_DOOR", l_ACTION_ITEM_UNLOCK_DOOR); + lua_register(L, "ACTION_ITEM_TOGGLE_LOCK", l_ACTION_ITEM_TOGGLE_LOCK); + lua_register(L, "ACTION_ITEM_UNTRAP_DOOR", l_ACTION_ITEM_UNTRAP_DOOR); + lua_register(L, "ACTION_ITEM_TOGGLE_PRESSURE_ITEMS", l_ACTION_ITEM_TOGGLE_PRESSURE_ITEMS); + lua_register(L, "ACTION_ITEM_MUSEUM_ALARM", l_ACTION_ITEM_MUSEUM_ALARM); + lua_register(L, "ACTION_ITEM_BLOODCAT_ALARM", l_ACTION_ITEM_BLOODCAT_ALARM ); + + //Sounds + lua_register(L, "PlayJA2Sample", l_PlayJA2Sample); + + //Tactical + lua_register(L, "CheckCivGroupHostile", l_fCivGroupHostile); + lua_register(L, "gTacticalStatus", l_gTacticalStatus); + lua_register(L, "CheckCombatMode", l_CheckCombatMode); + + lua_register(L, "GetTacticalStatusFirstID", l_GetFirstID); //new + lua_register(L, "GetTacticalStatusLastID", l_GetLastID); //new + lua_register(L, "TacticalStatusTeamHuman", l_TacticalStatusTeamHuman ); + lua_register(L, "TacticalStatusTeamActive", l_TacticalStatusTeamActive); + lua_register(L, "SetPublicNoiseVolume", l_gubPublicNoiseVolume); + lua_register(L, "SetPublicNoiseGridNo", l_gsPublicNoiseGridNo); + + //MercPtrs + lua_register(L, "GetPlayerMercID", l_ubID ); + lua_register(L, "GetMapMercSlotID", l_ubID ); + + lua_register(L, "SetOffPanicBombs", l_SetOffPanicBombs ); + lua_register(L, "WearGasMaskIfAvailable", l_WearGasMaskIfAvailable ); + lua_register(L, "SetNewSituationMercPtrs", l_SetNewSituationMercPtsr); + lua_register(L, "SetCivGroupHostile", l_SetCivGroupHostile); + lua_register(L, "EnterTeamCombatMode", l_SetEnterCombatModeTeam); + lua_register(L, "DeadMercPtrs", l_AnimMercPtsrSoldierGotHit ); + lua_register(L, "AnimMercPtrs", l_AnimMercPtsrInSector); + + lua_register(L, "CheckMercPtrsInCivilianGroup", l_CheckMercPtrsInCivilianGroup); + lua_register(L, "CheckMercPtrsInActive", l_CheckMercPtrsActive); + lua_register(L, "CheckMercPtrsInSector", l_CheckMercPtsrInSector); + lua_register(L, "CheckMercPtrsID1SeenID2", l_CheckMercPtsrubIDSeenubID2); + lua_register(L, "MakeMercPtrsHostile", l_MakeMercPtrsHostile); + + //v0.9 + + lua_register(L, "ChangeMercPtrsTeam", l_ChangeMercPtrsTeam); + + lua_register(L, "HandleNPCGotoGridNo", l_HandleNPCGotoGridNo ); + lua_register(L, "HandleNPCDoAction", l_HandleNPCDoAction ); + lua_register(L, "HandleNPCClosePanel", l_HandleNPCClosePanel ); + lua_register(L, "HandleNPCTriggerNPC", l_HandleNPCTriggerNPC ); + + lua_register(L, "IS_CIV_BODY_TYPE", l_IS_CIV_BODY_TYPE ); + lua_register(L, "SetOffBombsInGridNo", l_SetOffBombsInGridNo ); + lua_register(L, "ActivateSwitchInGridNo", l_ActivateSwitchInGridNo ); + + lua_register(L, "UpdateAndDamageSAMIfFound", l_UpdateAndDamageSAMIfFound ); + lua_register(L, "DoesSAMExistHere", l_DoesSAMExistHere ); + lua_register(L, "UpdateSAMDoneRepair", l_UpdateSAMDoneRepair ); + lua_register(L, "ActiveTimedBombExists", l_ActiveTimedBombExists ); + lua_register(L, "RemoveAllActiveTimedBombs", l_RemoveAllActiveTimedBombs ); + + lua_register(L, "CheckSoldierBodyType", l_CheckSoldierBodyType ); + lua_register(L, "GetSoldierBodyType", l_GetSoldierBodyType ); + lua_register(L, "SetSoldierBodyType", l_SetSoldierBodyType ); + + lua_register(L, "MercPtsrAIFlags", l_AnimMercPtsrfAIFlags ); + lua_register(L, "MercPtsrNextAction", l_AnimMercPtsrbNextAction ); + lua_register(L, "MercPtsrNextActionData", l_AnimMercPtsrusNextActionData ); + lua_register(L, "MercPtsrAbsoluteFinalDestination", l_AnimMercPtsrsAbsoluteFinalDestination ); + lua_register(L, "MercPtsrStrategicInsertionCode", l_AnimMercPtsrubStrategicInsertionCode ); + lua_register(L, "MercPtsrStrategicInsertionData", l_AnimMercPtsrusStrategicInsertionData ); + + lua_register(L, "PauseGame", l_PauseGame ); + + lua_register(L, "SetMusicMode", l_SetMusicMode ); + lua_register(L, "MusicPlay", l_MusicPlay ); + lua_register(L, "MusicSetVolume", l_MusicSetVolume ); + lua_register(L, "MusicGetVolume", l_MusicGetVolume ); + //lua_register(L, "MusicStop", l_MusicStop ); + //lua_register(L, "MusicFadeOut", l_MusicFadeOut ); + //lua_register(L, "MusicFadeIn", l_MusicFadeIn ); + lua_register(L, "SetSoundEffectsVolume", l_SetSoundEffectsVolume ); + lua_register(L, "SetSpeechVolume", l_SetSpeechVolume ); + lua_register(L, "GetSoundEffectsVolume", l_GetSoundEffectsVolume ); + lua_register(L, "GetSpeechVolume", l_GetSpeechVolume ); + + lua_register(L, "AddTransactionToPlayersBook", l_AddTransactionToPlayersBook ); + lua_register(L, "GetWorldTotalMin", l_GetWorldTotalMin ); + + //gGameExternalOptions + lua_register(L, "SetInvestigateSector", l_SetInvestigateSector ); + lua_register(L, "CheckInvestigateSector", l_CheckInvestigateSector ); + + lua_register(L, "GetStartingCashNovice", l_GetStartingCashNovice ); + lua_register(L, "GetStartingCashExperienced", l_GetStartingCashExperienced ); + lua_register(L, "GetStartingCashExpert", l_GetStartingCashExpert ); + lua_register(L, "GetStartingCashInsane", l_GetStartingCashInsane ); + + lua_register(L, "DeleteTalkingMenu", l_DeleteTalkingMenu ); + + lua_register(L, "PlayerMercsInSector", l_PlayerMercsInSector); + lua_register(L, "GetPlayerMercsInSector", l_GetPlayerMercsInSector); + lua_register(L, "PlayerGroupsInSector", l_PlayerGroupsInSector); + lua_register(L, "GetPlayerGroupsInSector", l_GetPlayerGroupsInSector); + + lua_register(L, "SetSoldierNonNeutral", l_SetSoldierNonNeutral); + + lua_register(L, "CheckSoldierNeutral", l_bNeutral); + lua_register(L, "CheckSoldierAttitude", l_bAttitude); + + lua_register(L, "AffectAllTownsLoyaltyByDistanceFrom", l_AffectAllTownsLoyaltyByDistanceFrom); + + lua_register(L, "InitCreatureQuest", l_InitCreatureQuest); + + lua_register(L, "DecrementTownLoyaltyEverywhere", l_DecrementTownLoyaltyEverywhere); + + lua_register(L, "GetSoldierTeam", l_GetSoldierTeam); + + lua_register(L, "WhichBuddy", l_WhichBuddy); + + + //Object + lua_register(L, "SetWorldItemsExists", l_SetgWorldItemsExists); + lua_register(L, "GetWorldItemsExists", l_gWorldItemsExists); + lua_register(L, "GetWorldItemsObjectItem", l_gWorldItemsObjectItem); + lua_register(L, "GetWorldItemsObjectDataMoney", l_gWorldItemsObjectDataMoney); + + lua_register(L, "AddHistoryToPlayersLog", l_AddHistoryToPlayersLog); + lua_register(L, "AddFutureDayStrategicEvent", l_AddFutureDayStrategicEvent); + + lua_register(L, "GetNPCBalance", l_GetiBalance); + + lua_register(L, "AddCreateItemToPool", l_CreateItemToPool); + lua_register(L, "AddCreateItemsToUnLoadedSector", l_CreateToUnLoadedSector); + + lua_register(L, "GetCharacterSectorZ", l_GetCharacterSectorZ); + lua_register(L, "GetCharacterSectorX", l_GetCharacterSectorX); + lua_register(L, "GetCharacterSectorY", l_GetCharacterSectorY); + + lua_register(L, "AddSameDayStrategicEvent", l_AddSameDayStrategicEvent); + + //lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + + lua_register(L, "MoveItemPools", l_MoveItemPools); + + + lua_register(L, "GetNumberOfWorldItemsFromTempItemFile", l_GetNumberOfWorldItemsFromTempItemFile); + + lua_register(L, "gubFact", l_gubFact); + + lua_register(L, "GetgubFact", l_GetgubFact); + + lua_register(L, "GetTacticalStatusEnemyInSector", l_GetTacticalStatusEnemyInSector); + + lua_register(L, "CountNumberOfBobbyPurchasesThatAreInTransit", l_CountNumberOfBobbyPurchasesThatAreInTransit); + + lua_register(L, "CheckForNewShipment", l_CheckForNewShipment); + + lua_register(L, "NumMalesPresent",l_NumMalesPresent); + lua_register(L, "NumWoundedMercsNearby",l_NumWoundedMercsNearby); + lua_register(L, "NumMercsNear",l_NumMercsNear); + lua_register(L, "CheckTalkerStrong",l_CheckTalkerStrong); + lua_register(L, "CheckTalkerFemale",l_CheckTalkerFemale); + + lua_register(L, "CheckCharacterSectorZ", l_CheckCharacterSectorZ); + + lua_register(L, "IssueHeadMinerQuote", l_IssueHeadMinerQuote); + lua_register(L, "GetHeadMinersMineIndex", l_GetHeadMinersMineIndex); + lua_register(L, "PlayerSpokeToHeadMiner", l_PlayerSpokeToHeadMiner); + lua_register(L, "IsHisMineRunningOut", l_IsHisMineRunningOut); + lua_register(L, "IsHisMineEmpty", l_IsHisMineEmpty); + lua_register(L, "IsHisMineDisloyal", l_IsHisMineDisloyal); + lua_register(L, "IsHisMineInfested", l_IsHisMineInfested); + lua_register(L, "IsHisMineLostAndRegained", l_IsHisMineLostAndRegained); + lua_register(L, "IsHisMineAtMaxProduction", l_IsHisMineAtMaxProduction); + lua_register(L, "ResetQueenRetookMine", l_ResetQueenRetookMine); + + + lua_register(L, "GetFirstArrivalDelay", l_GetiFirstArrivalDelay); + lua_register(L, "GetDefaultArrivalSectorX", l_GetubDefaultArrivalSectorX); + lua_register(L, "GetDefaultArrivalSectorY", l_GetubDefaultArrivalSectorY); + + lua_register(L, "SetFirstArrivalDelay", l_SetiFirstArrivalDelay); + lua_register(L, "SetDefaultArrivalSectorX", l_SetubDefaultArrivalSectorX); + lua_register(L, "SetDefaultArrivalSectorY", l_SetubDefaultArrivalSectorY); + + lua_register(L, "ResetHistoryFact", l_ResetHistoryFact); + lua_register(L, "SetHistoryFact", l_SetHistoryFact); + + lua_register(L, "TacticalCharacterDialogue", l_TacticalCharacterDialogue); + + lua_register(L, "DeleteMercInventory", l_DeleteMercInventory); + + lua_register(L, "DeleteSlotMercInventory", l_DeleteMercInventory); + + + lua_register(L, "IsMercDead", l_IsMercDead); + lua_register(L, "IsMercHireable", l_IsMercHireable); + lua_register(L, "NumberOfMercsOnPlayerTeam", l_NumberOfMercsOnPlayerTeam); + + lua_register(L, "GetMercArrivalTimeOfDay", l_GetMercArrivalTimeOfDay); + lua_register(L, "StrategicPythSpacesAway", l_StrategicPythSpacesAway); + + //----------------------------------------------- + lua_register(L, "SectorEnemy", l_SectorEnemy); + + lua_register(L, "ItemExistsAtLocation", l_ItemExistsAtLocation); + + lua_register(L, "SetMercStatus", l_Merc_Status); + + lua_register(L, "GetMercStatus", l_Get_Merc_Status); + + lua_register(L, "SetNPCLife", l_SetbLife); + lua_register(L, "GetNPCLifeMax", l_GetbLifeMax); + + lua_register(L, "HasHisMineBeenProducingForPlayerForSomeTime", l_HasHisMineBeenProducingForPlayerForSomeTime); + + lua_register(L, "AnotherFightPossible", l_AnotherFightPossible); + + lua_register(L, "PredictDailyIncomeFromAMine", l_PredictDailyIncomeFromAMine); + + //brak w faq + lua_register(L, "SetGroupSectorValue", l_SetGroupSectorValue); + lua_register(L, "SetGroupNextSectorValue", l_SetGroupNextSectorValue); + + lua_register(L, "FadeOutGameScreen", l_FadeOutGameScreen); + + lua_register(L, "FadeInGameScreen", l_FadeInGameScreen); + + lua_register(L, "SetCurrentWorldSector", l_SetCurrentWorldSector); + + lua_register(L, "EnterSector", l_EnterSector); + + lua_register(L, "gubQuest", l_gubQuest); + + lua_register(L, "GetTownIdForSector", l_GetTownIdForSector); + lua_register(L, "UpdateMercsInSector", l_UpdateMercsInSector); + lua_register(L, "CheckIfEntireTownHasBeenLiberated", l_CheckIfEntireTownHasBeenLiberated); + lua_register(L, "CheckIfEntireTownHasBeenLost", l_CheckIfEntireTownHasBeenLost); + lua_register(L, "DidFirstBattleTakePlaceInThisTown", l_DidFirstBattleTakePlaceInThisTown); + lua_register(L, "SetTheFirstBattleSector", l_SetTheFirstBattleSector); + lua_register(L, "AdjustLoyaltyForCivsEatenByMonsters", l_AdjustLoyaltyForCivsEatenByMonsters); + lua_register(L, "IsTownUnderCompleteControlByPlayer", l_IsTownUnderCompleteControlByPlayer); + lua_register(L, "GetNumberOfWholeTownsUnderControl", l_GetNumberOfWholeTownsUnderControl); + + lua_register(L, "GetCharacterTotalDaysServed", l_GetusTotalDaysServed); + lua_register(L, "SetCharacterTotalDaysServed", l_SetusTotalDaysServed); + + lua_register(L, "GetTownLoyaltyLiberatedAlready", l_GetTownLoyaltyfLiberatedAlready); + lua_register(L, "GetTownLoyaltyStarted", l_GetTownLoyaltyfStarted); + lua_register(L, "GetTownLoyaltyRating", l_GetTownLoyaltyubRating); + lua_register(L, "GetTownLoyaltyChange", l_GetTownLoyaltysChange); + + lua_register(L, "SetTownLoyaltyLiberatedAlready", l_SetTownLoyaltyfLiberatedAlready); + lua_register(L, "SetTownLoyaltyStarted", l_SetTownLoyaltyfStarted); + lua_register(L, "SetTownLoyaltyRating", l_SetTownLoyaltyubRating); + lua_register(L, "SetTownLoyaltyChange", l_SetTownLoyaltysChange); + + lua_register(L, "GetTownUsesLoyalty", l_GetgfTownUsesLoyalty); + lua_register(L, "SetTownUsesLoyalty", l_SetgfTownUsesLoyalty); + + lua_register(L, "GetCharacterTown", l_GetgMercProfilesbTown); + lua_register(L, "SetCharacterTown", l_SetgMercProfilesbTown); + + lua_register(L, "GetTimeQuestWasStarted", l_GetTimeQuestWasStarted); + + lua_register(L, "RepairmanIsFixingItemsButNoneAreDoneYet", l_RepairmanIsFixingItemsButNoneAreDoneYet); + + lua_register(L, "SECTOR", l_SECTOR); + lua_register(L, "GetSectorInfoBloodCats", l_SectorInfoBloodCats); + + lua_register(L, "SpokenToHeadMiner", l_SpokenToHeadMiner); + lua_register(L, "GetIdOfMineForSector", l_GetIdOfMineForSector); + + lua_register(L, "CALCULATE_STRATEGIC_INDEX", l_CALCULATE_STRATEGIC_INDEX); + + lua_register(L, "CheckTalkerUnpropositionedFemale", l_CheckTalkerUnpropositionedFemale); + + lua_register(L, "BoxerExists", l_BoxerExists); + lua_register(L, "CurrentPlayerProgressPercentage", l_CurrentPlayerProgressPercentage); + + lua_register(L, "UnderGroundSectorVisited", l_UnderGroundSectorVisited); + + lua_register(L, "SetTurnTimeLimit", l_fTurnTimeLimit); + + lua_register(L, "InitMercFace", l_InitFace); + + lua_register(L, "WhoIsThere2", l_WhoIsThere2); + + lua_register(L, "WhoIs", l_WhoIs); + + //Shop + lua_register(L, "GuaranteeAtLeastXItemsOfIndex", l_GuaranteeAtLeastXItemsOfIndex); + + lua_register(L, "MercProfileSetBIGPOCK2POS", l_gMercProfileGearset); + lua_register(L, "MercProfileSetPOCKPOS", l_gMercProfileGearset); + + lua_register(L, "FindUnderGroundSector", l_FindUnderGroundSector); + lua_register(L, "AddEnemyToUnderGroundSector", l_AddEnemyToUnderGroundSector); + lua_register(L, "FindUnderGroundSectorVisited", l_FindUnderGroundSectorVisited); + + lua_register(L, "SetCurrentWorldSector", l_SetCurrentWorldSector); + +// lua_register(L, "EnterTacticalInFinalSector", l_EnterTacticalInFinalSector); + + lua_register(L, "ReStartingGame", l_ReStartingGame); + +// lua_register(L, "AddCustomEmail", l_AddCustomEmail); + + //intro + lua_register(L, "DisplaySirtechSplashScreen", l_DisplaySirtechSplashScreen); + + lua_register(L, "SetEnteringMapScreen", l_gfEnteringMapScreen); + lua_register(L, "SetIntroScreenExit", l_gfIntroScreenExit); + lua_register(L, "SetDoneWithSplashScreen", l_gfDoneWithSplashScreen); + lua_register(L, "SetIntroExitScreen", l_guiIntroExitScreen); + lua_register(L, "SetIntroScreenMode", l_gbIntroScreenMode); + + lua_register(L, "SetVideo", l_iStringToUse); + lua_register(L, "StopVideo", l_StopVideo); + lua_register(L, "StartVideo", l_StartVideo); + + lua_register(L, "SetGlobalLoyaltyEvent", l_SetHandleGlobalLoyaltyEvent); + +} + + + +//------------------- intro ----------- + +BOOLEAN LuaIntro(UINT8 Init, UINT32 uiCurrentVideo, INT8 bIntroType, UINT32 iStringToUse ) +{ + const char* filename = "scripts\\Intro.lua"; + + LuaScopeState _LS(true); + + IniFunction( _LS.L() ); + IniGlobalGameSetting( _LS.L() ); + + SGP_THROW_IFFALSE( _LS.L.EvalFile(filename), _BS("Cannot open file: ") << filename << _BS::cget ); + + if ( Init == 0 ) + { + LuaFunction(_LS.L, "PrepareToExitIntroScreen" ).Call(0); + } + + if ( Init == 1 ) + { + LuaFunction(_LS.L, "GetNextIntroVideo" ).Param(uiCurrentVideo).Call(0); + } + + if ( Init == 2 ) + { + LuaFunction(_LS.L, "SetIntroType" ).Param(bIntroType).Call(0); + } + + return true; +} + +static int l_DisplaySirtechSplashScreen(lua_State *L) +{ + + DisplaySirtechSplashScreen (); + + return 0; +} + +static int l_gfIntroScreenExit(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN BOOL; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) BOOL = lua_toboolean(L,i); + } + + gfIntroScreenExit = BOOL; + return 0; +} + +static int l_gfDoneWithSplashScreen(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN BOOL; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) BOOL = lua_toboolean(L,i); + } + + gfDoneWithSplashScreen = BOOL; + return 0; +} + +static int l_guiIntroExitScreen(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 VAL;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) VAL = lua_tointeger(L,i); + } + + guiIntroExitScreen = VAL; + return 0; +} + +static int l_gbIntroScreenMode(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 VAL;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) VAL = lua_tointeger(L,i); + } + + gbIntroScreenMode = VAL; + return 0; +} + +static int l_iStringToUse(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 VAL;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) VAL = lua_tointeger(L,i); + } + + iStringToUseLua = VAL; + return 0; +} + +static int l_gfEnteringMapScreen(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN BOOL; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) BOOL = lua_toboolean(L,i); + } + + gfEnteringMapScreen = BOOL; + return 0; +} + +static int l_StopVideo(lua_State *L) +{ + + Test = 1; + return 0; +} + +static int l_StartVideo(lua_State *L) +{ + + Test = 0; + return 0; +} + +//------------------- End intro ----------- +/* +static int l_EnterTacticalInFinalSector(lua_State *L) +{ + + EnterTacticalInFinalSector (); + + return 0; +} +*/ +static int l_ReStartingGame(lua_State *L) +{ + + ReStartingGame (); + + return 0; +} + + +static int l_SetHandleGlobalLoyaltyEvent (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubEventType; +INT16 sSectorX; +INT16 sSectorY; +INT8 bSectorZ; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubEventType = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + if (i == 4 ) bSectorZ = lua_tointeger(L,i); + } + + HandleGlobalLoyaltyEvent( ubEventType, sSectorX, sSectorY, bSectorZ); + +return 0; +} + + +/* +static int l_AddCustomEmail (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT32 iMessageOffset; +INT32 iMessageLength; +UINT8 ubSender; +INT32 iCurrentIMPPosition; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) iMessageOffset = lua_tointeger(L,i); + if (i == 2 ) iMessageLength = lua_tointeger(L,i); + if (i == 3 ) ubSender = lua_tointeger(L,i); + //if (i == 4 ) iDate = lua_tointeger(L,i); + if (i == 4 ) iCurrentIMPPosition = lua_tointeger(L,i); + } + + AddCustomEmail(iMessageOffset,iMessageLength,ubSender, GetWorldTotalMin(), iCurrentIMPPosition); + +return 0; +} +*/ +static int l_gMercProfileGearset(lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 ID; +UINT16 inv; +UINT8 status; +UINT8 number; +UINT8 drop; +UINT8 slot; +UINT8 i1; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 3 ) i1 = lua_tointeger(L,i); + if (i == 4 ) inv = lua_tointeger(L,i); + if (i == 5 ) number = lua_tointeger(L,i); + if (i == 6 ) status = lua_tointeger(L,i); + if (i == 7 ) drop = lua_tointeger(L,i); + if (i == 8 ) slot = lua_tointeger(L,i); + } + + +gMercProfileGear[ID][i1].inv[slot] = inv; +gMercProfileGear[ID][i1].iNumber[slot] = number; +gMercProfileGear[ID][i1].iStatus[slot] = status; +gMercProfileGear[ID][i1].iDrop[slot] = drop; + + return 0; +} + +static int l_GuaranteeAtLeastXItemsOfIndex(lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 ShopID; +UINT16 ItemsID; +UINT32 VAL; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ShopID = lua_tointeger(L,i); + if (i == 2 ) ItemsID = lua_tointeger(L,i); + if (i == 3 ) VAL = lua_tointeger(L,i); + } + + + GuaranteeAtLeastXItemsOfIndex( ShopID, ItemsID, VAL ); + + return 0; +} + +static int l_FindUnderGroundSectorVisited(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 sSectorX; +UINT8 sSectorY; +UINT8 bLevel; +UNDERGROUND_SECTORINFO *pSector; +BOOLEAN bol; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) bLevel = lua_tointeger(L,i); + } + + pSector = FindUnderGroundSector( sSectorX, sSectorY, bLevel ); + + if ( pSector ) + { + if ( pSector->fVisited ) + { + bol = TRUE; + } + else + { + bol = FALSE; + } + } + + lua_pushboolean(L, bol); + +return 1; +} + +static int l_FindUnderGroundSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 sSectorX; +UINT8 sSectorY; +UINT8 bLevel; +UNDERGROUND_SECTORINFO *pSector; +BOOLEAN bol; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) bLevel = lua_tointeger(L,i); + } + + pSector = FindUnderGroundSector( sSectorX, sSectorY, bLevel ); + if ( pSector ) + { + bol = TRUE; //ScreenMsg( MSG_FONT_RED, MSG_CHAT, L"Failed to add map: %S.", zMapName ); + } + else + { + bol = FALSE; //pSector = NewUndergroundNode( (UINT8)iCol, (UINT8)iRow, bLevel ); + } + + lua_pushboolean(L, bol); + +return 1; +} + +static int l_AddEnemyToUnderGroundSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 sSectorX; +UINT8 sSectorY; +UNDERGROUND_SECTORINFO *pSector; +UINT8 bLevel; +UINT8 ubNumAdmins; +UINT8 ubNumTroops; +UINT8 ubNumElites; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) bLevel = lua_tointeger(L,i); + if (i == 4 ) ubNumAdmins = lua_tointeger(L,i); + if (i == 5 ) ubNumTroops = lua_tointeger(L,i); + if (i == 6 ) ubNumElites = lua_tointeger(L,i); + + } + + pSector = FindUnderGroundSector( sSectorX, sSectorY, bLevel ); + pSector->ubNumAdmins = ubNumAdmins; + pSector->ubNumTroops = ubNumTroops; + pSector->ubNumElites = ubNumElites; + +return 0; +} + +static int l_WhoIs (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i = 0; +INT8 bLevel = 0; +UINT8 Val = 0,Prof = 0, whois = 0; + + for (i= 1; i<=n; i++ ) + { + if ( i == 1 ) whois = lua_tointeger(L,i); + if ( i == 2 ) Val = lua_tointeger(L,i); + } + + if ( whois == 1 ) + Prof = gProfilesAIM[ Val ].ProfilId; + else if ( whois == 2 ) + Prof = gProfilesMERC[ Val ].ProfilId; + else if ( whois == 3 ) + Prof = gProfilesRPC[ Val ].ProfilId; + else if ( whois == 4 ) + Prof = gProfilesNPC[ Val ].ProfilId; + else if ( whois == 5 ) + Prof = gProfilesVehicle[ Val ].ProfilId; + else if ( whois == 6 ) + Prof = gProfilesIMP[ Val ].ProfilId; + else + Prof = 0; + + lua_pushinteger(L, Prof); + + return 1; +} + +static int l_WhoIsThere2 (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 sGridNo; +INT8 bLevel = 0; +UINT8 Val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + if (i == 2 ) bLevel = lua_tointeger(L,i); + } + + Val = WhoIsThere2( sGridNo, bLevel ); + + lua_pushinteger(L, Val); + + return 1; +} + +//set merc +static int l_SetMercProfiles(lua_State *L) +{ +MERCPROFILESTRUCT * pProfile; +UINT8 idNPC = -1; +UINT16 x = -1; +UINT16 y = -1; +UINT8 z = -1; +UINT32 Orders = -1; +UINT16 usEyesX = -1; +UINT16 usEyesY = -1; +UINT16 usMouthX = -1; +UINT16 usMouthY = -1; +UINT32 uiEyeDelay = -1; +UINT32 uiMouthDelay = -1; +UINT32 uiWeeklySalary = -1; +UINT32 uiBiWeeklySalary = -1; +INT16 sSalary = -1; +UINT8 ubBodyType = -1; + + idNPC = lh_getIntegerFromTable(L, "IDProfile"); + + if ( idNPC > -1 ) + { + pProfile = &(gMercProfiles[ idNPC ]); + + x = lh_getIntegerFromTable(L, "SectorX"); + y = lh_getIntegerFromTable(L, "SectorY"); + z = lh_getIntegerFromTable(L, "SectorZ"); + + usEyesX = lh_getIntegerFromTable(L, "EyesX"); + usEyesY = lh_getIntegerFromTable(L, "EyesY"); + usMouthX = lh_getIntegerFromTable(L, "MouthX"); + usMouthY = lh_getIntegerFromTable(L, "MouthY"); + uiEyeDelay = lh_getIntegerFromTable(L, "EyeDelay"); + uiMouthDelay = lh_getIntegerFromTable(L, "MouthDelay"); + + uiWeeklySalary = lh_getIntegerFromTable(L, "WeeklySalary"); + uiBiWeeklySalary = lh_getIntegerFromTable(L, "BiWeeklySalary"); + sSalary = lh_getIntegerFromTable(L, "Salary"); + ubBodyType = lh_getIntegerFromTable(L, "BodyType"); + + + if ((x != -1 )&& (x >= 1 || x <= 16) ) + pProfile->sSectorX = x; + + if((y != -1) && (y >= 1 || y <= 16) ) + pProfile->sSectorY = y; + + if ((z != -1) && (z >= 0 || z <= 3) ) + pProfile->bSectorZ = z; + + if ( usEyesX != -1 ) + pProfile->usEyesX = usEyesX; + + if ( usEyesY != -1 ) + pProfile->usEyesY = usEyesY; + + if ( usMouthX != -1 ) + pProfile->usMouthX = usMouthX; + + if ( usMouthY != -1 ) + pProfile->usMouthY = usMouthY; + + if ( uiEyeDelay != -1 ) + pProfile->uiEyeDelay = uiEyeDelay; + + if ( uiMouthDelay != -1 ) + pProfile->uiMouthDelay = uiMouthDelay; + + if ( uiWeeklySalary != -1 ) + pProfile->uiWeeklySalary = uiWeeklySalary; + + if ( uiBiWeeklySalary != -1 ) + pProfile->uiBiWeeklySalary = uiBiWeeklySalary; + + if ( sSalary != -1 ) + pProfile->sSalary = sSalary; + + if ( ubBodyType != -1 ) + pProfile->ubBodyType = ubBodyType; + } + + + return 0; +} +/* +BOOLEAN LuaCheckFact ( UINT16 usFact, UINT8 ubProfileID , UINT32 Init ) +{ + char * filename = "scripts\\Quests.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "CheckFact"); + lua_pushnumber (L, usFact ); + lua_pushnumber (L, ubProfileID ); + lua_call(L,2,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LuaCheckForKingpinsMoneyMissing( BOOLEAN fFirstCheck, UINT8 Init) +{ + char * filename = "scripts\\strategicmap.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + IniFunction(L); + IniGlobalGameSetting(L); + + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "CheckForKingpinsMoneyMissing"); + lua_pushboolean (L, fFirstCheck ); + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LuaHandleDelayedItemsArrival( UINT32 uiReason, UINT8 Init) +{ + char * filename = "scripts\\strategicmap.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleDelayedItemsArrival"); + lua_pushnumber (L, uiReason ); + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LuaHandleQuestCodeOnSectorEntry( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init) +{ + char * filename = "scripts\\strategicmap.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleQuestCodeOnSectorEntry"); + lua_pushnumber (L, sSectorX ); + lua_pushnumber (L, sSectorY ); + lua_pushnumber (L, bSectorZ ); + lua_call(L,3,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LuaHandleQuestCodeOnSectorExit( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init) +{ + char * filename = "scripts\\strategicmap.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleQuestCodeOnSectorExit"); + lua_pushnumber (L, sSectorX ); + lua_pushnumber (L, sSectorY ); + lua_pushnumber (L, bSectorZ ); + lua_call(L,3,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} +*/ +BOOLEAN LetLuaGameInit(UINT8 Init) +{ + char * filename = "scripts\\GameInit.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + SGP_THROW(msg); + } + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); +// lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "InitNewGame"); + lua_call(L,0,0); + } + + if ( Init == 1 ) + { + lua_getglobal(L , "InitNPCs"); + lua_call(L,0,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} +/* +BOOLEAN LuaHandleNPCTeamMemberDeath(UINT8 ProfileId, UINT8 Init) +{ + char * filename = "scripts\\Overhead.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleNPCTeamMemberDeath"); + lua_pushnumber (L, ProfileId ); + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LuaHandlePlayerTeamMemberDeath(UINT8 ProfileId, UINT8 Init) +{ + char * filename = "scripts\\Overhead.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "HandlePlayerTeamMemberDeath"); + lua_pushnumber (L, ProfileId ); + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} +*/ +BOOLEAN LetLuaMyCustomHandleAtNewGridNo(UINT8 bNewSide, UINT8 ProfileId, UINT8 Init) +{ + char * filename = "scripts\\Overhead.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + SGP_THROW(msg); + } + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function +// lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); +// lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + + IniGlobal_0(L); + lua_getglobal(L , "HandleAtNewGridNo"); + + lua_pushnumber (L, ProfileId ); + + lua_call(L,1,0); + } + + if ( Init == 1 ) + { + IniGlobal_1(L); + lua_getglobal(L , "MakeCivHostile"); + + lua_pushnumber (L, bNewSide ); + + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + + return true; + +} + + +SOLDIERTYPE * FindSoldierByProfileID_( UINT8 ubProfileID ) +{ + UINT8 ubLoop, ubLoopLimit; + SOLDIERTYPE * pSoldier; + + ubLoopLimit = MAX_NUM_SOLDIERS; + + for (ubLoop = 0, pSoldier = MercPtrs[0]; ubLoop < ubLoopLimit; ubLoop++, pSoldier++) + { + if (pSoldier->bActive && pSoldier->ubProfile == ubProfileID) + { + return( pSoldier ); + } + } + return( NULL ); +} + +SOLDIERTYPE * FindSoldierByProfileID2( UINT8 ubProfileID, BOOLEAN fPlayerMercsOnly ) +{ + UINT8 cnt2, ubLoopLimit; + SOLDIERTYPE * pSoldier; + + ubLoopLimit = gTacticalStatus.Team[CIV_TEAM].bLastID; + + cnt2 = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; + for ( pSoldier = MercPtrs[ cnt2 ]; cnt2 <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; cnt2++ ,pSoldier++) + { + if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->ubCivilianGroup == 17 ) + { + return( pSoldier ); + } + } + return( NULL ); +} + +BOOLEAN FindSoldier( SOLDIERTYPE **ppSoldier, UINT16 usSoldierIndex, BOOLEAN fPlayerMercsOnly) +{ + SOLDIERTYPE Menptr[ TOTAL_SOLDIERS ]; + + *ppSoldier = NULL; + + if ( usSoldierIndex < 0 || usSoldierIndex > TOTAL_SOLDIERS-1 ) + { + return( FALSE ); + } + + if ( MercPtrs[ usSoldierIndex ]->bActive ) + { + *ppSoldier = MercPtrs[ usSoldierIndex ]; + return( TRUE); + } + else + { + return( FALSE ); + } +} + +//-------------------------------- +/* +BOOLEAN LuaHandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum , UINT8 InitFunction) +{ + char * filename = "scripts\\InterfaceDialogue.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( InitFunction == 0 ) + { + lua_getglobal(L , "HandleNPCDoAction"); + lua_pushnumber(L, ubTargetNPC); + lua_pushnumber(L, usActionCode); + lua_pushnumber(L, ubQuoteNum); + lua_call(L,3,0); + } + + + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LetLuaInterfaceDialogue( UINT8 ubNPC, UINT8 InitFunction) +{ + char * filename = "scripts\\InterfaceDialogue.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( InitFunction == 0 ) + { + lua_getglobal(L , "CarmenLeavesSectorCallback"); + lua_call(L,0,0); + } + + if ( InitFunction == 0 ) + { + lua_getglobal(L , "HandleStuffForNPCEscorted"); + lua_pushnumber(L, ubNPC); + lua_call(L,1,0); + } + + + + lua_close(L); + + delete[] buffer; + + + return true; + +} + +BOOLEAN LetLuaPerformItemAction(UINT32 ActionID, INT32 sGridNo , UINT8 InitFunction) +{ + char * filename = "scripts\\ExplosionControl.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( InitFunction == 0 ) + { + lua_getglobal(L , "PerformItemAction"); + + lua_pushnumber(L, ActionID); + + lua_pushnumber(L, sGridNo); + + + lua_call(L,2,0); + //lua_pop(L,1); + } + + + lua_close(L); + + delete[] buffer; + + + return true; + +} +*/ +BOOLEAN LetLuaHourlyQuestUpdate(UINT8 Init) +{ + char * filename = "scripts\\HourlyUpdate.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + SGP_THROW(msg); + } + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function +// lua_register(L, "CheckFact", l_CheckFact); +// lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); +// lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + //-----boxer------ only hourly quest update + lua_register(L, "gfBoxerFought", l_SetgfBoxerFought); + lua_register(L, "GetWorldHour", l_GetWorldHour); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "HourlyQuestUpdate"); + lua_call(L,0,0); + } + + lua_close(L); + + delete[] buffer; + + return true; + +} + +//object + +//--------------- + +static int l_BoxerExists(lua_State *L) +{ +BOOLEAN Bool; + + Bool = BoxerExists( ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckTalkerUnpropositionedFemale(lua_State *L) +{ +BOOLEAN Bool; + + Bool = CheckTalkerUnpropositionedFemale( ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_RepairmanIsFixingItemsButNoneAreDoneYet(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubProfileID; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = RepairmanIsFixingItemsButNoneAreDoneYet( ubProfileID ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CurrentPlayerProgressPercentage(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +UINT8 val; + + val = CurrentPlayerProgressPercentage( ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_SetgMercProfilesbTown(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubProfileID; +UINT32 Town; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + if (i == 2 ) Town = lua_tointeger(L,i); + } + + gMercProfiles[ ubProfileID ].bTown = Town; + +return 0; +} + +static int l_GetgMercProfilesbTown(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubProfileID; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + val = gMercProfiles[ ubProfileID ].bTown; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_SetusTotalDaysServed(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 ProfilID; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ProfilID = lua_tointeger(L,i); + if (i == 2 ) val = lua_tointeger(L,i); + + } + + gMercProfiles[ ProfilID ].usTotalDaysServed = val; + +return 0; +} + +static int l_GetusTotalDaysServed(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 ProfilID; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ProfilID = lua_tointeger(L,i); + } + + val = gMercProfiles[ ProfilID ].usTotalDaysServed; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_SetgfTownUsesLoyalty(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +BOOLEAN Bool;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + if (i == 2 ) Bool = lua_tointeger(L,i); + } + + gfTownUsesLoyalty[ bTown ] = Bool; + +return 0; +} + +static int l_GetgfTownUsesLoyalty(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +BOOLEAN Bool;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + } + + Bool = gfTownUsesLoyalty[ bTown ]; + + lua_pushboolean(L, Bool); + +return 1; +} + + +static int l_SetTownLoyaltyfLiberatedAlready(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +BOOLEAN Bool;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + if (i == 2 ) Bool = lua_tointeger(L,i); + } + + gTownLoyalty[ bTown ].fLiberatedAlready = Bool; + +return 0; +} + +static int l_GetTownLoyaltyfLiberatedAlready(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +BOOLEAN Bool;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + } + + Bool = gTownLoyalty[ bTown ].fLiberatedAlready; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_SetTownLoyaltyfStarted(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +BOOLEAN Bool;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + if (i == 2 ) Bool = lua_toboolean(L,i); + } + + gTownLoyalty[ bTown ].fStarted = Bool; + +return 0; +} + +static int l_GetTownLoyaltyfStarted(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +BOOLEAN Bool;; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + } + + Bool = gTownLoyalty[ bTown ].fStarted; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_SetTownLoyaltysChange(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +INT16 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + if (i == 2 ) val = lua_tointeger(L,i); + } + + gTownLoyalty[ bTown ].sChange = val; + +return 0; +} + +static int l_GetTownLoyaltysChange(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +INT16 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + } + + val = gTownLoyalty[ bTown ].sChange; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_SetTownLoyaltyubRating(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +UINT8 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + if (i == 2 ) val = lua_tointeger(L,i); + } + + gTownLoyalty[ bTown ].ubRating = val; + +return 0; +} + +static int l_GetTownLoyaltyubRating(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 bTown; +UINT8 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTown = lua_tointeger(L,i); + } + + val = gTownLoyalty[ bTown ].ubRating; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetTownIdForSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sMapX; +INT16 sMapY; +UINT8 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sMapX = lua_tointeger(L,i); + if (i == 2 ) sMapY = lua_tointeger(L,i); + } + + val = GetTownIdForSector( sMapX, sMapY ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_UpdateMercsInSector(lua_State *L) +{ + UINT8 n = lua_gettop(L); + +INT16 sSectorX; +INT16 sSectorY; +INT8 bSectorZ; +int i; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) bSectorZ = lua_tointeger(L,i); + } + + UpdateMercsInSector( sSectorX, sSectorY, bSectorZ ); + +return 0; +} + +static int l_CheckIfEntireTownHasBeenLiberated(lua_State *L) +{ + UINT8 n = lua_gettop(L); +INT8 bTownId; +INT16 sSectorX; +INT16 sSectorY; +int i; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTownId = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + } + + CheckIfEntireTownHasBeenLiberated( bTownId, sSectorX, sSectorY ); + +return 0; +} + +static int l_CheckIfEntireTownHasBeenLost(lua_State *L) +{ + UINT8 n = lua_gettop(L); +INT8 bTownId; +INT16 sSectorX; +INT16 sSectorY; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTownId = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + } + + CheckIfEntireTownHasBeenLost( bTownId, sSectorX, sSectorY ); + +return 0; +} + +static int l_DidFirstBattleTakePlaceInThisTown(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 bTownId; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTownId = lua_tointeger(L,i); + } + + Bool = DidFirstBattleTakePlaceInThisTown( bTownId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_SetTheFirstBattleSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorValue; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorValue = lua_tointeger(L,i); + } + + SetTheFirstBattleSector( sSectorValue ); + +return 0; +} + +// used when monsters attack a town sector without going through tactical and they win +static int l_AdjustLoyaltyForCivsEatenByMonsters(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; +UINT8 ubHowMany; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) ubHowMany = lua_tointeger(L,i); + } + + AdjustLoyaltyForCivsEatenByMonsters( sSectorX, sSectorY, ubHowMany); + +return 0; +} + +static int l_IsTownUnderCompleteControlByPlayer(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT32 val; +INT32 bTownId; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bTownId = lua_tointeger(L,i); + } + + + val = IsTownUnderCompleteControlByPlayer(bTownId); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetNumberOfWholeTownsUnderControl(lua_State *L) +{ +INT32 val; + + val = GetNumberOfWholeTownsUnderControl(); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_SetCurrentWorldSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sMapX; +INT16 sMapY; +INT8 bMapZ; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sMapX = lua_tointeger(L,i); + if (i == 2 ) sMapY = lua_tointeger(L,i); + if (i == 3 ) bMapZ = lua_tointeger(L,i); + } + + Bool = SetCurrentWorldSector( sMapX, sMapY, bMapZ ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_EnterSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; +INT8 bSectorZ; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) bSectorZ = lua_tointeger(L,i); + } + + Bool = EnterSector( sSectorX, sSectorY, bSectorZ ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_FadeInGameScreen(lua_State *L) +{ + FadeInGameScreen( ); + + return 0; +} + +static int l_FadeOutGameScreen(lua_State *L) +{ + FadeOutGameScreen( ); + + return 0; +} + +static int l_SetGroupNextSectorValue(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; + +UINT8 ubGroupID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) ubGroupID = lua_tointeger(L,i); + } + + SetGroupNextSectorValue( sSectorX, sSectorY, ubGroupID ); + + return 0; +} + +static int l_SetGroupSectorValue(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; +INT16 sSectorZ; +UINT8 ubGroupID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) sSectorZ = lua_tointeger(L,i); + if (i == 4 ) ubGroupID = lua_tointeger(L,i); + } + + SetGroupSectorValue( sSectorX, sSectorY, sSectorZ, ubGroupID ); + + return 0; +} + + +static int l_DeleteMercInventory(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ID; +UINT32 inv; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) inv = lua_tointeger(L,i); + } + + //pProfile = &(gMercProfiles[ID]); + + gMercProfiles[ ID ].inv[ inv ] = 0; + gMercProfiles[ ID ].bInvStatus[ inv ] = 0; + gMercProfiles[ ID ].bInvNumber[ inv ] = 0; + + return 0; +} + +static int l_StrategicPythSpacesAway(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val; +INT16 sOrigin; +INT16 sDest; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sOrigin = lua_tointeger(L,i); + if (i == 2 ) sDest = lua_tointeger(L,i); + } + + val = StrategicPythSpacesAway( sOrigin, sDest); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetMercArrivalTimeOfDay(lua_State *L) +{ +//UINT8 n = lua_gettop(L); + +UINT32 val; + +// for (i= 1; i<=n; i++ ) +// { +// if (i == 1 ) ubMercID = lua_tointeger(L,i); +// } + + val = GetMercArrivalTimeOfDay( ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_NumberOfMercsOnPlayerTeam(lua_State *L) +{ +//UINT8 n = lua_gettop(L); + +UINT8 val; + + +// for (i= 1; i<=n; i++ ) +// { +// if (i == 1 ) ubMercID = lua_tointeger(L,i); +// } + + val = NumberOfMercsOnPlayerTeam( ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_IsMercHireable(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubMercID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMercID = lua_tointeger(L,i); + } + + Bool = IsMercHireable( ubMercID ); + + lua_pushboolean(L, Bool); + +return 1; +} + + + +static int l_IsMercDead(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubMercID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMercID = lua_tointeger(L,i); + } + + Bool = IsMercDead( ubMercID ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_ResetHistoryFact(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubCode; +INT16 sSectorX; +INT16 sSectorY; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCode = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + } + + ResetHistoryFact( ubCode, sSectorX, sSectorY ); + + return 0; +} + +static int l_SetHistoryFact(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubCode; +UINT8 ubSecondCode; +UINT32 uiDate; +INT16 sSectorX; +INT16 sSectorY; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCode = lua_tointeger(L,i); + if (i == 2 ) ubSecondCode = lua_tointeger(L,i); + if (i == 3 ) uiDate = lua_tointeger(L,i); + if (i == 4 ) sSectorX = lua_tointeger(L,i); + if (i == 5 ) sSectorY = lua_tointeger(L,i); + } + + SetHistoryFact( ubCode, ubSecondCode, uiDate, sSectorX, sSectorY ); + + return 0; +} + +static int l_SectorEnemy(lua_State *L) +{ +UINT16 x = -1; +UINT16 y = -1; +UINT16 z = -1; +UINT8 TROOPS_ILOSC = 0; +UINT8 ELITA_ILOSC = 0; +UINT CREATURE_ILOSC = 0; + + if ( ( x >= 1 || x <= 16 ) && ( y >= 1 || y <= 16 ) ) + { + x = lh_getIntegerFromTable(L, "SectorX"); + y = lh_getIntegerFromTable(L, "SectorY"); + + TROOPS_ILOSC = lh_getIntegerFromTable(L, "Troops"); + ELITA_ILOSC = lh_getIntegerFromTable(L, "Elite"); + CREATURE_ILOSC = lh_getIntegerFromTable(L, "Creature"); + + //z = lh_getIntegerFromTable(L, "SectorZ"); + + SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumTroops = TROOPS_ILOSC; + SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumElites = ELITA_ILOSC; + SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumCreatures = CREATURE_ILOSC; + } + + return 0; +} + +static int l_SECTOR(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT16 x,y; +UINT8 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) x = lua_tointeger(L,i); + if (i == 2 ) y = lua_tointeger(L,i); + } + + val = SECTOR( x, y ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_CALCULATE_STRATEGIC_INDEX(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT16 x,y; +UINT8 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) x = lua_tointeger(L,i); + if (i == 2 ) y = lua_tointeger(L,i); + } + + val = CALCULATE_STRATEGIC_INDEX( x, y ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_SectorInfoBloodCats(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 idSector; +UINT8 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) idSector = lua_tointeger(L,i); + } + + val = SectorInfo[ idSector ].bBloodCats; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_IsHisMineAtMaxProduction(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubMinerProfileId; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + Bool = IsHisMineAtMaxProduction(ubMinerProfileId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_IsHisMineLostAndRegained(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubMinerProfileId; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + Bool = IsHisMineLostAndRegained(ubMinerProfileId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_IsHisMineInfested(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubMinerProfileId; +BOOLEAN Bool; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + Bool = IsHisMineInfested(ubMinerProfileId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_IsHisMineDisloyal(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubMinerProfileId; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + Bool = IsHisMineDisloyal(ubMinerProfileId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_IsHisMineEmpty(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubMinerProfileId; +BOOLEAN Bool; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + Bool = IsHisMineEmpty(ubMinerProfileId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_IsHisMineRunningOut(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubMinerProfileId; +BOOLEAN Bool; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + Bool = IsHisMineRunningOut(ubMinerProfileId ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_GetHeadMinersMineIndex(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubMinerProfileId; +UINT8 ID2; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + ID2 = GetHeadMinersMineIndex(ubMinerProfileId); + + lua_pushinteger(L, ID2); + +return 1; +} + + +static int l_PlayerSpokeToHeadMiner(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubMinerProfileId; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + PlayerSpokeToHeadMiner( ubMinerProfileId ); + +return 0; +} + +static int l_ResetQueenRetookMine(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubMinerProfileId; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMinerProfileId = lua_tointeger(L,i); + } + + ResetQueenRetookMine( ubMinerProfileId ); + +return 0; +} + +static int l_IssueHeadMinerQuote(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 bMineIndex; +UINT8 ubQuoteType; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bMineIndex = lua_tointeger(L,i); + if (i == 2 ) ubQuoteType = lua_tointeger(L,i); + } + + IssueHeadMinerQuote( bMineIndex, ubQuoteType ); + +return 0; +} + +static int l_NumMercsNear(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubProfileID; +UINT8 ubMaxDist; +UINT8 ID2; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + if (i == 2 ) ubMaxDist = lua_tointeger(L,i); + } + + ID2 = NumMercsNear( ubProfileID, ubMaxDist ); + + lua_pushinteger(L, ID2); + +return 1; +} + +static int l_PredictDailyIncomeFromAMine(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +INT8 bMineIndex; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bMineIndex = lua_tointeger(L,i); + if (i == 2 ) Bool = lua_toboolean(L,i); + } + + val = PredictDailyIncomeFromAMine( bMineIndex, Bool ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetIdOfMineForSector(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 val; +INT16 sSectorX; +INT16 sSectorY; +INT8 bSectorZ; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) bSectorZ = lua_tointeger(L,i); + } + + val = GetIdOfMineForSector( sSectorX, sSectorY, bSectorZ ); + + lua_pushinteger(L, val); +return 1; +} + +static int l_SpokenToHeadMiner(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubMineIndex; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMineIndex = lua_tointeger(L,i); + } + + Bool = SpokenToHeadMiner( ubMineIndex ); + + lua_pushboolean(L, Bool); +return 1; +} + +static int l_AnotherFightPossible(lua_State *L) +{ +BOOLEAN Bool; + + Bool = AnotherFightPossible( ); + + lua_pushboolean(L, Bool); +return 1; +} + +static int l_fTurnTimeLimit(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Bool = lua_tointeger(L,i); + } + + + gGameOptions.fTurnTimeLimit = Bool; + +return 0; +} + +static int l_HasHisMineBeenProducingForPlayerForSomeTime(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT8 ubProfileID; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = HasHisMineBeenProducingForPlayerForSomeTime( ubProfileID ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckTalkerFemale(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +BOOLEAN Bool; + + Bool = CheckTalkerFemale( ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckTalkerStrong(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +BOOLEAN Bool; + + Bool = CheckTalkerStrong( ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_NumMalesPresent(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 id; +UINT8 ubProfileID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + id = NumMalesPresent( ubProfileID ); + lua_pushinteger(L, id); + +return 1; +} + +static int l_NumWoundedMercsNearby(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +INT8 ID,ID2; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + ID2 = NumWoundedMercsNearby(ID); + + lua_pushinteger(L, ID2); + +return 1; +} + + +static int l_gubFact(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT32 Fact; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Fact = lua_tointeger(L,i); + if (i == 2 ) Bool = lua_toboolean(L,i); + } + gubFact[Fact] = Bool; + +return 0; +} + +static int l_CheckPlayerHasHead(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +BOOLEAN Bool; + + Bool = CheckPlayerHasHead(); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_GetgubFact(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT32 Fact; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Fact = lua_tointeger(L,i); + } + Bool = gubFact[Fact]; + + lua_pushboolean(L, Bool); + +return 1; +} + + +static int l_CheckForNewShipment(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +BOOLEAN Bool; + + Bool = CheckForNewShipment(); + + lua_pushboolean(L, Bool); + +return 1; +} + + +static int l_CountNumberOfBobbyPurchasesThatAreInTransit(lua_State *L) +{ +UINT8 n = lua_gettop(L); + + +UINT16 id; + + id = CountNumberOfBobbyPurchasesThatAreInTransit(); + + lua_pushinteger(L, id); + +return 1; +} + +static int l_FunctionCheckForKingpinsMoneyMissing(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Bool = lua_toboolean(L,i); + } + CheckForKingpinsMoneyMissing( Bool ); + +return 0; +} + + +static int l_GetNumberOfWorldItemsFromTempItemFile(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +INT16 sMapX; +INT16 sMapY; +INT8 bMapZ; +UINT32 puiNumberOfItems; +BOOLEAN fIfEmptyCreate; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sMapX = lua_tointeger(L,i); + if (i == 2 ) sMapY = lua_tointeger(L,i); + if (i == 3 ) bMapZ = lua_tointeger(L,i); + if (i == 4 ) puiNumberOfItems = lua_tointeger(L,i); + if (i == 5 ) fIfEmptyCreate = lua_toboolean(L,i); + } + + Bool = GetNumberOfWorldItemsFromTempItemFile( sMapX, sMapY, bMapZ, &puiNumberOfItems, fIfEmptyCreate ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_MoveItemPools(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT32 sStartPos; +INT32 sEndPos; +INT8 bStartLevel; +INT8 bEndLevel; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sStartPos = lua_tointeger(L,i); + if (i == 2 ) sEndPos = lua_tointeger(L,i); + if (i == 3 ) bStartLevel = lua_tointeger(L,i); + if (i == 4 ) bEndLevel = lua_tointeger(L,i); + } + MoveItemPools( sStartPos, sEndPos, bStartLevel, bEndLevel ); + +return 0; +} + + +static int l_AddFutureDayStrategicEvent(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubCallbackID; +UINT32 uiMinStamp; +UINT32 uiParam; +UINT32 uiNumDaysFromPresent; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCallbackID = lua_tointeger(L,i); + if (i == 2 ) uiMinStamp = lua_tointeger(L,i); + if (i == 3 ) uiParam = lua_tointeger(L,i); + if (i == 4 ) uiNumDaysFromPresent = lua_tointeger(L,i); + } + AddFutureDayStrategicEvent( ubCallbackID, uiMinStamp, uiParam, uiNumDaysFromPresent ); + +return 0; +} + +static int l_AddSameDayStrategicEvent(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubCallbackID; +UINT32 uiMinStamp; +UINT32 uiParam; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCallbackID = lua_tointeger(L,i); + if (i == 2 ) uiMinStamp = lua_tointeger(L,i); + if (i == 3 ) uiParam = lua_tointeger(L,i); + } + AddSameDayStrategicEvent( ubCallbackID, uiMinStamp, uiParam ); + +return 0; +} + +static int l_AddHistoryToPlayersLog(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubCode; +UINT8 ubSecondCode; +UINT32 uiDate; +INT16 sSectorX; +INT16 sSectorY; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCode = lua_tointeger(L,i); + if (i == 2 ) ubSecondCode = lua_tointeger(L,i); + if (i == 3 ) uiDate = lua_tointeger(L,i); + if (i == 4 ) sSectorX = lua_tointeger(L,i); + if (i == 5 ) sSectorY = lua_tointeger(L,i); + } + AddHistoryToPlayersLog( ubCode, ubSecondCode, uiDate, sSectorX, sSectorY ); + +return 0; +} + +static int l_gWorldItemsObjectDataMoney(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT32 uiLoop, MoneyAmount; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiLoop = lua_tointeger(L,i); + } + MoneyAmount = gWorldItems[uiLoop].object[0]->data.money.uiMoneyAmount; + lua_pushinteger(L, MoneyAmount); + +return 1; +} + +static int l_gWorldItemsObjectItem(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT32 uiLoop, Object; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiLoop = lua_tointeger(L,i); + } + Object = gWorldItems[ uiLoop ].object.usItem; + lua_pushinteger(L, Object); + +return 1; +} + +static int l_ItemExistsAtLocation(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +INT32 sGridNo; +INT32 iItemIndex; +UINT8 ubLevel; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + if (i == 2 ) iItemIndex = lua_tointeger(L,i); + if (i == 3 ) ubLevel = lua_tointeger(L,i); + } + Bool = ItemExistsAtLocation( sGridNo, iItemIndex, ubLevel ); + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_gWorldItemsExists(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT32 uiLoop; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiLoop = lua_tointeger(L,i); + } + + Bool = gWorldItems[ uiLoop ].fExists; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_SetgWorldItemsExists(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; +UINT32 uiLoop; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiLoop = lua_tointeger(L,i); + if (i == 2 ) Bool = lua_tointeger(L,i); + } + + gWorldItems[ uiLoop ].fExists = Bool; + + + +return 0; +} + +//----------10-05-2010--------------------------- + +static int l_bAttitude(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; + +SOLDIERTYPE * pSoldier; +UINT32 Attitude; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) Attitude = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + Attitude = pSoldier->aiData.bAttitude; + } + + lua_pushinteger(L, Attitude); + +return 1; +} + +static int l_InitCreatureQuest (lua_State *L) +{ +UINT8 n = lua_gettop(L); + + + InitCreatureQuest(); + +return 0; +} + +static int l_AffectAllTownsLoyaltyByDistanceFrom (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 iLoyaltyChange; +INT16 sSectorX; +INT16 sSectorY; +INT8 bSectorZ; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) iLoyaltyChange = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + if (i == 4 ) bSectorZ = lua_tointeger(L,i); + } + + AffectAllTownsLoyaltyByDistanceFrom( iLoyaltyChange, sSectorX, sSectorY, bSectorZ ); + +return 0; +} + +static int l_PlayerMercsInSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 ubSectorX; +UINT8 ubSectorY; +UINT8 ubSectorZ; +UINT8 val; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubSectorX = lua_tointeger(L,i); + if (i == 2 ) ubSectorY = lua_tointeger(L,i); + if (i == 3 ) ubSectorZ = lua_tointeger(L,i); + } + val = PlayerMercsInSector( ubSectorX, ubSectorY, ubSectorZ ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetPlayerMercsInSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 ubSectorX; +UINT8 ubSectorY; +UINT8 ubSectorZ; +UINT8 val; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubSectorX = lua_tointeger(L,i); + if (i == 2 ) ubSectorY = lua_tointeger(L,i); + if (i == 3 ) ubSectorZ = lua_tointeger(L,i); + } + val = PlayerMercsInSector( ubSectorX, ubSectorY, ubSectorZ ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetPlayerGroupsInSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 bSectorX; +UINT8 bSectorY; +UINT8 bSectorZ; +UINT8 val; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) bSectorX = lua_tointeger(L,i); + if (i == 2 ) bSectorY = lua_tointeger(L,i); + if (i == 3 ) bSectorZ = lua_tointeger(L,i); + } + val = PlayerGroupsInSector( bSectorX, bSectorY, bSectorZ ); + + lua_pushinteger(L, val); + +return 1; +} + +static int l_PlayerGroupsInSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 ubSectorX; +UINT8 ubSectorY; +UINT8 ubSectorZ; + +UINT8 Group; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubSectorX = lua_tointeger(L,i); + if (i == 2 ) ubSectorY = lua_tointeger(L,i); + if (i == 3 ) ubSectorZ = lua_tointeger(L,i); + } + + Group = PlayerGroupsInSector( ubSectorX, ubSectorY, ubSectorZ ); + + lua_pushinteger(L, Group); + +return 1; +} + + +static int l_DeleteTalkingMenu (lua_State *L) +{ +UINT8 n = lua_gettop(L); + + DeleteTalkingMenu( ); + +return 0; +} + +static int l_SetubDefaultArrivalSectorY (lua_State *L) +{ +UINT8 n = lua_gettop(L); + +int i; + +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + gGameExternalOptions.ubDefaultArrivalSectorY = val; + + +return 0; +} + +static int l_SetiFirstArrivalDelay (lua_State *L) +{ +UINT8 n = lua_gettop(L); + +int i; + +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + gGameExternalOptions.iFirstArrivalDelay = val; + +return 0; +} + +static int l_SetubDefaultArrivalSectorX (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + gGameExternalOptions.ubDefaultArrivalSectorX = val; + +return 0; +} + + +//---- +static int l_GetubDefaultArrivalSectorY (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.ubDefaultArrivalSectorY; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetiFirstArrivalDelay (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.iFirstArrivalDelay; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetubDefaultArrivalSectorX (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.ubDefaultArrivalSectorX; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetStartingCashInsane (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.iStartingCashInsane; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetStartingCashExpert (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.iStartingCashExpert; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetStartingCashExperienced (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.iStartingCashExperienced; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetStartingCashNovice (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 val; + + val = gGameExternalOptions.iStartingCashNovice; + + lua_pushinteger(L, val); + +return 1; +} + +static int l_GetWorldTotalMin (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 uiDate; + + uiDate = GetWorldTotalMin(); +return 0; +} + +static int l_AddTransactionToPlayersBook (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubCode; +UINT8 ubSecondCode; +UINT32 uiDate; +INT32 iAmount; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCode = lua_tointeger(L,i); + if (i == 2 ) ubSecondCode = lua_tointeger(L,i); + if (i == 3 ) uiDate = lua_tointeger(L,i); + if (i == 4 ) iAmount = lua_tointeger(L,i); + } + + AddTransactionToPlayersBook(ubCode, ubSecondCode, uiDate, iAmount); +return 0; +} + + +static int l_CheckInvestigateSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +BOOLEAN Bool; + + Bool = gGameExternalOptions.gfInvestigateSector; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_SetInvestigateSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Bool = lua_toboolean(L,i); + } + + gGameExternalOptions.gfInvestigateSector = Bool; + +return 0; +} + +//static int l_MusicFadeIn (lua_State *L) +//{ +//UINT8 n = lua_gettop(L); +// +// MusicFadeIn(); +// +//return 0; +//} + +//static int l_MusicFadeOut (lua_State *L) +//{ +//UINT8 n = lua_gettop(L); +// +// MusicFadeOut(); +// +//return 0; +//} + +//static int l_MusicStop (lua_State *L) +//{ +//UINT8 n = lua_gettop(L); +// +// MusicStop( ); +// +//return 0; +//} + +static int l_MusicGetVolume (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 uiVolume; + + uiVolume = MusicGetVolume( ); + + lua_pushinteger(L, uiVolume); + +return 1; +} + +static int l_GetSpeechVolume (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 uiVolume; + + uiVolume = GetSpeechVolume( ); + + lua_pushinteger(L, uiVolume); + +return 1; +} + +static int l_GetSoundEffectsVolume (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT32 uiVolume; + + uiVolume = GetSoundEffectsVolume( ); + + lua_pushinteger(L, uiVolume); + +return 1; +} + +static int l_SetSoundEffectsVolume (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 uiVolume; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiVolume = lua_tointeger(L,i); + } + + SetSoundEffectsVolume( uiVolume ); + +return 0; +} + +static int l_SetSpeechVolume (lua_State *L) +{ +UINT8 n = lua_gettop(L); + +int i; +UINT32 uiVolume; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiVolume = lua_tointeger(L,i); + } + + SetSpeechVolume( uiVolume ); + +return 0; +} + +static int l_MusicSetVolume (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 uiVolume; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiVolume = lua_tointeger(L,i); + } + + MusicSetVolume( uiVolume ); + +return 0; +} + +static int l_MusicPlay (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 uiNum; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiNum = lua_tointeger(L,i); + } + + MusicPlay( uiNum ); + +return 0; +} + +static int l_SetMusicMode (lua_State *L) +{ +UINT8 n = lua_gettop(L); + +int i; +UINT8 ubMusicMode; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubMusicMode = lua_tointeger(L,i); + } + + SetMusicMode( ubMusicMode ); + +return 0; +} + +static int l_PlayerTeamFull (lua_State *L) +{ +UINT8 n = lua_gettop(L); +BOOLEAN Full; + + + Full = PlayerTeamFull( ); + + lua_pushboolean(L, Full); + +return 1; +} + +static int l_PauseGame (lua_State *L) +{ +UINT8 n = lua_gettop(L); +BOOLEAN Pause; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Pause = lua_toboolean(L,i); + } + + + if (Pause == TRUE) + { + HandlePlayerPauseUnPauseOfGame( ); + } + +return 0; +} + +static int l_SetProfileFaceData (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubCharNum; +UINT8 ubFaceIndex; +UINT16 usEyesX; +UINT16 usEyesY; +UINT16 usMouthX; +UINT16 usMouthY; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCharNum = lua_tointeger(L,i); + if (i == 2 ) ubFaceIndex = lua_tointeger(L,i); + if (i == 3 ) usEyesX = lua_tointeger(L,i); + if (i == 4 ) usEyesY = lua_tointeger(L,i); + if (i == 5 ) usMouthX = lua_tointeger(L,i); + if (i == 6 ) usMouthY = lua_tointeger(L,i); + } + + SetProfileFaceData( ubCharNum, ubFaceIndex, usEyesX, usEyesY, usMouthX, usMouthY ); + +return 0; +} + +static int l_GetProfileFaceData (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubCharNum; +UINT8 ubFaceIndex; +UINT16 usEyesX; +UINT16 usEyesY; +UINT16 usMouthX; +UINT16 usMouthY; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCharNum = lua_tointeger(L,i); + } + + ubFaceIndex = gMercProfiles[ ubCharNum ].ubFaceIndex; + usEyesX = gMercProfiles[ ubCharNum ].usEyesX; + usEyesY = gMercProfiles[ ubCharNum ].usEyesY; + usMouthX = gMercProfiles[ ubCharNum ].usMouthX; + usMouthY = gMercProfiles[ ubCharNum ].usMouthY; + + lua_pushinteger(L, ubFaceIndex); + lua_pushinteger(L, usEyesX); + lua_pushinteger(L, usEyesY); + lua_pushinteger(L, usMouthX); + lua_pushinteger(L, usMouthY); + +return 5; +} + +static int l_SetOffPanicBombs (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubID; +INT8 bPanicTrigger; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) bPanicTrigger = lua_tointeger(L,i); + } + + SetOffPanicBombs( ubID, bPanicTrigger ); + +return 0; +} + +static int l_ToggleActionItemsByFrequency (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT16 ID; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + ToggleActionItemsByFrequency( FIRST_MAP_PLACED_FREQUENCY + ID ); + +return 0; +} + +static int l_PlayJA2Sample (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 sGridNo; +UINT16 sample; +INT8 SoundVolume2; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sample = lua_tointeger(L,i); + if (i == 2 ) SoundVolume2 = lua_tointeger(L,i); + if (i == 3 ) sGridNo = lua_tointeger(L,i); + } + PlayJA2Sample( sample, RATE_11025, SoundVolume( SoundVolume2, sGridNo ), 5, SoundDir( sGridNo ) ); +return 0; +} + +//-----------------07-05-2010-------------------- + +static int l_WorldLevelDataTerrainID(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT32 sGridNo, sGridNo2; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + sGridNo2 = gpWorldLevelData[sGridNo].ubTerrainID; + + lua_pushboolean(L, sGridNo2); + +return 1; +} + +static int l_MakeNoise(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubNoiseMaker; +INT32 sGridNo; +INT8 bLevel; +UINT8 ubTerrType; +UINT8 ubVolume; +UINT8 ubNoiseType; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubNoiseMaker = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + if (i == 3 ) bLevel = lua_tointeger(L,i); + if (i == 4 ) ubTerrType = lua_tointeger(L,i); + if (i == 5 ) ubVolume = lua_tointeger(L,i); + if (i == 6 ) ubNoiseType = lua_tointeger(L,i); + } + + MakeNoise( ubNoiseMaker, sGridNo, bLevel, ubTerrType, ubVolume, ubNoiseType ); + +return 0; +} + +static int l_TacticalStatusTeamHuman(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 team; +BOOLEAN Bool; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) team = lua_tointeger(L,i); + } + + if (gTacticalStatus.Team[team].bHuman ) + Bool = TRUE; + else + Bool = FALSE; + + lua_pushboolean(L, Bool); + +return 1; +} + + +static int l_TacticalStatusTeamActive(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 team; +BOOLEAN Bool; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) team = lua_tointeger(L,i); + } + + if (gTacticalStatus.Team[team].bTeamActive ) + Bool = TRUE; + else + Bool = FALSE; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_bNeutral(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +BOOLEAN Bool; +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + if ( pSoldier->aiData.bNeutral ) + Bool = TRUE; + else + Bool = FALSE; + } + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckSoldierAlertStatus(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 Status_alert, ID; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + Status_alert = pSoldier->aiData.bAlertStatus; + + lua_pushinteger(L, Status_alert); + +return 1; +} + +static int l_InitFace(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT8 IDFace = -1; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) IDFace = lua_tointeger(L,i); + } + + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + DeleteSoldierFace( pSoldier ); + // create new face + if (IDFace > -1 ) + pSoldier->iFaceIndex = IDFace;//InitSoldierFace( pSoldier ); + else + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + + } + +return 0; +} + +static int l_ActionInProgress(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID,cnt,cnt2; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) cnt = lua_tointeger(L,i); + } + + if ( ID > -1 ) + { + pSoldier = FindSoldierByProfileID2( ID, TRUE ); + if (pSoldier) + { + pSoldier->aiData.bActionInProgress = ExecuteAction( pSoldier); + } + } + else + { + + cnt2 = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; + for ( pSoldier = MercPtrs[ cnt2 ]; cnt2 <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; cnt2++ ,pSoldier++) + { + if (pSoldier->bActive ) + { + if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->ubProfile == NO_PROFILE ) + { + pSoldier->aiData.bActionInProgress = ExecuteAction( pSoldier); + } + } + } + + + } + +return 0; +} + +static int l_SetSoldierNonNeutral(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + + if ( ID != NO_PROFILE ) + { + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + SetSoldierNonNeutral (pSoldier); + } + } + else + { + pSoldier = FindSoldierByProfileID_( ID ); + if ( pSoldier->ubProfile == ID ) + { + + if (pSoldier) + { + SetSoldierNonNeutral (pSoldier); + } + } + } + +return 0; +} + +static int l_CheckSoldierNoiseVolume(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 NoiseVolume, ID; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + + NoiseVolume = pSoldier->aiData.ubNoiseVolume; + } + + lua_pushinteger(L, NoiseVolume); + +return 1; +} + + +static int l_TogglePressureActionItemsInGridNo(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + TogglePressureActionItemsInGridNo( sGridNo ); + +return 0; +} + + + +static int l_TriggerNPCWithIHateYouQuote(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + TriggerNPCWithIHateYouQuote(ID); + +return 0; +} + +static int l_SetNewSituation(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +BOOLEAN Bool = FALSE; +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + SetNewSituation(pSoldier); + } + +return 0; +} + +static int l_SetNoiseGridno(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 sGridNo; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + pSoldier->aiData.sNoiseGridno = sGridNo; + } + +return 0; +} + +static int l_SetNoiseVolume(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 NoiseVolume; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) NoiseVolume = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + pSoldier->aiData.ubNoiseVolume = NoiseVolume; + } + +return 0; +} + +static int l_TacticalCharacterDialogue(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 Quote; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) Quote = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + TacticalCharacterDialogue (pSoldier,Quote); + } + +return 0; +} + +static int l_SetAlertStatus(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 AlertStatus; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) AlertStatus = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + pSoldier->aiData.bAlertStatus = AlertStatus; + } + +return 0; +} + +static int l_CheckAction(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 Action; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + Action = pSoldier->aiData.bAction; + } + + lua_pushinteger(L, Action); + +return 1; +} + +static int l_SetNextAction(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 NextAction; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) NextAction = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + pSoldier->aiData.bNextAction = NextAction; + } + +return 0; +} + +static int l_ActiveTimedBombExists(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +BOOLEAN Bool; + + Bool = ActiveTimedBombExists (); + + lua_pushboolean(L, Bool); + +return 1; +} + + +static int l_DoesSAMExistHere(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; +INT16 sSectorZ; +INT32 sGridNo; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) sSectorZ = lua_tointeger(L,i); + if (i == 4 ) sGridNo = lua_tointeger(L,i); + } + + Bool = DoesSAMExistHere( sSectorX, sSectorY, sSectorZ, sGridNo ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_RemoveAllActiveTimedBombs(lua_State *L) +{ +UINT8 n = lua_gettop(L); + +RemoveAllActiveTimedBombs( ); + +return 0; +} + +static int l_UpdateSAMDoneRepair(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; +INT16 sSectorZ; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) sSectorZ = lua_tointeger(L,i); + } + + UpdateSAMDoneRepair( sSectorX, sSectorY, sSectorZ ); + +return 0; +} + +static int l_UpdateAndDamageSAMIfFound(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT16 sSectorX; +INT16 sSectorY; +INT16 sSectorZ; +INT32 sGridNo; +UINT8 ubDamage; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + if (i == 3 ) sSectorZ = lua_tointeger(L,i); + if (i == 4 ) sGridNo = lua_tointeger(L,i); + if (i == 5 ) ubDamage = lua_tointeger(L,i); + } + + UpdateAndDamageSAMIfFound( sSectorX, sSectorY, sSectorZ, sGridNo, ubDamage ); + +return 0; +} + +static int l_ActivateSwitchInGridNo(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubID; +INT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + } + + if ( sGridNo > 0 && ubID > -1 ) + ActivateSwitchInGridNo( ubID, sGridNo ); +return 0; +} + +static int l_HandleNPCTriggerNPC(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubTargetNPC; +UINT8 ubTargetRecord; +BOOLEAN fShowDialogueMenu; +UINT8 ubTargetApproach; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) ubTargetRecord = lua_tointeger(L,i); + if (i == 3 ) fShowDialogueMenu = lua_toboolean(L,i); + if (i == 4 ) ubTargetApproach = lua_tointeger(L,i); + } + + if ( ubTargetNPC > -1 ) + HandleNPCTriggerNPC ( ubTargetNPC, ubTargetRecord, fShowDialogueMenu, ubTargetApproach ); +return 0; +} + +static int l_HandleNPCGotoGridNo(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubTargetNPC; +INT32 usGridNo; +UINT8 ubQuoteNum; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) usGridNo = lua_tointeger(L,i); + if (i == 3 ) ubQuoteNum = lua_tointeger(L,i); + } + + if ( ubTargetNPC > -1 ) + HandleNPCGotoGridNo (ubTargetNPC , usGridNo, ubQuoteNum); +return 0; +} + +static int l_HandleNPCClosePanel(lua_State *L) +{ +UINT8 n = lua_gettop(L); + + HandleNPCClosePanel (); + +return 0; +} + +static int l_HandleNPCDoAction(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT16 usActionCode; +UINT8 ubQuoteNum; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) usActionCode = lua_tointeger(L,i); + if (i == 3 ) ubQuoteNum = lua_tointeger(L,i); + } + + if ( ID > -1 ) + HandleNPCDoAction (ID , usActionCode, ubQuoteNum); + + +return 0; +} + +static int l_SetNextActionData(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 NextActionData; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) NextActionData = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + pSoldier->aiData.usNextActionData = NextActionData; + } + +return 0; +} + +static int l_RESETTIMECOUNTER(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 Counter; + +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) Counter = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + RESETTIMECOUNTER( pSoldier->timeCounters.AICounter, Counter ); + } + +return 0; +} + +static int l_CancelAIAction(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + CancelAIAction( pSoldier, TRUE ); + } + +return 0; +} + +static int l_SoldierTo3DLocationLineOfSightTest(lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ID; +UINT32 sGridNo; +BOOLEAN Bool; +SOLDIERTYPE * pSoldier; +INT8 bLevel; +INT8 bCubeLevel; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + if (i == 3 ) bLevel = lua_tointeger(L,i); + if (i == 4 ) bCubeLevel = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + if ( SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, bLevel, bCubeLevel, TRUE ) ) + Bool = TRUE; + else + Bool = FALSE; + } + + lua_pushboolean(L, Bool); +return 1; +} +//------------ + +static int l_NPCGotoGridNo (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT32 Gridno,sAdjustedGridNo; + +UINT8 ID; +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) Gridno = lua_tointeger(L,i); + } + + if ( ID >= 0 && Gridno >= 1 ) + { + pSoldier = FindSoldierByProfileID( ID, FALSE ); + if (pSoldier) + { + if (NewOKDestination( pSoldier, Gridno, TRUE, 0 ) ) + { + // go for it! + NPCGotoGridNo( ID, Gridno, 1 ); + } + else + { + sAdjustedGridNo = FindAdjacentGridEx( pSoldier, Gridno, NULL, NULL, FALSE, FALSE ); + if (sAdjustedGridNo != -1) + { + NPCGotoGridNo( ID, sAdjustedGridNo, 1 ); + } + } + } + } +return 0; +} + +//------------------- +//Maps function + +static int l_ApplyMapChangesToMapTempFile (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Bool = lua_toboolean(L,i); + } + + // Remove old graphic + ApplyMapChangesToMapTempFile( Bool ); + +return 0; +} + +/* +static int l_gTacticalStatus_Team (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool = FALSE; +INT32 cnt; +SOLDIERTYPE *pSoldier; +UINt8 Team; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Team = lua_tointeger(L,i); + } + + +return 0; +} + +*/ +/* +static int l_AddExitGridToWorld (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +EXITGRID ExitGrid; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Bool = lua_toboolean(L,i); + } + + ExitGrid.ubGotoSectorX = 8; + ExitGrid.ubGotoSectorY = 4; + ExitGrid.ubGotoSectorZ = 1; + + AddExitGridToWorld( 6004, &ExitGrid ); + AddExitGridToWorld( 6005, &ExitGrid ); + + AddExitGridToWorld( 6164, &ExitGrid ); + AddExitGridToWorld( 6165, &ExitGrid ); + +return 0; +} +*/ + +static int l_RemoveStruct (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool = FALSE; +UINT16 usTileIndex; +UINT32 Gridno, uiCheckType; +UINT16 usSubIndex; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiCheckType = lua_tointeger(L,i); + if (i == 2 ) usSubIndex = lua_tointeger(L,i); + if (i == 3 ) Gridno = lua_tointeger(L,i); + } + + GetTileIndexFromTypeSubIndex( uiCheckType, usSubIndex, &usTileIndex ); + RemoveStruct( Gridno, usTileIndex ); + +return 0; +} + +static int l_AddStructToHead (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool = FALSE; +UINT16 usTileIndex; +UINT32 Gridno, uiCheckType; +UINT16 usSubIndex; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) uiCheckType = lua_tointeger(L,i); + if (i == 2 ) usSubIndex = lua_tointeger(L,i); + if (i == 3 ) Gridno = lua_tointeger(L,i); + } + + GetTileIndexFromTypeSubIndex( uiCheckType, usSubIndex, &usTileIndex ); + AddStructToHead( Gridno, usTileIndex ); + +return 0; +} + +static int l_ConvertGridNoToXY (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN Bool = FALSE; +UINT32 Gridno,dis; +INT16 sX, sY; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Gridno = lua_tointeger(L,i); + if (i == 2 ) dis = lua_tointeger(L,i); + } + + // Redo movement costs.... + ConvertGridNoToXY( Gridno, &sX, &sY ); + RecompileLocalMovementCostsFromRadius( Gridno, dis ); + +return 0; +} + +static int l_SetRender (lua_State *L) +{ +UINT8 n = lua_gettop(L); + + + gTacticalStatus.uiFlags |= NOHIDE_REDUNDENCY; + + InvalidateWorldRedundency( ); + SetRenderFlags(RENDER_FLAG_FULL); + +return 0; +} + +//----------------- +static int l_SetUpHelicopterForPlayer (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT16 SextorX; +UINT16 SextorY; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) SextorX = lua_tointeger(L,i); + if (i == 2 ) SextorY = lua_tointeger(L,i); + } + + SetUpHelicopterForPlayer( SextorX, SextorY ); + +return 0; +} + +//-----Ai Action------------ + +//open door +static int l_ACTION_ITEM_OPEN_DOOR (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + + +OBJECTTYPE DoorCloser; + +UINT32 sGridNo; + +STRUCTURE *pStructure; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + pStructure = FindStructure( sGridNo, STRUCTURE_ANYDOOR ); + if (pStructure) + { + if (pStructure->fFlags & STRUCTURE_OPEN) + { + // it's already open - this MIGHT be an error but probably not + // because we are basically just ensuring that the door is open + } + else + { + if (pStructure->fFlags & STRUCTURE_BASE_TILE) + { + HandleDoorChangeFromGridNo( NULL, sGridNo, FALSE ); + } + else + { + HandleDoorChangeFromGridNo( NULL, pStructure->sBaseGridNo, FALSE ); + } + gfExplosionQueueMayHaveChangedSight = TRUE; + } + } + +return 0; +} + +//Close Door +static int l_ACTION_ITEM_CLOSE_DOOR (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + + +OBJECTTYPE DoorCloser; + +UINT32 sGridNo; + +STRUCTURE *pStructure; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + pStructure = FindStructure( sGridNo, STRUCTURE_ANYDOOR ); + if (pStructure) + { + if (pStructure->fFlags & STRUCTURE_OPEN) + { + if (pStructure->fFlags & STRUCTURE_BASE_TILE) + { + HandleDoorChangeFromGridNo( NULL, sGridNo , FALSE ); + } + else + { + HandleDoorChangeFromGridNo( NULL, pStructure->sBaseGridNo, FALSE ); + } + gfExplosionQueueMayHaveChangedSight = TRUE; + } + else + { + // it's already closed - this MIGHT be an error but probably not + // because we are basically just ensuring that the door is closed + } + } + +return 0; +} + + +static int l_ACTION_ITEM_TOGGLE_DOOR (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; +STRUCTURE *pStructure; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + pStructure = FindStructure( sGridNo, STRUCTURE_ANYDOOR ); + if (pStructure) + { + if (pStructure->fFlags & STRUCTURE_BASE_TILE) + { + HandleDoorChangeFromGridNo( NULL, sGridNo, FALSE ); + } + else + { + HandleDoorChangeFromGridNo( NULL, pStructure->sBaseGridNo , FALSE ); + } + gfExplosionQueueMayHaveChangedSight = TRUE; + } + +return 0; +} + +//locked unlocked door +static int l_ACTION_ITEM_UNLOCK_DOOR (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; +DOOR * pDoor; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + pDoor = FindDoorInfoAtGridNo( sGridNo ); + if ( pDoor ) + { + pDoor->fLocked = FALSE; + } + +return 0; +} + +static int l_ACTION_ITEM_TOGGLE_LOCK (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; +DOOR * pDoor; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + pDoor = FindDoorInfoAtGridNo( sGridNo ); + if ( pDoor ) + { + if ( pDoor->fLocked ) + { + pDoor->fLocked = FALSE; + } + else + { + pDoor->fLocked = TRUE; + } + } + +return 0; +} + +static int l_ACTION_ITEM_UNTRAP_DOOR (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; +DOOR * pDoor; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + pDoor = FindDoorInfoAtGridNo( sGridNo ); + if ( pDoor ) + { + pDoor->ubTrapLevel = 0; + pDoor->ubTrapID = NO_TRAP; + } + +return 0; +} + +static int l_ACTION_ITEM_SMALL_PIT (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + Add3X3Pit( sGridNo ); + SearchForOtherMembersWithinPitRadiusAndMakeThemFall( sGridNo, 1 ); + +return 0; +} + +static int l_SearchForOtherMembersWithinPitRadiusAndMakeThemFall (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; +INT16 sRadius; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + if (i == 2 ) sRadius = lua_tointeger(L,i); + } + SearchForOtherMembersWithinPitRadiusAndMakeThemFall( sGridNo, sRadius ); + +return 0; +} + +static int l_Add5X5Pit (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + Add5X5Pit( sGridNo ); + +return 0; +} + +static int l_Add3X3Pit (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + Add3X3Pit( sGridNo ); + +return 0; +} + +static int l_ACTION_ITEM_LARGE_PIT (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + Add5X5Pit( sGridNo ); + SearchForOtherMembersWithinPitRadiusAndMakeThemFall( sGridNo, 2 ); + +return 0; +} + +static int l_ACTION_ITEM_TOGGLE_ACTION1 (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + + ToggleActionItemsByFrequency( FIRST_MAP_PLACED_FREQUENCY + 1 ); + +return 0; +} + +static int l_ACTION_ITEM_TOGGLE_ACTION2 (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + + ToggleActionItemsByFrequency( FIRST_MAP_PLACED_FREQUENCY + 2 ); + +return 0; +} + +static int l_ACTION_ITEM_TOGGLE_ACTION3 (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + + ToggleActionItemsByFrequency( FIRST_MAP_PLACED_FREQUENCY + 3 ); + +return 0; +} + +static int l_ACTION_ITEM_TOGGLE_ACTION4 (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + + ToggleActionItemsByFrequency( FIRST_MAP_PLACED_FREQUENCY + 4 ); + +return 0; +} + +static int l_ACTION_ITEM_TOGGLE_PRESSURE_ITEMS (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + +TogglePressureActionItemsInGridNo( sGridNo ); + +return 0; +} + +static int l_ACTION_ITEM_ENTER_BROTHEL (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + +return 0; +} + +static int l_ACTION_ITEM_EXIT_BROTHEL (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + +return 0; +} + +static int l_ACTION_ITEM_KINGPIN_ALARM (lua_State *L) +{ +UINT8 n = lua_gettop(L); +OBJECTTYPE DoorCloser; + +return 0; +} + +static int l_ACTION_ITEM_SEX (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + if ( ! (gTacticalStatus.uiFlags & INCOMBAT) ) + { + UINT8 ubID; + OBJECTTYPE DoorCloser; + INT16 sTeleportSpot; + INT16 sDoorSpot; + UINT8 ubDirection; + UINT8 ubRoom, ubOldRoom; + + ubID = WhoIsThere2( sGridNo, 0 ); + if ( (ubID != NOBODY) && (MercPtrs[ ubID ]->bTeam == gbPlayerNum) ) + { + if ( InARoom( sGridNo, &ubRoom ) && InARoom( MercPtrs[ ubID ]->sOldGridNo, &ubOldRoom ) && ubOldRoom != ubRoom ) + { + // also require there to be a miniskirt civ in the room + if ( HookerInRoom( ubRoom ) ) + { + + // stop the merc... + MercPtrs[ ubID ]->EVENT_StopMerc( MercPtrs[ ubID ]->sGridNo, MercPtrs[ ubID ]->ubDirection ); + + switch( sGridNo ) + { + case 13414: + sDoorSpot = 13413; + sTeleportSpot = 13413; + break; + case 11174: + sDoorSpot = 11173; + sTeleportSpot = 11173; + break; + case 12290: + sDoorSpot = 12290; + sTeleportSpot = 12291; + break; + + default: + + sDoorSpot = NOWHERE; + sTeleportSpot = NOWHERE; + + + } + + if (!TileIsOutOfBounds(sDoorSpot) && !TileIsOutOfBounds(sTeleportSpot) ) + { + // close the door... + DoorCloser[0]->data.misc.bActionValue = ACTION_ITEM_CLOSE_DOOR; + PerformItemAction( sDoorSpot, &DoorCloser ); + + // have sex + HandleNPCDoAction( 0, NPC_ACTION_SEX, 0 ); + + // move the merc outside of the room again + sTeleportSpot = FindGridNoFromSweetSpotWithStructData( MercPtrs[ ubID ], STANDING, sTeleportSpot, 2, &ubDirection, FALSE ); + MercPtrs[ ubID ]->ChangeSoldierState( STANDING, 0, TRUE ); + TeleportSoldier( MercPtrs[ ubID ], sTeleportSpot, FALSE ); + + HandleMoraleEvent( MercPtrs[ ubID ], MORALE_SEX, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + FatigueCharacter( MercPtrs[ ubID ] ); + FatigueCharacter( MercPtrs[ ubID ] ); + FatigueCharacter( MercPtrs[ ubID ] ); + FatigueCharacter( MercPtrs[ ubID ] ); + DirtyMercPanelInterface( MercPtrs[ ubID ], DIRTYLEVEL1 ); + } + } + + } + + } + } + + +return 0; +} + +static int l_ACTION_ITEM_REVEAL_ROOM (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + UINT8 ubRoom; + if ( InAHiddenRoom( sGridNo, &ubRoom ) ) + { + RemoveRoomRoof( sGridNo, ubRoom, NULL ); + } + +return 0; +} + +static int l_ACTION_ITEM_LOCAL_ALARM (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + +MakeNoise( NOBODY, sGridNo, 0, gpWorldLevelData[sGridNo].ubTerrainID, 30, NOISE_SILENT_ALARM ); + +return 0; +} + + +static int l_ACTION_ITEM_GLOBAL_ALARM (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + +CallAvailableEnemiesTo( sGridNo ); + +return 0; +} + +static int l_ACTION_ITEM_BLOODCAT_ALARM (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + +CallAvailableTeamEnemiesTo( sGridNo, CREATURE_TEAM ); + +return 0; +} + +static int l_ACTION_ITEM_KLAXON (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + +PlayJA2Sample( KLAXON_ALARM, RATE_11025, SoundVolume( MIDVOLUME, sGridNo ), 5, SoundDir( sGridNo ) ); + +return 0; +} + +static int l_ACTION_ITEM_MUSEUM_ALARM (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 sGridNo; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + PlayJA2Sample( KLAXON_ALARM, RATE_11025, SoundVolume( MIDVOLUME, sGridNo ), 5, SoundDir( sGridNo ) ); + CallEldinTo( sGridNo ); + +return 0; +} + +//------------------------------------------------ +static int l_Action_door (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +BOOLEAN Bool; +UINT32 Gridno; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Bool = lua_toboolean(L,i); + if (i == 2 ) Gridno = lua_tointeger(L,i); + + } + + + if (Bool == FALSE) + { + DoorCloser[0]->data.misc.bActionValue = ACTION_ITEM_CLOSE_DOOR; + PerformItemAction ( Gridno, &DoorCloser ); + } + else + { + DoorCloser[0]->data.misc.bActionValue = ACTION_ITEM_OPEN_DOOR; + PerformItemAction ( Gridno, &DoorCloser ); + } + +return 0; +} + +static int l_Action_door_open (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 Gridno; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Gridno = lua_tointeger(L,i); + + } + DoorCloser[0]->data.misc.bActionValue = ACTION_ITEM_OPEN_DOOR; + PerformItemAction ( Gridno, &DoorCloser ); + +return 0; +} + +static int l_Action_door_close (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +OBJECTTYPE DoorCloser; +UINT32 Gridno; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Gridno = lua_tointeger(L,i); + + } + DoorCloser[0]->data.misc.bActionValue = ACTION_ITEM_CLOSE_DOOR; + PerformItemAction ( Gridno, &DoorCloser ); + +return 0; +} +//----------------------------------- + +//action +static int l_SetOffBombsByFrequency (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 ACTION; +UINT8 ID; +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ACTION = lua_tointeger(L,i); + if (i == 2 ) ID = lua_tointeger(L,i); + } + + if (ACTION >= 1 || ACTION <=4) + { + pSoldier = FindSoldierByProfileID( ID, TRUE ); + if (pSoldier) + { + SetOffBombsByFrequency( pSoldier->ubID, FIRST_MAP_PLACED_FREQUENCY + ACTION ); + } + } +return 0; +} + + +//action +static int l_TeleportSoldier (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 Gridno; +UINT8 ID; +SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ID = lua_tointeger(L,i); + if (i == 2 ) Gridno = lua_tointeger(L,i); + } + + if (ID >= 0 && Gridno >=1) + { + pSoldier = FindSoldierByProfileID( ID, TRUE ); + if (pSoldier) + { + TeleportSoldier( pSoldier, Gridno, TRUE ); + } + } +return 0; +} + +//------------------------------------------- + +static int l_SetGlobalLuaBoolFalse (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + + gLuaGlobal[val].fGlobalLuaBool = FALSE; + + +return 0; +} + +static int l_SetGlobalLuaBoolTrue (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + + gLuaGlobal[val].fGlobalLuaBool = TRUE; + + +return 0; +} + +static int l_SetGlobalLuaBool (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +BOOLEAN set; +UINT32 val; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + if (i == 2 ) set = lua_toboolean(L,i); + } + +if ( val >=0 || 1000<= val ) + gLuaGlobal[val].fGlobalLuaBool = set; + +return 0; +} + +static int l_SetGlobalLuaVal (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val,set; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + +if ( val >=0 || 1000<= val ) + gLuaGlobal[val].iGlobalLuaVal = set; + +return 0; +} + +static int l_GetGlobalLuaVal (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val,set; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + + set = gLuaGlobal[val].iGlobalLuaVal; + + lua_pushinteger(L, set); + +return 1; +} + +static int l_CheckGlobalLuaBool (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + //if (i == 2 ) set = lua_toboolean(L,i); + } + + Bool = gLuaGlobal[val].fGlobalLuaBool; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckGlobalLuaVal (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 val,set; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) val = lua_tointeger(L,i); + } + + set = gLuaGlobal[val].iGlobalLuaVal; + + lua_pushinteger(L, set); + +return 1; +} + +static int l_ItemTypeExistsAtLocation (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT32 GridNo,ItemIndex; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ItemIndex = lua_tointeger(L,i); + if (i == 2 ) GridNo = lua_tointeger(L,i); + } + + Bool = ItemTypeExistsAtLocation( GridNo, ItemIndex, 0, NULL ); + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_fCivGroupHostile (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 Group; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Group = lua_tointeger(L,i); + } + + Bool = gTacticalStatus.fCivGroupHostile[ Group ]; + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_fEnemyControlled (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +BOOLEAN Bool; +UINT16 id; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + Bool = StrategicMap[ id ].fEnemyControlled; + + lua_pushboolean(L, Bool); + +return 1; +} + +//anim +static int l_EVENT_InitNewSoldierAnim (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + + +SOLDIERTYPE * pSoldier; +UINT8 ubTargetNPC; + +UINT32 ANIM; +INT32 cnt; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + //if (i == 2 ) BodyType = lua_tointeger(L,i); + if (i == 2 ) ANIM = lua_tointeger(L,i); + if (i == 3 ) cnt = lua_tointeger(L,i); + //if (i == 4 ) PlayerControl = lua_tointeger(L,i); + } + + if (ubTargetNPC > -1) + { + pSoldier = FindSoldierByProfileID ( ubTargetNPC, TRUE ); + if ( pSoldier )//&& pSoldier->ubBodyType == BodyType ) + { + DeleteTalkingMenu(); + pSoldier->EVENT_InitNewSoldierAnim( ANIM, 0, TRUE ); + } + } + else if (ubTargetNPC == -1) + { + + + if ( MercPtrs[ cnt ]->bInSector ) + MercPtrs[ cnt ]->EVENT_InitNewSoldierAnim( ANIM, 0, TRUE ); + + } + +return 0; +} + +static int l_EnterShopKeeperInterfaceScreen (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +UINT8 ubCharacterNum; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCharacterNum = lua_tointeger(L,i); + } + + if( HandleShopKeepHasBeenShutDown( ubCharacterNum ) == FALSE ) + { + DeleteTalkingMenu( ); + EnterShopKeeperInterfaceScreen( ubCharacterNum ); + } + +return 0; +} + +static int l_CheckCombatMode (lua_State *L) +{ +UINT8 n = lua_gettop(L); +BOOLEAN Bool; + + Bool = ( gTacticalStatus.uiFlags & INCOMBAT ); + +lua_pushboolean(L, Bool); + +return 1; +} + +//--------------------------------------------- +static int l_SetEnterCombatMode (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT16 group; +UINT8 ubLoop; +SOLDIERTYPE * pGoon; +UINT8 ubID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) group = lua_tointeger(L,i); + if (i == 2 ) ubID = lua_tointeger(L,i); + } + + for ( ubLoop = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; ubLoop <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; ubLoop++ ) + { + pGoon = MercPtrs[ ubLoop ]; + if ( pGoon->ubCivilianGroup == group && pGoon->bActive && pGoon->bInSector && pGoon->stats.bLife >= OKLIFE && pGoon->aiData.bOppList[ ubID ] == SEEN_CURRENTLY ) + { + MakeCivHostile( pGoon, 2 ); + if ( ! (gTacticalStatus.uiFlags & INCOMBAT) ) + { + EnterCombatMode( pGoon->bTeam ); + } + } + } + +return 0; +} + +static int l_SetEnterCombatModeTeam (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 Team; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Team = lua_tointeger(L,i); + } + + if ( ! (gTacticalStatus.uiFlags & INCOMBAT) ) + { + EnterCombatMode( Team ); + } + +return 0; +} + +static int l_MakeMercPtrsHostile (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + + MakeCivHostile( MercPtrs[ ubID ], 2 ); + +return 0; +} + + +static int l_ChangeNpcToDifferentSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubNpcId; +INT16 sSectorX; +INT16 sSectorY; +INT8 bSectorZ; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubNpcId = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + if (i == 4 ) bSectorZ = lua_tointeger(L,i); + } + + ChangeNpcToDifferentSector( ubNpcId, sSectorX, sSectorY, bSectorZ ); + +return 0; +} + +static int l_PlayerInARoom (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 ubRoom,ubRoom2; +UINT32 sGridNo; +BOOLEAN Bool; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + if (i == 2 ) ubRoom2 = lua_tointeger(L,i); + } + + if ( InARoom( sGridNo, &ubRoom ) && ubRoom == ubRoom2 ) + { + Bool = TRUE; + } + else + { + Bool = FALSE; + } + + lua_pushboolean(L, Bool); + +return 1; +} + + +static int l_EVENT_SoldierGotHit (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +SOLDIERTYPE *pTarget2; +UINT8 UID; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + if ( gMercProfiles[ UID ].bMercStatus != MERC_IS_DEAD ) + { + pTarget2 = FindSoldierByProfileID( UID, FALSE ); + if (pTarget2) + { + DeleteTalkingMenu(); + if ( pTarget2->stats.bLife >= 0 ) + { + pTarget2->EVENT_SoldierGotHit( 1, 100, 10, pTarget2->ubDirection, 320, NOBODY , FIRE_WEAPON_NO_SPECIAL, AIM_SHOT_TORSO, 0, NOWHERE ); + } + } + } + +return 0; +} + +/* +static int l_SetSoldierSide (lua_State *L) +{ + +UINT8 n = lua_gettop(L); +int i; +INT8 bNewSide; +SOLDIERTYPE *pSoldier; +UINT8 ubID; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) bNewSide = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + { pSoldier = MercPtrs[ ubID ]; + if (pSoldier) + { + pSoldier->bSide = bNewSide; + } + } + +return 0; +} + +*/ + +static int l_SetSoldierSide (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 bNewSide; +SOLDIERTYPE *pSoldier; +UINT8 UID; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + if (i == 2 ) bNewSide = lua_tointeger(L,i); + } + + if ( UID != NO_PROFILE ) + { + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + pSoldier->bSide = bNewSide; + } + } + else + { + pSoldier = FindSoldierByProfileID_( UID ); + if ( pSoldier->ubProfile == UID ) + { + if (pSoldier) + { + pSoldier->bSide = bNewSide; + } + } + } + +return 0; +} + + +static int l_CheckSoldierSide (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 bNewSide; +SOLDIERTYPE *pSoldier; +UINT8 UID; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + + if ( UID != NO_PROFILE ) + { + pSoldier = FindSoldierByProfileID( UID, FALSE); + if (pSoldier) + { + bNewSide = pSoldier->bSide; + } + } + else + { + pSoldier = FindSoldierByProfileID_( UID ); + if ( pSoldier->ubProfile == UID ) + { + if (pSoldier) + { + bNewSide = pSoldier->bSide; + } + } + } + + lua_pushinteger(L, bNewSide); + +return 1; +} + +static int l_CheckSoldierNeutral (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +SOLDIERTYPE *pSoldier; +UINT8 UID; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + + if ( UID != NO_PROFILE ) + { + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + if ( pSoldier->aiData.bNeutral ) + Bool = TRUE; + else + Bool = FALSE; + } + } + else + { + pSoldier = FindSoldierByProfileID_( UID ); + if ( pSoldier->ubProfile == UID ) + { + if (pSoldier) + { + if ( pSoldier->aiData.bNeutral ) + Bool = TRUE; + else + Bool = FALSE; + } + } + } + + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckSoldierCivilianGroup (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 bGroup; +SOLDIERTYPE *pSoldier; +UINT8 UID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + bGroup = pSoldier->ubCivilianGroup; + } + + lua_pushinteger(L, bGroup); + +return 1; +} + +static int l_CheckSoldierubProfile (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 bGroup; +SOLDIERTYPE *pSoldier; +UINT8 UID; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + + bGroup = pSoldier->ubProfile; + } + + lua_pushinteger(L, bGroup); + +return 1; +} + +static int l_SetSoldierOrders (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +SOLDIERTYPE *pSoldier; +UINT8 Orders , UID; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + if (i == 2 ) Orders = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + + pSoldier->aiData.bOrders = Orders; + } + +return 0; +} + +static int l_CheckForPotentialAddToBattleIncrement (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +SOLDIERTYPE *pSoldier; +UINT8 UID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + + if (pSoldier) + CheckForPotentialAddToBattleIncrement( pSoldier ); + +return 0; +} + +static int l_RecalculateOppCntsDueToNoLongerNeutral (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +SOLDIERTYPE *pSoldier; +UINT8 UID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + + if (pSoldier) + RecalculateOppCntsDueToNoLongerNeutral( pSoldier ); + + +return 0; +} + +static int l_CheckSoldierActive (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +SOLDIERTYPE *pSoldier; +UINT8 UID; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + if ( pSoldier->bActive ) + Bool = TRUE; + else + Bool = FALSE; + } + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_CheckSoldierInSector (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + +SOLDIERTYPE *pSoldier; +UINT8 UID; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + if ( pSoldier->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + } + + lua_pushboolean(L, Bool); + +return 1; +} + +static int l_GetSoldierTeam (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 Side; +SOLDIERTYPE *pSoldier; +UINT8 UID; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + Side = pSoldier->bSide; + } + + lua_pushinteger(L, Side); + +return 1; +} + +static int l_ChangeSoldierTeam (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 Side; +SOLDIERTYPE *pSoldier; +UINT8 UID; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + if (i == 2 ) Side = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( UID, FALSE ); + if (pSoldier) + { + + ChangeSoldierTeam( pSoldier, Side ); + } + + +return 0; +} + +static int l_ChangeMercPtrsTeam (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +INT8 Side; +SOLDIERTYPE *pSoldier; +UINT8 UID; +BOOLEAN Bool; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) UID = lua_tointeger(L,i); + if (i == 2 ) Side = lua_tointeger(L,i); + } + + if ( MercPtrs[ UID ]->bInSector && MercPtrs[ UID ]->bActive ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + { pSoldier = MercPtrs[ UID ]; + if (pSoldier) + { + pSoldier->bSide = Side; + } + } + +return 0; +} + +//------------------- + + +static int l_ExecuteStrategicAIAction (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT16 usActionCode;// See list in "interface Dialogue.h" +INT16 sSectorX; // Target X location of strategic action +INT16 sSectorY; // Target Y location of strategic action +INT32 option1 = 0; // Option 1, vaies with action +INT32 option2 = 0; // Option 2, vaies with action + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) usActionCode = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + if (i == 4 ) option1 = lua_tointeger(L,i); + if (i == 5 ) option2 = lua_tointeger(L,i); + } + + ExecuteStrategicAIAction( usActionCode, sSectorX, sSectorY, option1, option2); + +return 0; +} + +//AddEmail +static int l_AddEmail (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + + +INT32 iMessageOffset; +INT32 iMessageLength; +UINT8 ubSender; + +INT32 iCurrentIMPPosition; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) iMessageOffset = lua_tointeger(L,i); + if (i == 2 ) iMessageLength = lua_tointeger(L,i); + if (i == 3 ) ubSender = lua_tointeger(L,i); + //if (i == 4 ) iDate = lua_tointeger(L,i); + if (i == 4 ) iCurrentIMPPosition = lua_tointeger(L,i); + } + + AddEmail(iMessageOffset,iMessageLength,ubSender, GetWorldTotalMin(), iCurrentIMPPosition); + +return 0; +} + +//AddPreReadEmail +static int l_AddPreReadEmail (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + + +INT32 iMessageOffset; +INT32 iMessageLength; +UINT8 ubSender; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) iMessageOffset = lua_tointeger(L,i); + if (i == 2 ) iMessageLength = lua_tointeger(L,i); + if (i == 3 ) ubSender = lua_tointeger(L,i); + } + + AddPreReadEmail(iMessageOffset,iMessageLength,ubSender, GetWorldTotalMin()); + +return 0; +} + +//gfBoxerFought +static int l_SetgfBoxerFought (lua_State *L) +{ +UINT8 n = lua_gettop(L); +UINT8 id; +BOOLEAN Bool; +int i; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,n); + if (i == 2 ) Bool = lua_toboolean(L,n); + } + +gfBoxerFought[id] = Bool; + +return 0; +} + +static int l_GetWorldHour (lua_State *L) +{ +UINT32 h2; + +h2 = GetWorldHour(); + +lua_pushinteger(L, h2); + +return 1; +} + +static int l_GetWorldMinutesInDay (lua_State *L) +{ +UINT32 uiTime; + +uiTime = GetWorldMinutesInDay(); + +lua_pushinteger(L, uiTime); + +return 1; +} + +//--------------------------------------------------------------------------------------- + +BOOLEAN LetLuaHandleEarlyMorningEvents(UINT8 Init) +{ + char * filename = "scripts\\StrategicEventHandler.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + SGP_THROW(msg); + } + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function +// lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); +// lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleEarlyMorningEvents"); + lua_call(L,0,0); + } + /* + if ( Init == 1 ) + { + lua_getglobal(L , "HandlePossiblyDamagedPackage"); + lua_call(L,0,0); + } + + if ( Init == 2 ) + { + lua_getglobal(L , "AddSecondAirportAttendant"); + lua_call(L,0,0); + } + + if ( Init == 3 ) + { + lua_getglobal(L , "SetPabloToUnbribed"); + lua_call(L,0,0); + } + + if ( Init == 4 ) + { + lua_getglobal(L , "CheckForMissingHospitalSupplies"); + lua_call(L,0,0); + } + */ + lua_close(L); + + delete[] buffer; + + return true; + +} + +/* +BOOLEAN LetLuaHandleNPCSystemEvent( UINT32 uiEvent, UINT8 Init) +{ + char * filename = "scripts\\StrategicEventHandler.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + return false; + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function + lua_register(L, "CheckFact", l_CheckFact); + lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); + lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleNPCSystemEvent"); + lua_pushnumber(L, uiEvent); + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + return true; + +} +*/ +//--------------- + +static int l_FindItemSoldier (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; + + +SOLDIERTYPE *pSoldier; +UINT8 ubTargetNPC; +UINT32 ItemIndex; +UINT32 Grido; +INT8 bItemIn; +BOOLEAN fPlayerMercsOnly; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) ItemIndex = lua_tointeger(L,i); + if (i == 3 ) Grido = lua_tointeger(L,i); + if (i == 4 ) fPlayerMercsOnly = lua_toboolean(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, fPlayerMercsOnly); + if (pSoldier) + { + bItemIn = FindObj( pSoldier, ItemIndex ); + if (bItemIn != NO_SLOT) + { + AddItemToPool( Grido, &(pSoldier->inv[bItemIn]), -1 , 0, 0, 0 ); + DeleteObj( &(pSoldier->inv[ bItemIn ]) ); + RemoveObjectFromSoldierProfile( ubTargetNPC, ItemIndex ); + } + } +return 0; +} + +//Create items +static int l_CreateItem (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i; + INT32 iWorldItem; + OBJECTTYPE Object; + INT32 sGridNo; + UINT16 usItem; + INT16 bStatus; + UINT8 bLevel; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) usItem = lua_tointeger(L,i); + if (i == 2 ) bStatus = lua_tointeger(L,i); + if (i == 3 ) sGridNo = lua_tointeger(L,i); + if (i == 4 ) bLevel = lua_tointeger(L,i); + } + + CreateItem( usItem, bStatus, &Object ); + AddItemToPoolAndGetIndex( sGridNo, &Object, -1, bLevel, 0, 0, -1, &iWorldItem ); + + return 0; +} + +//Create items +static int l_CreateToUnLoadedSector (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i; + OBJECTTYPE Object; + INT32 sGridNo; + UINT16 usItem; + INT16 bStatus; + INT16 sMapX; + INT16 sMapY; + INT8 bMapZ; + UINT32 uiNumberOfItems; + UINT8 ubLevel; + UINT16 usFlags; + INT8 bRenderZHeightAboveLevel; + INT8 bVisible; + BOOLEAN fReplaceEntireFile; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) usItem = lua_tointeger(L,i); + if (i == 2 ) bStatus = lua_tointeger(L,i); + if (i == 3 ) sMapX = lua_tointeger(L,i); + if (i == 4 ) sMapY = lua_tointeger(L,i); + if (i == 5 ) bMapZ = lua_tointeger(L,i); + if (i == 6 ) sGridNo = lua_tointeger(L,i); + if (i == 7 ) uiNumberOfItems = lua_tointeger(L,i); + if (i == 8 ) ubLevel = lua_tointeger(L,i); + if (i == 9 ) usFlags = lua_tointeger(L,i); + if (i == 10 ) bRenderZHeightAboveLevel = lua_tointeger(L,i); + if (i == 11 ) bVisible = lua_tointeger(L,i); + if (i == 12 ) fReplaceEntireFile = lua_toboolean(L,i); + } + + CreateItem( usItem, bStatus, &Object ); + AddItemsToUnLoadedSector( sMapX, sMapY, bMapZ, sGridNo, uiNumberOfItems, &Object, ubLevel, usFlags, bRenderZHeightAboveLevel, bVisible, fReplaceEntireFile ); + + return 0; +} + +//Create items +static int l_CreateItemToPool (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i; + OBJECTTYPE Object; + INT32 sGridNo; + UINT16 usItem; + INT16 bStatus; + UINT8 ubLevel; + INT8 bVisible; + UINT16 usFlags; + INT8 bRenderZHeightAboveLevel; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) usItem = lua_tointeger(L,i); + if (i == 2 ) bStatus = lua_tointeger(L,i); + if (i == 3 ) sGridNo = lua_tointeger(L,i); + if (i == 5 ) bVisible = lua_tointeger(L,i); + if (i == 5 ) ubLevel = lua_tointeger(L,i); + if (i == 6 ) usFlags = lua_tointeger(L,i); + if (i == 7 ) bRenderZHeightAboveLevel = lua_tointeger(L,i); + } + + CreateItem( usItem, bStatus, &Object ); + AddItemToPool( sGridNo, &Object, bVisible, ubLevel, usFlags, bRenderZHeightAboveLevel ); + + return 0; +} + +static int l_CreateMoney (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + INT32 iWorldItem = 0; + OBJECTTYPE Object; + INT32 sGridNo = 0; + UINT16 money = 0; + + UINT8 bLevel = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) money = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + if (i == 3 ) bLevel = lua_tointeger(L,i); + } + + CreateMoney(money, &Object ); + AddItemToPoolAndGetIndex( sGridNo, &Object, -1, bLevel, 0, 0, -1, &iWorldItem ); + + return 0; +} + +//RecruitRPC +static int l_RecruitRPC (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + RecruitRPC( id ); + + return 0; +} + +//RecruitEPC +static int l_RecruitEPC (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + if ( !CheckNPCIsEPC(id) ) + RecruitEPC( id ); + + return 0; +} + +//UnRecruitEPC +static int l_UnRecruitEPC (lua_State *L) +{ +UINT8 n = lua_gettop(L); +int i; +UINT8 id; + + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + +if (CheckNPCIsEPC(id)) + UnRecruitEPC( id ); + +return 0; +} + +static int l_FindSoldierTeam (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 team = 0; + UINT8 ubTargetNPC; + SOLDIERTYPE *pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC,FALSE); + if (pSoldier ) + { + + if ( pSoldier->bTeam == OUR_TEAM ) + team = 0; + else if ( pSoldier->bTeam == ENEMY_TEAM ) + team = 1; + else if ( pSoldier->bTeam == CREATURE_TEAM ) + team = 2; + else if ( pSoldier->bTeam == MILITIA_TEAM ) + team = 3; + else if ( pSoldier->bTeam == CIV_TEAM ) + team = 4; + else if ( pSoldier->bTeam == PLAYER_PLAN ) + team = 5; + } + + lua_pushinteger(L, team); + + return 1; +} + +static int l_EVENT_StopMerc (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) + ubTargetNPC = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE); + if (pSoldier ) + { + pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection ); + } + +return 0; +} + +static int l_GetGridoProfileID (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + + UINT32 grido = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + // if (i == 2 ) fPlayerMercsOnly = lua_toboolean(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE); + if ( pSoldier ) + grido = pSoldier->sGridNo; + else + grido = 0; + + lua_pushinteger(L, grido); + +return 1; +} + +static int l_GetDirection (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + + UINT32 Direction; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE); + if ( pSoldier ) + Direction = pSoldier->ubDirection; + else + Direction = 0; + + lua_pushinteger(L, Direction); + + return 1; +} + +static int l_ubID (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + + UINT32 ubID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) + ubTargetNPC = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE); + if ( pSoldier ) + ubID = pSoldier->ubID; + else + ubID = -1; + + lua_pushinteger(L, ubID); + + return 1; +} +//------------ +static int l_GetFirstID (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i; + UINT8 team = 0; + UINT32 id; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) team = lua_tointeger(L,i); + } + + id = gTacticalStatus.Team[ team ].bFirstID; + + lua_pushinteger(L, id); + + return 1; +} + +static int l_GetLastID (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 team = 0; + UINT32 id = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) team = lua_tointeger(L,i); + } + + id = gTacticalStatus.Team[ team ].bLastID; + + lua_pushinteger(L, id); + + return 1; +} + +static int l_SetCivGroupHostile (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 status = 0,Civ = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Civ = lua_tointeger(L,i); + if (i == 2 ) status = lua_tointeger(L,i); + } + + gTacticalStatus.fCivGroupHostile[ Civ ] = status; + + return 0; +} + +//Merc +static int l_CheckMercPtrsActive (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + UINT32 ubID = 0; + + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bActive ) + Bool = TRUE; + else + Bool = FALSE; + + lua_pushboolean(L, Bool); + + return 1; +} + +static int l_CheckMercPtsrInSector (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + UINT32 ubID = 0; + + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + lua_pushboolean(L, Bool); + + return 1; +} + +static int l_WearGasMaskIfAvailable(lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubID = 0; + BOOLEAN Bool = FALSE; + SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + { + pSoldier = MercPtrs[ ubID ]; + + if (pSoldier) + { + WearGasMaskIfAvailable(pSoldier); + } + } + + return 0; +} + +static int l_SetNewSituationMercPtsr(lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubID = 0; + BOOLEAN Bool = FALSE; + SOLDIERTYPE * pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + { + pSoldier = MercPtrs[ ubID ]; + + if (pSoldier) + { + SetNewSituation(pSoldier); + } + } + + return 0; +} + +static int l_gsPublicNoiseGridNo(lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 Team = 0; + UINT32 sGridNo = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Team = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + } + + gsPublicNoiseGridNo[ Team ] = sGridNo; + + return 0; +} + +static int l_gubPublicNoiseVolume(lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 Team = 0; + UINT32 Duration = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Team = lua_tointeger(L,i); + if (i == 2 ) Duration = lua_tointeger(L,i); + } + + //MAX_MISC_NOISE_DURATION + gubPublicNoiseVolume[ Team ] = Duration; + + return 0; +} + +static int l_AnimMercPtsrInSector (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + UINT32 ubID = 0,Anim = 0; + + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) Anim = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->EVENT_InitNewSoldierAnim( Anim, 0, TRUE ); + + return 0; +} + +static int l_AnimMercPtsrfAIFlags(lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->aiData.fAIFlags |= AI_HANDLE_EVERY_FRAME; + + return 0; +} + +static int l_AnimMercPtsrusStrategicInsertionData(lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,GridNo = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) GridNo = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->usStrategicInsertionData = GridNo; + + return 0; +} + + +static int l_AnimMercPtsrubStrategicInsertionCode (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,GridNo = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) GridNo = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->ubStrategicInsertionCode = GridNo; + + return 0; +} + +static int l_WhichBuddy (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID1 = 0,ubID2 = 0,bBuddyIndex = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID1 = lua_tointeger(L,i); + if (i == 2 ) ubID2 = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID1 ]->bInSector && MercPtrs[ ubID2 ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + bBuddyIndex = WhichBuddy( ubID1, ubID2 ); + + lua_pushinteger(L, bBuddyIndex); + + return 1; +} + +static int l_AnimMercPtsrsAbsoluteFinalDestination (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,GridNo = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) GridNo = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->sAbsoluteFinalDestination = GridNo; + + return 0; +} + +static int l_AnimMercPtsrusNextActionData (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,GridNo = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) GridNo = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->aiData.usNextActionData = GridNo; + + return 0; +} + +static int l_AnimMercPtsrbNextAction (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,AI_ACTION = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) AI_ACTION = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->aiData.bNextAction = AI_ACTION; + + return 0; +} + +static int l_SetSoldierBodyType (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,Anim = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) Anim = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + MercPtrs[ ubID ]->ubBodyType = Anim; + + return 0; +} + +static int l_GetSoldierBodyType (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,Anim = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + Anim = MercPtrs[ ubID ]->ubBodyType; + + lua_pushinteger(L, Anim); + + return 1; +} + +static int l_CheckSoldierBodyType (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,Anim = 0; + BOOLEAN Bool = FALSE, Bool2 = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) Anim = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive ) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + { + if ( MercPtrs[ ubID ]->ubBodyType == Anim ) + Bool2 = TRUE; + else + Bool2 = FALSE; + } + + lua_pushboolean(L, Bool2); + + return 1; +} + +static int l_IS_CIV_BODY_TYPE (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive && IS_CIV_BODY_TYPE (MercPtrs[ ubID ]) == TRUE ) + Bool = TRUE; + else + Bool = FALSE; + + lua_pushboolean(L, Bool); + + return 1; +} + +static int l_SetOffBombsInGridNo (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubID = 0; + INT32 sGridNo = 0; + BOOLEAN fAllBombs = FALSE; + INT8 bLevel = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + if (i == 3 ) fAllBombs = lua_toboolean(L,i); + if (i == 4 ) bLevel = lua_tointeger(L,i); + } + + SetOffBombsInGridNo( ubID, sGridNo, fAllBombs,bLevel ); + return 0; +} + + +static int l_AnimMercPtsrSoldierGotHit (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + //if (i == 2 ) Anim = lua_tointeger(L,i); + } + + if ( MercPtrs[ ubID ]->bInSector && MercPtrs[ ubID ]->bActive) + Bool = TRUE; + else + Bool = FALSE; + + if ( Bool == TRUE ) + { + if ( MercPtrs[ ubID ]->stats.bLife >= 0 ) + { + MercPtrs[ ubID ]->EVENT_SoldierGotHit( 1, 100, 10, MercPtrs[ ubID ]->ubDirection, 320, NOBODY , FIRE_WEAPON_NO_SPECIAL, AIM_SHOT_TORSO, 0, NOWHERE ); + } + } + + return 0; +} + +static int l_CheckMercPtsrubIDSeenubID2 (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubID = 0,ubID2 = 0; + UINT16 seen = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + if (i == 2 ) ubID2 = lua_tointeger(L,i); + } + + seen = MercPtrs[ ubID ]->aiData.bOppList[ ubID2 ]; + + lua_pushinteger(L, seen); + + return 1; +} + +static int l_CheckMercPtrsInCivilianGroup (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 group = 0; + UINT32 ubID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + group = MercPtrs[ ubID ]->ubCivilianGroup; + + lua_pushinteger(L, group); + return 1; +} + +//------------ + +//INT32 NewGridNo(INT32 sGridNo, INT16 sDirInc); +//INT16 DirectionInc(UINT8 ubDirection); +//INT32 OutOfBounds(INT32 sGridNo, INT32 sProposedGridNo); + +static int l_TileIsOutOfBounds (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + INT32 sGridNo = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + } + + TileIsOutOfBounds(sGridNo); + + return 0; +} + +static int l_ClosestPC (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + INT32 psDistance = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) psDistance = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE); + if ( pSoldier ) + { + ClosestPC( pSoldier, &psDistance ); + } + + return 0; +} + +static int l_TileIsOutOfBoundsClosestPC (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + BOOLEAN Bool = FALSE , fPlayerMercsOnly = FALSE; + INT32 sDist = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) fPlayerMercsOnly = lua_toboolean(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, fPlayerMercsOnly); + if ( pSoldier ) + { + + if ( TileIsOutOfBounds(ClosestPC( pSoldier, &sDist )) && sDist > NPC_TALK_RADIUS * 2 ) + Bool = TRUE; + else + Bool = FALSE; + + } + + lua_pushboolean(L, Bool); + + return 1; +} + +static int l_FindSoldierByProfileID (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0,ubLoop = 0,ubLoopLimit = 0; + SOLDIERTYPE *pSoldier; + UINT8 id = -1; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + // if (i == 2 ) fPlayerMercsOnly = lua_tointeger(L,i); + } + + ubLoopLimit = MAX_NUM_SOLDIERS; + + for (ubLoop = 0, pSoldier = MercPtrs[0]; ubLoop < ubLoopLimit; ubLoop++, pSoldier++) + { + if (pSoldier->bActive && pSoldier->ubProfile == ubTargetNPC) + { + id = pSoldier->ubProfile; + } + } + + lua_pushinteger(L, id); + + return 1; +} + +static int l_ubWhatKindOfMercAmI (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 team = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + // if (i == 2 ) fPlayerMercsOnly = lua_toboolean(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC,TRUE);//, fPlayerMercsOnly); + if (pSoldier ) + { + + if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) + team = 0; + else if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) + team = 1; + else if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC ) + team = 2; + else if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__NPC ) + team = 3; + else if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__EPC ) + team = 4; + else if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__NPC_WITH_UNEXTENDABLE_CONTRACT ) + team = 5; + else if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE ) + team = 6; + } + + lua_pushinteger(L, team); + + return 1; +} + +static int l_PythSpacesAway (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + INT32 sOrigin = 0; + INT32 sDest = 0; + + SOLDIERTYPE *pSoldier; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) sDest = lua_tointeger(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE); + + if (pSoldier ) + sOrigin = PythSpacesAway( pSoldier->sGridNo, sDest ); + + lua_pushinteger(L, sOrigin); + + return 1; +} + +static int l_MakeHostile (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 ubTargetNPC = 0; + SOLDIERTYPE *pSoldier; + BOOLEAN fPlayerMercsOnly = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubTargetNPC = lua_tointeger(L,i); + if (i == 2 ) fPlayerMercsOnly = lua_toboolean(L,i); + } + + pSoldier = FindSoldierByProfileID( ubTargetNPC, fPlayerMercsOnly ); + if (pSoldier ) + { + if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP ) + { + if ( gTacticalStatus.fCivGroupHostile[ pSoldier->ubCivilianGroup ] == CIV_GROUP_NEUTRAL ) + { + CivilianGroupMemberChangesSides( pSoldier ); + } + } + else + { + // make hostile + MakeCivHostile( pSoldier, 2 ); + } + DeleteTalkingMenu(); + if ( ! ( gTacticalStatus.uiFlags & INCOMBAT ) ) + { + EnterCombatMode( pSoldier->bTeam ); + } + } + + return 0; +} +//--------------- + +//-------------New-------------- +static int l_GetTimeQuestWasStarted (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT32 ubCode = 0, ubCode2 = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubCode = lua_tointeger(L,i); + } + + ubCode2 = GetTimeQuestWasStarted( ubCode ); + + lua_pushinteger(L, ubCode2); + + return 1; +} + +static int l_gubQuest (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 quest = 0; + UINT8 Bool = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) quest = lua_tointeger(L,i); + } + + if (gubQuest[ quest ] == QUESTNOTSTARTED) + Bool = 0; + else if (gubQuest[ quest ] == QUESTINPROGRESS) + Bool = 1; + else if (gubQuest[ quest ] == QUESTDONE) + Bool = 2; + lua_pushinteger(L, Bool); + + + return 1; +} + +static int l_GetTacticalStatusEnemyInSector (lua_State *L) +{ + UINT8 n = lua_gettop(L); + BOOLEAN Bool = FALSE; + Bool = gTacticalStatus.fEnemyInSector; + + lua_pushboolean(L, Bool); + + return 1; +} + +//InTownSectorWithTrainingLoyalty +static int l_InTownSectorWithTrainingLoyalty (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + INT16 sSectorX = 0; + INT16 sSectorY = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sSectorX = lua_tointeger(L,i); + if (i == 2 ) sSectorY = lua_tointeger(L,i); + } + + Bool = InTownSectorWithTrainingLoyalty( sSectorX, sSectorY ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//NPCHeardShot +static int l_NPCHeardShot (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = NPCHeardShot( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//CheckNPCIsUnderFire +static int l_CheckNPCIsUnderFire (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = CheckNPCIsUnderFire( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//CheckNPCCowering +static int l_CheckNPCCowering (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = CheckNPCCowering( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//AIMMercWithin +static int l_AIMMercWithin (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + INT32 sGridNo = 0; + INT16 sDistance = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) sGridNo = lua_tointeger(L,i); + if (i == 2 ) sDistance = lua_tointeger(L,i); + } + + Bool = AIMMercWithin( sGridNo, sDistance ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//CheckNPCSectorBool +static int l_CheckNPCSectorBool (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + INT16 sSectorX = 0; + INT16 sSectorY = 0; + INT8 bSectorZ = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + if (i == 2 ) sSectorX = lua_tointeger(L,i); + if (i == 3 ) sSectorY = lua_tointeger(L,i); + if (i == 4 ) bSectorZ = lua_tointeger(L,i); + } + + //if (gMercProfiles[ id ].sSectorX == sSectorX && gMercProfiles[ id ].sSectorY == sSectorY && gMercProfiles[ id ].bSectorZ == bSectorZ) + // Bool = TRUE; + //else + // Bool = FALSE; + + Bool = CheckNPCSector( ubProfileID, sSectorX, sSectorY, bSectorZ ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//FemalePresent +static int l_FemalePresent (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = FemalePresent( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//PCInSameRoom +static int l_PCInSameRoom (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = PCInSameRoom( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//NPCInRoomRange +static int l_NPCInRoomRange (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + UINT8 ubRoomID1 = 0; + UINT8 ubRoomID2 = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + if (i == 2 ) ubRoomID1 = lua_tointeger(L,i); + if (i == 3 ) ubRoomID2 = lua_tointeger(L,i); + } + + Bool = NPCInRoomRange( ubProfileID, ubRoomID1,ubRoomID2 ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//NPCInRoom +static int l_NPCInRoom (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + UINT8 ubRoomID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + if (i == 2 ) ubRoomID = lua_tointeger(L,i); + } + + Bool = NPCInRoom( ubProfileID, ubRoomID ); + + lua_pushboolean(L, Bool); + + return 1; +} + + +//CheckNPCIsRPC +static int l_CheckNPCIsRPC (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = CheckNPCIsRPC( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + + +//CheckNPCIsEPC +static int l_CheckNPCIsEPC (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = CheckNPCIsEPC( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//CheckNPCIsEnemy +static int l_CheckNPCIsEnemy (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + BOOLEAN Bool = FALSE; + UINT8 ubProfileID = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubProfileID = lua_tointeger(L,i); + } + + Bool = CheckNPCIsEnemy( ubProfileID ); + + lua_pushboolean(L, Bool); + + return 1; +} + + +//CheckNPCAt +static int l_CheckNPCAt (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + BOOLEAN Bool = FALSE; + UINT8 ubNPC = 0; + INT32 sGridNo = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubNPC = lua_tointeger(L,i); + if (i == 2 ) sGridNo = lua_tointeger(L,i); + } + + Bool = CheckNPCAt( ubNPC, sGridNo ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//CheckGuyVisible +static int l_CheckGuyVisible (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + BOOLEAN Bool = FALSE; + UINT8 ubNPC = 0; + UINT8 ubGuy = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubNPC = lua_tointeger(L,i); + if (i == 2 ) ubGuy = lua_tointeger(L,i); + } + + Bool = CheckGuyVisible( ubNPC, ubGuy ); + + lua_pushboolean(L, Bool); + + return 1; +} + + + +//CheckNPCWithin +static int l_CheckNPCWithin (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + BOOLEAN Bool = FALSE; + UINT8 ubFirstNPC = 0; + UINT8 ubSecondNPC = 0; + UINT8 ubMaxDistance = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubFirstNPC = lua_tointeger(L,i); + if (i == 2 ) ubSecondNPC = lua_tointeger(L,i); + if (i == 3 ) ubMaxDistance = lua_tointeger(L,i); + } + + Bool = CheckNPCWithin( ubFirstNPC, ubSecondNPC, ubMaxDistance ); + + lua_pushboolean(L, Bool); + + return 1; +} + + +//CheckNPCInOkayHealth +static int l_CheckNPCInOkayHealth (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + Bool = CheckNPCInOkayHealth( id ); + + lua_pushboolean(L, Bool); + + return 1; +} + + +//CheckNPCWounded +static int l_CheckNPCWounded (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + Bool = CheckNPCWounded( id, FALSE ); + + lua_pushboolean(L, Bool); + + return 1; +} + +static int l_CheckNPCWoundedbyPlayer (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + Bool = CheckNPCWounded( id, TRUE ); + + lua_pushboolean(L, Bool); + + return 1; +} + +//------------ +//CheckNPCBleeding +static int l_CheckNPCBleeding (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + Bool = CheckNPCBleeding (id); + + lua_pushboolean(L, Bool); + + return 1; +} + +//Check character SectorZ +static int l_CheckCharacterSectorZ (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT16 SectorZ = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorZ = gMercProfiles[ id ].bSectorZ; + + lua_pushinteger(L, SectorZ); + + return 1; +} + +//Check character SectorY +static int l_CheckCharacterSectorY (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT16 SectorY = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorY = gMercProfiles[ id ].sSectorY; + + lua_pushinteger(L, SectorY); + + return 1; +} + +//Check character SectorX +static int l_CheckCharacterSectorX (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + UINT8 id = 0; + UINT16 SectorX = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorX = gMercProfiles[ id ].sSectorX; + + lua_pushinteger(L, SectorX); + + return 1; +} + +//SetPendingNewScreen( SEX_SCREEN ); +static int l_SetPendingNewScreenSEXSCREEN (lua_State *L) +{ + UINT8 n = lua_gettop(L); + + SetPendingNewScreen( SEX_SCREEN ); + + return 0; +} +//-------------- + +//Set charcter to sector Z +static int l_GetCharacterSectorZ (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT8 SectorZ = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorZ = gMercProfiles[ id ].bSectorZ; + + lua_pushinteger(L, SectorZ); + + return 1; +} + +//Set charcter to sector Y +static int l_GetCharacterSectorY (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT16 SectorY = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorY = gMercProfiles[ id ].sSectorY; + + lua_pushinteger(L, SectorY); + + return 1; +} + +//Set charcter to sector X +static int l_GetCharacterSectorX (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT16 SectorX = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorX = gMercProfiles[ id ].sSectorX; + + lua_pushinteger(L, SectorX); + + return 1; +} + +//----------- +//Set charcter to sector Z +static int l_SetCharacterSectorZ (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT8 SectorZ = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + if (i == 2 ) SectorZ = lua_tointeger(L,i); + } + + gMercProfiles[ id ].bSectorZ = SectorZ; + + return 0; +} + +//Set charcter to sector Y +static int l_SetCharacterSectorY (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT16 SectorY = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + if (i == 2 ) SectorY = lua_tointeger(L,i); + } + + gMercProfiles[ id ].sSectorY = SectorY; + + return 0; +} + +//Set charcter to sector X +static int l_SetCharacterSectorX (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + UINT8 id = 0; + UINT16 SectorX = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + if (i == 2 ) SectorX = lua_tointeger(L,i); + } + + gMercProfiles[ id ].sSectorX = SectorX; + +return 0; +} + +//Run TriggerRecord +static int l_TriggerNPCRecord(lua_State *L) +{ + UINT8 prof = 0,set = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) prof = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + TriggerNPCRecord (prof,set); + + return 0; +} + +//Run TriggerNPCRecordImmediately +static int l_TriggerNPCRecordImmediately(lua_State *L) +{ + UINT8 prof = 0,set = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) prof = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + TriggerNPCRecordImmediately (prof,set); + + return 0; +} + +//Add undern Ground Sector +static int l_AddAltUnderGroundSectorNew(lua_State *L) +{ + UINT8 x = 0,y = 0,z = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) x = lua_tointeger(L,i); + if (i == 2 ) y = lua_tointeger(L,i); + if (i == 3 ) z = lua_tointeger(L,i); + } + + if ((x>=1 || x<=16) && (y>=1 || y<=16) && (z>=0 || z<=3) ) + { + UNDERGROUND_SECTORINFO *pSector; + pSector = FindUnderGroundSector( x, y, z ); + if( pSector ) + { + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + } + } + + return 0; +} + +static int l_UnderGroundSectorVisited(lua_State *L) +{ + UINT8 x = 0,y = 0,z = 0; + UINT8 n = lua_gettop(L); + int i = 0; + BOOLEAN Bool = FALSE; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) x = lua_tointeger(L,i); + if (i == 2 ) y = lua_tointeger(L,i); + if (i == 3 ) z = lua_tointeger(L,i); + } + + if ((x>=1 || x<=16) && (y>=1 || y<=16) && (z>=0 || z<=3) ) + { + UNDERGROUND_SECTORINFO *pSector; + pSector = FindUnderGroundSector( x, y, z ); + if( pSector ) + { + Bool = pSector->fVisited; + + } + } + + lua_pushboolean(L, Bool); + + return 1; +} + +//Add underGroundSector +static int l_AddAlternateSectorNew(lua_State *L) +{ + UINT8 x = 0,y = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) x = lua_tointeger(L,i); + if (i == 2 ) y = lua_tointeger(L,i); + } + + if ((x>=1 || x<=16) && (y>=1 || y<=16)) + { + SectorInfo[ SECTOR( x, y ) ].uiFlags |= SF_USE_ALTERNATE_MAP; + } + + return 0; +} + +//Add character to sector +static int l_AddNPCTOSECTOR(lua_State *L) +{ + MERCPROFILESTRUCT * pProfile; + UINT8 x = 0,y = 0,z = 0,id = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + if (i == 2 ) x = lua_tointeger(L,i); + if (i == 3 ) y = lua_tointeger(L,i); + if (i == 4 ) z = lua_tointeger(L,i); + } + + if ( (x>=0 || x<=16) && (y>=0 || y<=16) && (z>=0 || z<=3) ) + { + pProfile = &(gMercProfiles[ id ]); + + pProfile->sSectorX = x; + pProfile->sSectorY = y; + pProfile->bSectorZ = z; + } + + return 0; +} + + +//Check character Sector New +static int l_CheckNPCSectorNew (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + UINT8 SectorZ = 0,id = 0; + UINT16 SectorX = 0,SectorY = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + SectorX = gMercProfiles[ id ].sSectorX; + SectorY = gMercProfiles[ id ].sSectorY; + SectorZ = gMercProfiles[ id ].bSectorZ; + + lua_pushinteger(L, id); + lua_pushinteger(L, SectorX); + lua_pushinteger(L, SectorY); + lua_pushinteger(L, SectorZ); + + return 4; +} + +//Check character Sector +static int l_CheckNPCSector (lua_State *L) +{ + UINT8 n = lua_gettop(L); + int i = 0; + + UINT8 SectorZ = 0,Z1 = 0,id = 0; + UINT16 SectorX = 0,SectorY = 0,X1 = 0,Y1 = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + if (i == 2 ) X1 = lua_tointeger(L,i); + if (i == 3 ) Y1 = lua_tointeger(L,i); + if (i == 4 ) Z1 = lua_tointeger(L,i); + } + + if( gMercProfiles[ id].sSectorX == X1) + { + SectorX = gMercProfiles[ id ].sSectorX; + } + + if (gMercProfiles[ id ].sSectorY == Y1) + { + SectorY = gMercProfiles[ id ].sSectorY; + } + + if (gMercProfiles[ id ].bSectorZ == Z1) + { + SectorZ = gMercProfiles[ id ].bSectorZ; + } + + lua_pushinteger(L, id); + lua_pushinteger(L, SectorX); + lua_pushinteger(L, SectorY); + lua_pushinteger(L, SectorZ); + + return 4; +} + +//Check Life character +static int l_bLife (lua_State *L) +{ + UINT8 IDNPC = lua_gettop(L); + UINT32 Life = 0; + UINT8 Profile = 0; + + Profile = lua_tointeger(L,IDNPC); + + Life = gMercProfiles[ Profile ].bLife; + + lua_pushinteger(L, Life); + + return 1; +} + +//Set Life character +static int l_SetbLife (lua_State *L) +{ + UINT8 n = lua_gettop(L); + UINT32 Life = 0; + UINT8 Profile = 0; + int i = 0; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) Life = lua_tointeger(L,i); + } + + gMercProfiles[ Profile ].bLife = Life; + + return 0; +} + +//Get Life Maxcharacter +static int l_GetbLifeMax (lua_State *L) +{ + UINT8 n = lua_gettop(L); + UINT32 Life = 0; + UINT8 Profile = 0; + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + } + + Life = gMercProfiles[ Profile ].bLifeMax; + + lua_pushinteger(L, Life); + + return 1; +} + +//check character LastDateSpokenTot +static int l_ubLastDateSpokenTot (lua_State *L) +{ + UINT8 IDNPC = lua_gettop(L); + UINT32 LastDateSpokenTo = 0; + UINT8 Profile = 0; + + Profile = lua_tointeger(L,IDNPC); + + LastDateSpokenTo = gMercProfiles[ Profile ].ubLastDateSpokenTo; + + lua_pushinteger(L, LastDateSpokenTo); + + return 1; +} + +//check character NPCData +static int l_fNPCData (lua_State *L) +{ + UINT8 IDNPC = lua_gettop(L); + UINT32 NPCData = 0; + UINT8 Profile = 0; + + Profile = lua_tointeger(L,IDNPC); + + NPCData = gMercProfiles[ Profile ].bNPCData; + + lua_pushinteger(L, NPCData); + + return 1; + +} + +//check character NPCData2 +static int l_fNPCData2 (lua_State *L) +{ + UINT8 IDNPC = lua_gettop(L); + UINT32 NPCData2 = 0; + UINT8 Profile = 0; + + Profile = lua_tointeger(L,IDNPC); + + NPCData2 = gMercProfiles[ Profile ].bNPCData2; + + lua_pushinteger(L, NPCData2); + + return 1; + +} + +//check character money +static int l_fuiMoney (lua_State *L) +{ + UINT8 IDNPC = lua_gettop(L); + UINT32 Money = 0; + UINT8 Profile = 0; + + Profile = lua_tointeger(L,IDNPC); + + Money = gMercProfiles[ Profile ].uiMoney; + + lua_pushinteger(L, Money); + + return 1; + +} + +//set money to character +static int l_SetuiMoney(lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + gMercProfiles[Profile].uiMoney = set; + + return 0; +} + +//set start quest +static int l_StartQuest(lua_State *L) +{ + UINT8 n = lua_gettop(L); + UINT8 Quest = 0; + UINT16 X = 0,Y = 0; + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Quest = lua_tointeger(L,i); + if (i == 2 ) X = lua_tointeger(L,i); + if (i == 3 ) Y = lua_tointeger(L,i); + } + + StartQuest( Quest, X, Y ); + + return 0; +} + +//set end quest +static int l_EndQuest(lua_State *L) +{ + UINT8 n = lua_gettop(L); + UINT8 Quest = 0; + UINT16 X = 0,Y = 0; + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Quest = lua_tointeger(L,i); + if (i == 2 ) X = lua_tointeger(L,i); + if (i == 3 ) Y = lua_tointeger(L,i); + } + + EndQuest( Quest, X, Y ); + + return 0; +} +//get +static int l_GetiBalance(lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + } + + + set = gMercProfiles[Profile].iBalance; + + lua_pushinteger(L, set); + + return 1; +} +//set balance character +static int l_iBalance(lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + gMercProfiles[Profile].iBalance = set; + + return 0; +} + +//set chracter NPCDATA1 +static int l_bNPCData(lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + gMercProfiles[Profile].bNPCData = set; + + return 0; +} + +//set chracter NPCDATA2 +static int l_bNPCData2(lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + gMercProfiles[Profile].bNPCData2 = set; + + return 0; +} + + +//check character MiscFlags2 +static int l_ubMiscFlags2Check (lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + UINT8 Flag = 0; + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + Flag = (gMercProfiles[Profile].ubMiscFlags2 & set); + + lua_pushinteger(L, Flag); + + return 1; +} + +//check character MiscFlags1 +static int l_ubMiscFlags1Check (lua_State *L) +{ + UINT32 set = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + + UINT8 Flag = 0; + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + Flag = (gMercProfiles[Profile].ubMiscFlags & set); + + + lua_pushinteger(L, Flag); + + return 1; + +} + +//set chracter MiscFlags1 +static int l_ubMiscFlags1Set(lua_State *L) +{ + UINT32 set = 0; + UINT32 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + if (set == 0) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_RECRUITED); + } + else if (set == 1) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_HAVESEENCREATURE); + } + else if (set == 2) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_FORCENPCQUOTE); + } + else if (set == 3) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_WOUNDEDBYPLAYER); + } + else if (set == 4) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_TEMP_NPC_QUOTE_DATA_EXISTS); + } + else if (set == 5) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_SAID_HOSTILE_QUOTE); + } + else if (set == 6 ) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_EPCACTIVE); + } + else if (set == 7 ) + { + gMercProfiles[Profile].ubMiscFlags &= (~PROFILE_MISC_FLAG_ALREADY_USED_ITEMS); + } + +/* +PROFILE_MISC_FLAG3_PLAYER_LEFT_MSG_FOR_MERC_AT_AIM +PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE +PROFILE_MISC_FLAG3_PLAYER_HAD_CHANCE_TO_HIRE +PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL +PROFILE_MISC_FLAG3_NPC_PISSED_OFF +PROFILE_MISC_FLAG3_MERC_MERC_IS_DEAD_AND_QUOTE_SAID +PROFILE_MISC_FLAG3_TOWN_DOESNT_CARE_ABOUT_DEATH +PROFILE_MISC_FLAG3_GOODGUY +*/ + return 0; +} + +//set chracter MiscFlags2 +static int l_ubMiscFlags2Set(lua_State *L) +{ + UINT32 set = 0; + UINT32 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + if (set == 0) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_DONT_ADD_TO_SECTOR); + } + else if (set == 1) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_LEFT_COUNTRY); + } + else if (set == 2) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_BANDAGED_TODAY); + } + else if (set == 3) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_SAID_FIRSTSEEN_QUOTE); + } + else if (set == 4) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_NEEDS_TO_SAY_HOSTILE_QUOTE); + } + else if (set == 5) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_MARRIED_TO_HICKS); + } + else if (set == 6 ) + { + gMercProfiles[Profile].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_ASKED_BY_HICKS); + } + return 0; +} + +//set chracter ThreatenDefaultResponseUsedRecently +static int l_bThreatenDefaultResponseUsedRecently(lua_State *L) +{ + BOOLEAN set = FALSE; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_toboolean(L,i); + } + + gMercProfiles[Profile].bThreatenDefaultResponseUsedRecently = set; + + return 0; +} + +//set chracter RecruitDefaultResponseUsedRecently +static int l_bRecruitDefaultResponseUsedRecently(lua_State *L) +{ + BOOLEAN set = FALSE; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_toboolean(L,i); + } + + gMercProfiles[Profile].bRecruitDefaultResponseUsedRecently = set; + + return 0; +} + +//set chracter FriendlyOrDirectDefaultResponseUsedRecently +static int l_bFriendlyOrDirectDefaultResponseUsedRecently(lua_State *L) +{ + BOOLEAN set = FALSE; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) set = lua_toboolean(L,i); + } + + gMercProfiles[Profile].bFriendlyOrDirectDefaultResponseUsedRecently = set; + + return 0; +} + +//remove object from chracter inventory slot +static int l_RemoveObjectFromSoldierProfile(lua_State *L) +{ + UINT32 cnt = 0; + UINT8 Profile = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) cnt = lua_tointeger(L,i); + } + + RemoveObjectFromSoldierProfile( Profile, cnt ); + + return 0; +} + +//CheckForMissingHospitalSupplies +static int l_CheckForMissingHospitalSupplies(lua_State *L) +{ + CheckForMissingHospitalSupplies (); + return 0; +} + +//Set money in charcter +static int l_SetMoneyInSoldierProfile(lua_State *L) +{ + UINT8 Profile = 0; + UINT32 Money = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) Profile = lua_tointeger(L,i); + if (i == 2 ) Money = lua_tointeger(L,i); + + } + + SetMoneyInSoldierProfile (Profile, Money); + return 0; +} + +static int l_AddToShouldBecomeHostileOrSayQuoteList(lua_State *L) +{ + UINT8 ubID = 0; + UINT8 n = lua_gettop(L); + int i = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) ubID = lua_tointeger(L,i); + } + + AddToShouldBecomeHostileOrSayQuoteList( ubID ); + return 0; +} + +// set fact = false +static int l_SetFactFalse(lua_State *L) +{ + UINT32 FactFalse = 0; + UINT8 n = lua_gettop(L); + + FactFalse = lua_tointeger(L,n); + + SetFactFalse (FactFalse); + return 0; +} + +//set fact = true +static int l_SetFactTrue(lua_State *L) +{ + UINT32 FactTrue = 0; + UINT8 n = lua_gettop(L); + + FactTrue = lua_tointeger(L,n); + + SetFactTrue (FactTrue); + + return 0; +} + +//Check fact is true or false +static int l_CheckFact (lua_State *L) +{ + UINT32 fcheck = lua_gettop(L); + UINT32 checkfact = 0,fact = 0; + UINT8 ubProfileID = -1; + UINT8 n = lua_gettop(L); + + int i; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) + fact = lua_tointeger(L,i); + if (i == 2 ) + ubProfileID = lua_tointeger(L,i); + } + + if ( ubProfileID != 255 && CheckFact( fact, ubProfileID ) ) + { + checkfact= TRUE; + } + else + { + checkfact = FALSE; + } + + lua_pushboolean(L, checkfact); + + return 1; + +} + +//--------------------------------------- + +BOOLEAN LetHandleLoyaltyChangeForNPCAction(UINT8 ubNPCProfileId , UINT8 Init) +{ + char * filename = "scripts\\StrategicTownLoyalty.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + SGP_THROW(msg); + } + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function +// lua_register(L, "CheckFact", l_CheckFact); +// lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); +// lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleLoyaltyChangeForNPCAction"); + lua_pushnumber(L, ubNPCProfileId ); + + lua_call(L,1,0); + } + + lua_close(L); + + delete[] buffer; + + return true; +} + +BOOLEAN LuaHandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , UINT8 Init) +{ + char * filename = "scripts\\StrategicTownLoyalty.lua"; + UINT32 size, bytesRead; + char* buffer; + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + SGP_THROW(msg); + } + + size = FileSize(filename); + buffer = new char[size+1]; + buffer[size] = 0; + FileRead(file, buffer, size, &bytesRead); + FileClose(file); + + lua_State *L = lua_open(); + luaL_openlibs(L); + + //init function +// lua_register(L, "CheckFact", l_CheckFact); +// lua_register(L, "CheckForMissingHospitalSupplies", l_CheckForMissingHospitalSupplies); +// lua_register(L, "CheckForKingpinsMoneyMissing", l_FunctionCheckForKingpinsMoneyMissing); + IniFunction(L); + IniGlobalGameSetting(L); + + if (luaL_dostring(L, buffer)) + { + // oh noes, error + // TODO: write to log or something + return false; + } + + if ( Init == 0 ) + { + lua_getglobal(L , "HandleGlobalLoyaltyEvent"); + lua_pushnumber(L, ubEventType ); + lua_pushnumber(L, sSectorX ); + lua_pushnumber(L, sSectorY ); + lua_pushnumber(L, bSectorZ ); + + lua_call(L,4,0); + } + + lua_close(L); + + delete[] buffer; + + return true; +} + +//set merc is ready +static int l_Merc_Status (lua_State *L) +{ + UINT8 n = lua_gettop(L); + + UINT8 id = 0; + int i = 0; + UINT32 set = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + if (i == 2 ) set = lua_tointeger(L,i); + } + + if ( set == 0 ) gMercProfiles[ id ].bMercStatus = MERC_OK; + if ( set == -1 ) gMercProfiles[ id ].bMercStatus = MERC_HAS_NO_TEXT_FILE; + if ( set == -2 ) gMercProfiles[ id ].bMercStatus = MERC_ANNOYED_BUT_CAN_STILL_CONTACT; + if ( set == -3 ) gMercProfiles[ id ].bMercStatus = MERC_ANNOYED_WONT_CONTACT; + if ( set == -4 ) gMercProfiles[ id ].bMercStatus = MERC_HIRED_BUT_NOT_ARRIVED_YET; + if ( set == -5 ) gMercProfiles[ id ].bMercStatus = MERC_IS_DEAD; + if ( set == -6 ) gMercProfiles[ id ].bMercStatus = MERC_RETURNING_HOME; + if ( set == -7 ) gMercProfiles[ id ].bMercStatus = MERC_WORKING_ELSEWHERE; + if ( set == -8 ) gMercProfiles[ id ].bMercStatus = MERC_FIRED_AS_A_POW; + + return 0; +} + +static int l_Get_Merc_Status (lua_State *L) +{ + UINT8 n = lua_gettop(L); + + UINT8 id = 0; + int i = 0; + UINT32 set = 0; + + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) id = lua_tointeger(L,i); + } + + if ( gMercProfiles[ id ].bMercStatus == MERC_OK ) set = 0; + if ( gMercProfiles[ id ].bMercStatus == MERC_HAS_NO_TEXT_FILE) set = -1; + if ( gMercProfiles[ id ].bMercStatus == MERC_ANNOYED_BUT_CAN_STILL_CONTACT) set = -2; + if ( gMercProfiles[ id ].bMercStatus == MERC_ANNOYED_WONT_CONTACT)set = -3; + if ( gMercProfiles[ id ].bMercStatus == MERC_HIRED_BUT_NOT_ARRIVED_YET) set = -4; + if ( gMercProfiles[ id ].bMercStatus == MERC_IS_DEAD) set = -5; + if ( gMercProfiles[ id ].bMercStatus == MERC_RETURNING_HOME) set = -6; + if ( gMercProfiles[ id ].bMercStatus == MERC_WORKING_ELSEWHERE) set = -7; + if ( gMercProfiles[ id ].bMercStatus == MERC_FIRED_AS_A_POW) set = -8; + + lua_pushinteger (L, set); + + return 1; +} + +//Check merc is dead +static int l_Merc_Is_Dead (lua_State *L) +{ + UINT8 npcID = lua_gettop(L); + BOOLEAN dead = FALSE; + UINT8 id = 0; + + id = lua_tointeger(L,npcID); + + if ( gMercProfiles[ id ].bMercStatus == MERC_IS_DEAD ) + { + dead = TRUE; + } + else + { + dead = FALSE; + } + + lua_pushboolean (L, dead); + + return 1; +} + +// add town loyalty +static int l_IncrementTownLoyalty(lua_State *L) +{ + UINT32 n = lua_gettop(L); + UINT32 idLoyalty = 0,idTown = 0; + + //for (i= 1; i<=n; i++ ) + //{ + // if (i == 1 ) + idTown = lua_tointeger(L,1); + // if (i == 2 ) + idLoyalty = lua_tointeger(L,2); + //} + + if (idLoyalty >= 1 ) + { + IncrementTownLoyalty( idTown, idLoyalty ); + } + + return 0; +} + +static int l_DecrementTownLoyaltyEverywhere(lua_State *L) +{ + UINT32 n = lua_gettop(L); + UINT32 idLoyalty = 0; + + +// for (i= 1; i<=n; i++ ) + //{ + // if (i == 1 ) + idLoyalty = lua_tointeger(L,1); + //} + + if (idLoyalty >= 1 ) + { + DecrementTownLoyaltyEverywhere( idLoyalty ); + } + + return 0; +} + +// add loyalty +static int l_IncrementTownLoyaltyEverywhere(lua_State *L) +{ + UINT32 n = lua_gettop(L); + UINT32 idLoyalty = 0; + + +// for (i= 1; i<=n; i++ ) + //{ + // if (i == 1 ) + idLoyalty = lua_tointeger(L,1); + //} + + + if (idLoyalty >= 1 ) + { + IncrementTownLoyaltyEverywhere( idLoyalty ); + } + + return 0; +} + +// remove town loyalty +static int l_DecrementTownLoyalty(lua_State *L) +{ + UINT32 n = lua_gettop(L); + UINT32 idLoyalty = 0, idTown = 0; + + + //for (i= 1; i<=n; i++ ) + //{ + // if (i == 1 ) + idTown = lua_tointeger(L,1); + /// if (i == 2 ) + idLoyalty = lua_tointeger(L,2); + //} + + if (idLoyalty >= 1 ) + { + DecrementTownLoyalty( idTown, idLoyalty ); + } + + return 0; +} + +// set town loyalty 0 - 100% +static int l_SetTownLoyalty(lua_State *L) +{ + UINT32 idLoyalty,idTown; + UINT8 n = lua_gettop(L); + int i = 0; + for (i= 1; i<=n; i++ ) + { + if (i == 1 ) idTown = lua_tointeger(L,i); + if (i == 2 ) idLoyalty = lua_tointeger(L,i); + } + + if (idLoyalty >= 1 ) + { + SetTownLoyalty( idTown, idLoyalty ); + } + + return 0; +} +//------------------------------------------------ + +//set Hospital Temp Balance +static int l_HospitalTempBalance(lua_State *L) +{ + UINT32 Balance = 0; + UINT8 n = lua_gettop(L); + + Balance = lua_tointeger(L,n); + + giHospitalTempBalance = Balance; + return 0; +} + +//set PlayerTeamSawJoey +static int l_gfPlayerTeamSawJoey(lua_State *L) +{ + BOOLEAN set = FALSE; + UINT8 n = lua_gettop(L); + + set = lua_toboolean(L,n); + + gfPlayerTeamSawJoey = set; + return 0; +} + +// set +static int l_HospitalRefund(lua_State *L) +{ + UINT32 Balance = 0; + UINT8 n = lua_gettop(L); + + Balance = lua_tointeger(L,n); + + giHospitalRefund = Balance; + return 0; +} + +//set +static int l_HospitalPriceModifier(lua_State *L) +{ + UINT32 Balance = 0; + UINT8 n = lua_gettop(L); + + Balance = lua_tointeger(L,n); + + gbHospitalPriceModifier = Balance; + return 0; +} + +//add character to sector +static int l_AddNPC(lua_State *L) +{ + MERCPROFILESTRUCT * pProfile; + + std::string sector_id = lh_getStringFromTable(L, "sector"); + UINT8 idNPC = 0; + UINT8 x = 0,y = 0,z = 0; + + if (locationStringToCoordinates(sector_id, &x, &y, &z)) + { + idNPC = lh_getIntegerFromTable(L, "MercProfiles"); + + pProfile = &(gMercProfiles[ idNPC ]); + + pProfile->sSectorX = x; + pProfile->sSectorY = y; + pProfile->bSectorZ = z; + } + + return 0; +} + +//add alternate sector +static int l_AddAlternateSector(lua_State *L) +{ + + std::string sector_id = lh_getStringFromTable(L, "altSector"); + + UINT8 x = 0,y = 0; + + if (locationStringToCoordinates_AltSector(sector_id, &x, &y)) + { + SectorInfo[ SECTOR( x, y ) ].uiFlags |= SF_USE_ALTERNATE_MAP; + } + return 0; +} + +//add alternate under ground sector +static int l_AddAltUnderGroundSector(lua_State *L) +{ + std::string sector_id = lh_getStringFromTable(L, "altSector"); + + UINT8 x = 0,y = 0,z = 0; + + if (locationStringToCoordinates(sector_id, &x, &y, &z)) + { + UNDERGROUND_SECTORINFO *pSector; + pSector = FindUnderGroundSector( x, y, z ); + if( pSector ) + { + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + } + } + + return 0; +} + +static int lh_getBooleanFromTable(lua_State *L, const char * fieldname) +{ + lua_getfield(L, -1, fieldname); + int i = lua_toboolean(L, -1); + lua_pop(L, 1); + return i; +} + +static int lh_getIntegerFromTable(lua_State *L, const char * fieldname) +{ + lua_getfield(L, -1, fieldname); + int i = lua_tointeger(L, -1); + lua_pop(L, 1); + return i; +} + +static std::string lh_getStringFromTable(lua_State *L, const char * fieldname) +{ + lua_getfield(L, -1, fieldname); + string s = lua_tostring(L, -1); + lua_pop(L, 1); + return s; +} + +static bool locationStringToCoordinates_AltSector(std::string loc, UINT8* x, UINT8* y) +{ + int length = loc.length(); + + // gather row + if (length < 2 || length > 3) + return false; + + char row = loc[0]; + if (row >= 'A' && row <= 'P') + { + *y = row - 'A' + 1; + } + else if (row >= 'a' && row <= 'p') + { + *y = row - 'a' + 1; + } + else + { + return false; + } + + // gather column +#if 0 + loc = loc.substr(1); + stringstream ss = stringstream(); + if (loc[0] >= '0' && loc[0] <= '9') + { + ss << loc[0]; + loc = loc.substr(1); + } + if (loc[0] >= '0' && loc[0] <= '9') + { + ss << loc[0]; + loc = loc.substr(1); + } +#else + stringstream ss(loc.substr(1)); +#endif + int col = 0; + ss >> col; + if (col >= 1 && col <= 16) + { + *x = col; + } + else + { + return false; + } + + return true; +} + +// extract x,y,z from strings like "D13-1" +static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z) +{ + int length = loc.length(); + + // gather row + if (length < 4 || length > 5) + return false; + + char row = loc[0]; + if (row >= 'A' && row <= 'P') + { + *y = row - 'A' + 1; + } + else if (row >= 'a' && row <= 'p') + { + *y = row - 'a' + 1; + } + else + { + return false; + } + + // gather column +#if 0 + loc = loc.substr(1); + stringstream ss = stringstream(); + if (loc[0] >= '0' && loc[0] <= '9') + { + ss << loc[0]; + loc = loc.substr(1); + } + if (loc[0] >= '0' && loc[0] <= '9') + { + ss << loc[0]; + loc = loc.substr(1); + } +#else + stringstream ss(loc); +#endif + int col = 0; + ss >> col; + if (col >= 1 && col <= 16) + { + *x = col; + } + else + { + return false; + } + + // gather level + char lvl = loc[loc.length() - 1]; + if (lvl >= '0' && lvl <= '3') + { + *z = lvl - '0'; + } + else + { + return false; + } + return true; +} + + + +static int l_gTacticalStatus(lua_State *L) +{ + + return 0; +} + + +//-------------------------------------------------------------- + + +BOOLEAN SaveLuaGlobalToSaveGameFile( HWFILE hFile ) +{ + UINT32 uiNumBytesWritten; + + FileWrite( hFile, &gLuaGlobal, sizeof( gLuaGlobal), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gLuaGlobal ) ) + { + return( FALSE ); + } + + return( TRUE ); +} + +BOOLEAN LoadLuaGlobalFromLoadGameFile( HWFILE hFile ) +{ + UINT32 uiNumBytesRead; + + FileRead( hFile, &gLuaGlobal, sizeof( gLuaGlobal ), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gLuaGlobal ) ) + { + return( FALSE ); + } + + return( TRUE ); +} +//-------------------------------------------------------------- \ No newline at end of file diff --git a/Strategic/LuaInitNPCs.h b/Strategic/LuaInitNPCs.h new file mode 100644 index 00000000..e7fe5333 --- /dev/null +++ b/Strategic/LuaInitNPCs.h @@ -0,0 +1,75 @@ +#ifndef _LUAINITNPCS_H +#define _LUAINITNPCS_H + +#include "Types.h" + +typedef struct +{ + BOOLEAN fGlobalLuaBool; + UINT32 iGlobalLuaVal; +} LUA_GLOBAL; + +extern LUA_GLOBAL gLuaGlobal[1000]; + + +#define MAX_ACTION_NAMES_CHARS 30 + +typedef struct +{ + UINT16 uiIndex; + UINT8 ActionID; + UINT32 BombItem; + CHAR16 szName[MAX_ACTION_NAMES_CHARS]; + UINT8 BlowUp; + +} ACTION_ITEM_VALUES; + +extern ACTION_ITEM_VALUES ActionItemsValues[500]; + +extern UINT32 uiHourLua; +extern UINT32 uiDayLua; +extern UINT32 uiMinLua; +extern UINT16 PROFILLUA_sSectorX; +extern UINT16 PROFILLUA_sSectorY; +extern UINT8 PROFILLUA_bSectorZ; +extern UINT8 PROFILLUA_Level; +extern UINT8 PROFILLUA_ubID; +extern UINT32 PROFILLUA_sGridNo; +extern UINT8 PROFILLUA_ubDirectiono; +extern UINT8 PROFILLUA_bTeam; + +extern UINT8 PROFILLUA2_ubProfile; +extern UINT16 PROFILLUA2_sSectorX; +extern UINT16 PROFILLUA2_sSectorY; +extern UINT8 PROFILLUA2_bSectorZ; +extern UINT8 PROFILLUA2_ubID; +extern UINT32 PROFILLUA2_sGridNo; + +extern BOOLEAN LetHandleLoyaltyChangeForNPCAction(UINT8 ubNPCProfileId , UINT8 Init); +extern BOOLEAN LuaHandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , UINT8 Init); +extern BOOLEAN LetLuaHandleEarlyMorningEvents(UINT8 Init); +extern BOOLEAN LetLuaHourlyQuestUpdate(UINT8 Init); +extern BOOLEAN LetLuaMyCustomHandleAtNewGridNo(UINT8 bNewSide, UINT8 ProfileId, UINT8 Init); +extern BOOLEAN LetLuaPerformItemAction(UINT32 Action, INT32 sGridNo, UINT8 InitFunction); +extern BOOLEAN LetLuaGameInit(UINT8 Init); +extern BOOLEAN LetLuaInterfaceDialogue( UINT8 ubNPC, UINT8 InitFunction); +extern BOOLEAN LuaHandlePlayerTeamMemberDeath(UINT8 ProfileId, UINT8 Init); +extern BOOLEAN LuaHandleNPCTeamMemberDeath(UINT8 ProfileId, UINT8 Init); +extern BOOLEAN LuaCheckForKingpinsMoneyMissing( BOOLEAN fFirstCheck, UINT8 Init); +extern BOOLEAN LuaHandleQuestCodeOnSectorExit( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init); +extern BOOLEAN LuaHandleQuestCodeOnSectorEntry( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 Init); +extern BOOLEAN LuaHandleDelayedItemsArrival( UINT32 uiReason, UINT8 Init); +extern BOOLEAN LetLuaHandleNPCSystemEvent( UINT32 uiEvent, UINT8 Init); + +extern BOOLEAN LuaCheckFact ( UINT16 usFact, UINT8 ubProfileID , UINT32 Init); +extern BOOLEAN LuaHandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum , UINT8 InitFunction); + +extern void IniLuaGlobal(); + +extern BOOLEAN LoadLuaGlobalFromLoadGameFile( HWFILE hFile ); +extern BOOLEAN SaveLuaGlobalToSaveGameFile( HWFILE hFile ); + +//Intro +extern BOOLEAN LuaIntro(UINT8 Init, UINT32 uiCurrentVideo, INT8 bIntroType, UINT32 iStringToUse); + +#endif diff --git a/Strategic/Luaglobal.cpp b/Strategic/Luaglobal.cpp new file mode 100644 index 00000000..d3bc205e --- /dev/null +++ b/Strategic/Luaglobal.cpp @@ -0,0 +1,200 @@ +#include +#include +#include + + +#include "connect.h" +#include "FileMan.h" +#include "GameSettings.h" +#include "Game Init.h" +#include "interface Dialogue.h" +#include "opplist.h" +#include "Strategic All.h" +#include "Luaglobal.h" +#include "Boxing.h" +#include "LuaInitNPCs.h" +#include "Game Clock.h" +#include "Overhead.h" +#include "Music Control.h" + +#include "Intro.h" +#include "End Game.h" +#include "Queen Command.h" +#include "gamescreen.h" +#include "Map Screen Interface Map.h" + +#include "Creature Spreading.h" +#include "World Items.h" +#include "Map Screen Helicopter.h" +#include "Campaign Types.h" + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +} + +using namespace std; + +extern BOOLEAN gfDoneWithSplashScreen; + + +void IniGlobalGameSetting(lua_State *L) +{ + // ------------------------------- + // Start new game settings (use "new" prefix) + // ------------------------------- + + lua_pushinteger(L, gGameOptions.ubGameStyle); + lua_setglobal(L, "newGAME_STYLE"); + + lua_pushinteger(L, gGameOptions.ubDifficultyLevel); + lua_setglobal(L, "newDIFFICULTY_LEVEL"); + + // ------------------------------- + // ja2_options.ini Settings (use "ini" prefix) + // ------------------------------- + + lua_pushinteger(L, gGameExternalOptions.fEnableCrepitus); + lua_setglobal(L, "iniENABLE_CREPITUS"); + + // WANNE: Currently not used + lua_pushboolean(L, gGameExternalOptions.gfInvestigateSector); + lua_setglobal(L, "iniENEMY_INVESTIGATE_SECTOR"); + + lua_pushboolean(L, gGameExternalOptions.fMercDayOne); + lua_setglobal(L, "iniMERC_WEBSITE_IMMEDIATELY_AVAILABLE"); + + lua_pushinteger(L, gGameExternalOptions.ubChanceTonyAvailable); + lua_setglobal(L, "iniCHANCE_TONY_AVAILABLE"); + + lua_pushinteger(L, gGameExternalOptions.iStartingCashNovice); + lua_setglobal(L, "iniSTARTING_CASH_NOVICE"); + + lua_pushinteger(L, gGameExternalOptions.iStartingCashExperienced); + lua_setglobal(L, "iniSTARTING_CASH_EXPERIENCED"); + + lua_pushinteger(L, gGameExternalOptions.iStartingCashExpert); + lua_setglobal(L, "iniSTARTING_CASH_EXPERT"); + + lua_pushinteger(L, gGameExternalOptions.iStartingCashInsane); + lua_setglobal(L, "iniSTARTING_CASH_INSANE"); + + // WANNE: Currently not used + lua_pushinteger(L, gGameExternalOptions.fCanTrueCiviliansBecomeHostile); + lua_setglobal(L, "iniCAN_TRUE_CIVILIANS_BECOME_HOSTILE"); + + // ------------------------------- + // Other global variables + // ------------------------------- + + lua_pushinteger(L, gGameExternalOptions.ubDefaultArrivalSectorY); + lua_setglobal(L, "ubDefaultArrivalSectorY"); + + lua_pushinteger(L, gGameExternalOptions.ubDefaultArrivalSectorX); + lua_setglobal(L, "ubDefaultArrivalSectorX"); + + lua_pushinteger(L, gGameExternalOptions.iFirstArrivalDelay); + lua_setglobal(L, "iFirstArrivalDelay"); + + lua_pushinteger(L, guiHelicopterSkyriderTalkState); + lua_setglobal(L, "guiHelicopterSkyriderTalkState"); + + lua_pushinteger(L, guiTimeOfLastSkyriderMonologue); + lua_setglobal(L, "guiTimeOfLastSkyriderMonologue"); + + lua_pushinteger(L, gubBloodcatLairSectorId); + lua_setglobal(L, "gubBloodcatLairSectorId"); + + lua_pushinteger(L, gubSrcSoldierProfile); + lua_setglobal(L, "gubSrcSoldierProfile"); + + lua_pushinteger(L, giLairID); + lua_setglobal(L, "giLairID"); + + lua_pushinteger(L, is_networked); + lua_setglobal(L, "is_networked"); + + lua_pushinteger(L, gWorldSectorX); + lua_setglobal(L, "gWorldSectorX"); + + lua_pushinteger(L, gWorldSectorY); + lua_setglobal(L, "gWorldSectorY"); + + lua_pushinteger(L, gbWorldSectorZ); + lua_setglobal(L, "gWorldSectorZ"); + + lua_pushinteger(L, gbWorldSectorZ); + lua_setglobal(L, "gbWorldSectorZ"); + + lua_pushinteger(L, giHospitalTempBalance); + lua_setglobal(L, "giHospitalTempBalance"); + + lua_pushinteger(L, gbHospitalPriceModifier); + lua_setglobal(L, "gbHospitalPriceModifier"); + + lua_pushinteger(L, giHospitalRefund); + lua_setglobal(L, "giHospitalRefund"); + + lua_pushboolean(L, gfBoxersResting); + lua_setglobal(L, "gfBoxersResting"); + + lua_pushinteger(L, gubBoxersRests); + lua_setglobal(L, "gubBoxersRests"); + + lua_pushinteger(L, gubBoxingMatchesWon); + lua_setglobal(L, "gubBoxingMatchesWon"); + + lua_pushinteger(L, uiHourLua); + lua_setglobal(L, "cHour"); + + lua_pushinteger(L, uiDayLua); + lua_setglobal(L, "cDay"); + + lua_pushinteger(L, uiMinLua); + lua_setglobal(L, "cMin"); + + lua_pushinteger(L, gbPlayerNum); + lua_setglobal(L, "gbPlayerNum"); + + lua_pushinteger(L, GetMusicHandle()); + lua_setglobal(L, "uiMusicHandle"); + + lua_pushinteger(L, GetMusicMode()); + lua_setglobal(L, "gubMusicMode"); + + lua_pushboolean(L, IsMusicPlaying()); + lua_setglobal(L, "fMusicPlaying"); + + // unused + //lua_pushboolean(L, gfForceMusicToTense); + //lua_setglobal(L, "gfForceMusicToTense"); + + // WANNE: Currently not used + lua_pushinteger(L, guiNumWorldItems); + lua_setglobal(L, "guiNumWorldItems"); + + lua_pushboolean(L, gfEnteringMapScreen); + lua_setglobal(L, "gfEnteringMapScreen"); + + lua_pushboolean(L, guiIntroExitScreen); + lua_setglobal(L, "guiIntroExitScreen"); + + lua_pushboolean(L, gfIntroScreenExit); + lua_setglobal(L, "gfIntroScreenExit"); + + lua_pushinteger(L, sSelMapX); + lua_setglobal(L, "sSelMapX"); + + lua_pushinteger(L, sSelMapY); + lua_setglobal(L, "sSelMapY"); + + lua_pushinteger(L, iCurrentMapSectorZ); + lua_setglobal(L, "iCurrentMapSectorZ"); + + lua_pushboolean(L, gfDoneWithSplashScreen); + lua_setglobal(L, "gfDoneWithSplashScreen"); + + lua_pushinteger(L, gbIntroScreenMode); + lua_setglobal(L, "gbIntroScreenMode"); +} \ No newline at end of file diff --git a/Strategic/Luaglobal.h b/Strategic/Luaglobal.h new file mode 100644 index 00000000..3cde6a89 --- /dev/null +++ b/Strategic/Luaglobal.h @@ -0,0 +1,23 @@ +#ifndef _LUAGLOBAL_H +#define _LUAGLOBAL_H + +#include "Types.h" + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +} + +// -------------------------- +// WANNE: Should we enable lua scripting for different actions, or should we use "hardcoded" stuff instead? +#define LUA_INTRO // Intro.lua +#define LUA_HOURLY_QUEST_UPDATE // HourlyUpdate.lua +#define LUA_STRATEGY_EVENT_HANDLER // StrategicEventHandler.lua +#define LUA_STRATEGY_TOWN_LOYALTY // StrategicTownLoyalty.lua +#define LUA_OVERHEAD // Overhead.lua +// -------------------------- + +void IniGlobalGameSetting(lua_State *L); + +#endif diff --git a/Strategic/Map Screen Helicopter.cpp b/Strategic/Map Screen Helicopter.cpp index 6c5e43dc..f3dc8dfb 100644 --- a/Strategic/Map Screen Helicopter.cpp +++ b/Strategic/Map Screen Helicopter.cpp @@ -72,7 +72,7 @@ extern UINT8 ubSAMControlledSectors[ MAP_WORLD_Y ][ MAP_WORLD_X ]; extern INT32 iSeatingCapacities[]; // the static NPC dialogue faces -extern UINT32 uiExternalStaticNPCFaces[]; +//extern UINT32 uiExternalStaticNPCFaces[]; // the squad mvt groups extern INT8 SquadMovementGroups[ ]; @@ -376,10 +376,15 @@ BOOLEAN HandleHeliEnteringSector( INT16 sX, INT16 sY ) else { // Say quote: "Gonna have to abort. Enemies below" - if(gGameSettings.fOptions[ TOPTION_SILENT_SKYRIDER ] == FALSE) + //CHRISL: Whether skyrider is set to silent or not, we should still say this if we aren't allowing landing in a hot lz. + //if(gGameSettings.fOptions[ TOPTION_SILENT_SKYRIDER ] == FALSE) + if(gGameExternalOptions.ubSkyriderHotLZ == 0) HeliCharacterDialogue( pSkyRider, ARRIVED_IN_HOSTILE_SECTOR ); + else + HeliCharacterDialogue( pSkyRider, HELI_HOT_DROP ); - //StopTimeCompression(); + PaySkyriderBill(); + StopTimeCompression(); } if( CheckForArrivalAtRefuelPoint( ) ) @@ -2230,6 +2235,7 @@ void PaySkyriderBill( void) ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pSkyriderText[ 1 ], -gMercProfiles[ SKYRIDER ].iBalance ); // kick everyone out! (we know we're in a safe sector if we're paying) + //CHRISL: This may no longer be the case but I'm not sure of a better way to handle things. MoveAllInHelicopterToFootMovementGroup( ); MakeHeliReturnToBase(); diff --git a/Strategic/Map Screen Helicopter.h b/Strategic/Map Screen Helicopter.h index 4c34ed51..834e6dce 100644 --- a/Strategic/Map Screen Helicopter.h +++ b/Strategic/Map Screen Helicopter.h @@ -40,6 +40,8 @@ #define HELI_TOOK_MINOR_DAMAGE 52 #define HELI_TOOK_MAJOR_DAMAGE 53 #define HELI_GOING_DOWN 54 +#define HELI_PATH_THROUGH_ENEMEY_AIRSPACE 55 +#define HELI_HOT_DROP 56 // enums for skyrider monologue diff --git a/Strategic/Map Screen Interface Border.cpp b/Strategic/Map Screen Interface Border.cpp index ef13809f..50d87ec6 100644 --- a/Strategic/Map Screen Interface Border.cpp +++ b/Strategic/Map Screen Interface Border.cpp @@ -23,6 +23,12 @@ #include "Strategic Town Loyalty.h" #include "strategicmap.h" #include "Assignments.h" + // HEADROCK HAM 4: Now accepts INI settings + #include "GameSettings.h" + // Also include Town Militia for checks regarding Mobile Militia Restrictions + #include "Town Militia.h" + // Also include Quests, for checking whether a fact is true. + #include "Quests.h" #endif @@ -32,6 +38,27 @@ //#define MAP_BORDER_CORNER_X 584 //#define MAP_BORDER_CORNER_Y 279 +// HEADROCK HAM 4: Now defining X/Y coordinates for Map Bottom buttons. Some day perhaps variable coordinates? +UINT16 MAP_BORDER_TOWN_BTN_X; +UINT16 MAP_BORDER_TOWN_BTN_Y; +UINT16 MAP_BORDER_MINE_BTN_X; +UINT16 MAP_BORDER_MINE_BTN_Y; +UINT16 MAP_BORDER_TEAMS_BTN_X; +UINT16 MAP_BORDER_TEAMS_BTN_Y; +UINT16 MAP_BORDER_AIRSPACE_BTN_X; +UINT16 MAP_BORDER_AIRSPACE_BTN_Y; +UINT16 MAP_BORDER_ITEM_BTN_X; +UINT16 MAP_BORDER_ITEM_BTN_Y; +UINT16 MAP_BORDER_MILITIA_BTN_X; +UINT16 MAP_BORDER_MILITIA_BTN_Y; +UINT16 MAP_BORDER_MOBILE_BTN_X; +UINT16 MAP_BORDER_MOBILE_BTN_Y; + +UINT16 MAP_LEVEL_MARKER_X; +UINT16 MAP_LEVEL_MARKER_Y; +UINT16 MAP_LEVEL_MARKER_DELTA; +UINT16 MAP_LEVEL_MARKER_WIDTH; + // extern to anchored button in winbart97 extern GUI_BUTTON *gpAnchoredButton; extern BOOLEAN gfAnchoredState; @@ -54,6 +81,7 @@ BOOLEAN fShowTeamFlag = FALSE; BOOLEAN fShowMilitia = FALSE; BOOLEAN fShowAircraftFlag = FALSE; BOOLEAN fShowItemsFlag = FALSE; +BOOLEAN fShowMobileRestrictionsFlag = FALSE; // HEADROCK HAM 4 BOOLEAN fZoomFlag = FALSE; //BOOLEAN fShowVehicleFlag = FALSE; @@ -64,8 +92,9 @@ BOOLEAN fZoomFlag = FALSE; // buttons & button images -INT32 giMapBorderButtons[ 6 ] = { -1, -1, -1, -1, -1, -1 }; -INT32 giMapBorderButtonsImage[ 6 ] = { -1, -1, -1, -1, -1, -1 }; +// HEADROCK HAM 4: Increase both arrays by one to accomodate new Mobile Restrictions button +INT32 giMapBorderButtons[ 7 ] = { -1, -1, -1, -1, -1, -1, -1 }; +INT32 giMapBorderButtonsImage[ 7 ] = { -1, -1, -1, -1, -1, -1, -1 }; //UINT32 guiMapBorderScrollButtons[ 4 ] = { -1, -1, -1, -1 }; //UINT32 guiMapBorderScrollButtonsImage[ 4 ]; @@ -101,6 +130,8 @@ void BtnItemCallback(GUI_BUTTON *btn,INT32 reason); void BtnAircraftCallback(GUI_BUTTON *btn,INT32 reason); void BtnTeamCallback(GUI_BUTTON *btn,INT32 reason); void BtnMilitiaCallback(GUI_BUTTON *btn,INT32 reason); +// HEADROCK HAM 4: Mobile Restrictions Button callback +void BtnMobileCallback(GUI_BUTTON *btn,INT32 reason); //void BtnZoomCallback(GUI_BUTTON *btn,INT32 reason); void BtnGenericMouseMoveButtonCallbackForMapBorder(GUI_BUTTON *btn,INT32 reason); @@ -215,7 +246,15 @@ void RenderMapBorder( void ) // get and blt border GetVideoObject(&hHandle, guiMapBorder ); - BltVideoObject( guiSAVEBUFFER , hHandle, 0, MAP_BORDER_X, MAP_BORDER_Y, VO_BLT_SRCTRANSPARENCY,NULL ); + // HEADROCK HAM 4: Load different map border depending on whether we want to display the mobile militia button or not. + if (gGameExternalOptions.gfAllowMilitiaGroups) + { + BltVideoObject( guiSAVEBUFFER , hHandle, 1, MAP_BORDER_X, MAP_BORDER_Y, VO_BLT_SRCTRANSPARENCY,NULL ); + } + else + { + BltVideoObject( guiSAVEBUFFER , hHandle, 0, MAP_BORDER_X, MAP_BORDER_Y, VO_BLT_SRCTRANSPARENCY,NULL ); + } if (iResolution == 1 || iResolution == 2) { @@ -301,6 +340,8 @@ BOOLEAN CreateButtonsForMapBorder( void ) { // will create the buttons needed for the map screen border region + // HEADROCK HAM 4: Call to initiate coordinates for all buttons. + InitMapBorderButtonCoordinates(); /* // up button guiMapBorderScrollButtonsImage[ ZOOM_MAP_SCROLL_UP ] = LoadButtonImage( "INTERFACE\\map_screen_bottom_arrows.sti" ,11,4,-1,6,-1 ); @@ -333,43 +374,56 @@ BOOLEAN CreateButtonsForMapBorder( void ) SetButtonFastHelpText( guiMapBorderScrollButtons[ 3 ], pMapScreenBorderButtonHelpText[ 9 ] ); */ + // HEADROCK HAM 4: Button X/Y coordinates are now INIT'ed separately. + // towns giMapBorderButtonsImage[ MAP_BORDER_TOWN_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,5,-1,14,-1 ); - giMapBorderButtons[ MAP_BORDER_TOWN_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_TOWN_BTN ], MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 152), (SCREEN_HEIGHT - 160), + giMapBorderButtons[ MAP_BORDER_TOWN_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_TOWN_BTN ], MAP_BORDER_TOWN_BTN_X, MAP_BORDER_TOWN_BTN_Y, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnTownCallback); // mines giMapBorderButtonsImage[ MAP_BORDER_MINE_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,4,-1,13,-1 ); - giMapBorderButtons[ MAP_BORDER_MINE_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_MINE_BTN ], MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 109), (SCREEN_HEIGHT - 160), + giMapBorderButtons[ MAP_BORDER_MINE_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_MINE_BTN ], MAP_BORDER_MINE_BTN_X, MAP_BORDER_MINE_BTN_Y, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnMineCallback); // people giMapBorderButtonsImage[ MAP_BORDER_TEAMS_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,3,-1,12,-1 ); - giMapBorderButtons[ MAP_BORDER_TEAMS_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_TEAMS_BTN ], MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 66), (SCREEN_HEIGHT - 160), + giMapBorderButtons[ MAP_BORDER_TEAMS_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_TEAMS_BTN ], MAP_BORDER_TEAMS_BTN_X, MAP_BORDER_TEAMS_BTN_Y, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnTeamCallback); // militia giMapBorderButtonsImage[ MAP_BORDER_MILITIA_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,8,-1,17,-1 ); - giMapBorderButtons[ MAP_BORDER_MILITIA_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_MILITIA_BTN ], MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 23), (SCREEN_HEIGHT - 160), + giMapBorderButtons[ MAP_BORDER_MILITIA_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_MILITIA_BTN ], MAP_BORDER_MILITIA_BTN_X, MAP_BORDER_MILITIA_BTN_Y, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnMilitiaCallback); // airspace giMapBorderButtonsImage[ MAP_BORDER_AIRSPACE_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,2,-1,11,-1 ); - giMapBorderButtons[ MAP_BORDER_AIRSPACE_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_AIRSPACE_BTN ], MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 20), (SCREEN_HEIGHT - 160), + giMapBorderButtons[ MAP_BORDER_AIRSPACE_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_AIRSPACE_BTN ], MAP_BORDER_AIRSPACE_BTN_X, MAP_BORDER_AIRSPACE_BTN_Y, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnAircraftCallback); // items giMapBorderButtonsImage[ MAP_BORDER_ITEM_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,1,-1,10,-1 ); - giMapBorderButtons[ MAP_BORDER_ITEM_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_ITEM_BTN ], MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 63), (SCREEN_HEIGHT - 160), + giMapBorderButtons[ MAP_BORDER_ITEM_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_ITEM_BTN ], MAP_BORDER_ITEM_BTN_X, MAP_BORDER_ITEM_BTN_Y, BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnItemCallback); + // WANNE: Only display the buton when mobile militia is allowed! + // HEADROCK HAM 4: Mobile Restrictions Button + if (gGameExternalOptions.gfAllowMilitiaGroups) + { + giMapBorderButtonsImage[ MAP_BORDER_MOBILE_BTN ] = LoadButtonImage( "INTERFACE\\map_border_buttons.sti" ,-1,20,-1,21,-1 ); + giMapBorderButtons[ MAP_BORDER_MOBILE_BTN ] = QuickCreateButton( giMapBorderButtonsImage[ MAP_BORDER_MOBILE_BTN ], MAP_BORDER_MOBILE_BTN_X, MAP_BORDER_MOBILE_BTN_Y, + BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGH, + (GUI_CALLBACK)MSYS_NO_CALLBACK, (GUI_CALLBACK)BtnMobileCallback); + } + + // raise and lower view level @@ -395,6 +449,9 @@ BOOLEAN CreateButtonsForMapBorder( void ) SetButtonFastHelpText( giMapBorderButtons[ 4 ], pMapScreenBorderButtonHelpText[ 4 ] ); SetButtonFastHelpText( giMapBorderButtons[ 5 ], pMapScreenBorderButtonHelpText[ 5 ] ); + if (gGameExternalOptions.gfAllowMilitiaGroups) + SetButtonFastHelpText( giMapBorderButtons[ 6 ], pMapScreenBorderButtonHelpText[ 6 ] ); // HEADROCK HAM 4: Mobile Militia button + //SetButtonFastHelpText( guiMapBorderLandRaiseButtons[ 0 ], pMapScreenBorderButtonHelpText[ 10 ] ); //SetButtonFastHelpText( guiMapBorderLandRaiseButtons[ 1 ], pMapScreenBorderButtonHelpText[ 11 ] ); @@ -405,6 +462,9 @@ BOOLEAN CreateButtonsForMapBorder( void ) SetButtonCursor(giMapBorderButtons[ 4 ], MSYS_NO_CURSOR ); SetButtonCursor(giMapBorderButtons[ 5 ], MSYS_NO_CURSOR ); + if (gGameExternalOptions.gfAllowMilitiaGroups) + SetButtonCursor(giMapBorderButtons[ 6 ], MSYS_NO_CURSOR ); // HEADROCK HAM 4: Mobile Militia button + // SetButtonCursor(guiMapBorderLandRaiseButtons[ 0 ], MSYS_NO_CURSOR ); // SetButtonCursor(guiMapBorderLandRaiseButtons[ 1 ], MSYS_NO_CURSOR ); @@ -432,6 +492,10 @@ void DeleteMapBorderButtons( void ) RemoveButton( giMapBorderButtons[ 4 ]); RemoveButton( giMapBorderButtons[ 5 ]); + // WANNE: Only remove if we added the button + if (gGameExternalOptions.gfAllowMilitiaGroups) + RemoveButton( giMapBorderButtons[ 6 ]); // HEADROCK HAM 4 + //RemoveButton( guiMapBorderLandRaiseButtons[ 0 ]); //RemoveButton( guiMapBorderLandRaiseButtons[ 1 ]); @@ -451,11 +515,17 @@ void DeleteMapBorderButtons( void ) UnloadButtonImage( giMapBorderButtonsImage[ 4 ] ); UnloadButtonImage( giMapBorderButtonsImage[ 5 ] ); + // WANNE: Only unload if we added the button + if (gGameExternalOptions.gfAllowMilitiaGroups) + UnloadButtonImage( giMapBorderButtonsImage[ 6 ] ); // HEADROCK HAM 4 + + //UnloadButtonImage( guiMapBorderLandRaiseButtonsImage[ 0 ] ); //UnloadButtonImage( guiMapBorderLandRaiseButtonsImage[ 1 ] ); - for ( ubCnt = 0; ubCnt < 6; ubCnt++ ) + // HEADROCK HAM 4: Increased number of buttons by one. + for ( ubCnt = 0; ubCnt < NUM_MAP_BORDER_BTNS; ubCnt++ ) { giMapBorderButtons[ ubCnt ] = -1; giMapBorderButtonsImage[ ubCnt ] = -1; @@ -608,6 +678,21 @@ void BtnItemCallback(GUI_BUTTON *btn,INT32 reason) } } +// HEADROCK HAM 4: Callback for Mobile Restrictions Button +void BtnMobileCallback(GUI_BUTTON *btn,INT32 reason) +{ + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + CommonBtnCallbackBtnDownChecks(); + + ToggleMobileFilter(); + } + else if(reason & MSYS_CALLBACK_REASON_RBUTTON_DWN ) + { + CommonBtnCallbackBtnDownChecks(); + } +} + /* void BtnZoomCallback(GUI_BUTTON *btn,INT32 reason) @@ -723,6 +808,12 @@ void ToggleShowMinesMode( void ) fShowItemsFlag = FALSE; MapBorderButtonOff( MAP_BORDER_ITEM_BTN ); } + // HEADROCK HAM 4: Mobile Militia Restrictions + if( fShowMobileRestrictionsFlag == TRUE ) + { + fShowMobileRestrictionsFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_MOBILE_BTN ); + } } fMapPanelDirty = TRUE; @@ -859,6 +950,26 @@ void ToggleItemsFilter( void ) } } +// HEADROCK HAM 4: Toggle Mobile Restrictions Button +void ToggleMobileFilter( void ) +{ + if( fShowMobileRestrictionsFlag == TRUE ) + { + // turn items OFF + fShowMobileRestrictionsFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_MOBILE_BTN ); + + // dirty regions + fMapPanelDirty = TRUE; + fTeamPanelDirty = TRUE; + fCharacterInfoPanelDirty = TRUE; + } + else + { + // turn items ON + TurnOnMobileFilterMode(); + } +} /* void ShowDestinationOfPlottedPath( STR16 pLoc ) @@ -1279,6 +1390,12 @@ void TurnOnShowTeamsMode( void ) fShowMilitia = FALSE; MapBorderButtonOff( MAP_BORDER_MILITIA_BTN ); } + // HEADROCK HAM 4: Turn off Show Militia Restrictions + if (fShowMobileRestrictionsFlag == TRUE) + { + fShowMobileRestrictionsFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_MOBILE_BTN ); + } /* if( fShowAircraftFlag == TRUE ) @@ -1340,6 +1457,12 @@ void TurnOnAirSpaceMode( void ) MapBorderButtonOff( MAP_BORDER_MILITIA_BTN ); } */ + // HEADROCK HAM 4: Turn off Militia Restrictions + if (fShowMobileRestrictionsFlag == TRUE) + { + fShowMobileRestrictionsFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_MOBILE_BTN ); + } // Turn off items if( fShowItemsFlag == TRUE ) @@ -1403,6 +1526,12 @@ void TurnOnItemFilterMode( void ) fShowMilitia = FALSE; MapBorderButtonOff( MAP_BORDER_MILITIA_BTN ); } + // HEADROCK HAM 4: Turn off Militia Restrictions + if (fShowMobileRestrictionsFlag == TRUE) + { + fShowMobileRestrictionsFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_MOBILE_BTN ); + } if( fShowAircraftFlag == TRUE ) { @@ -1422,6 +1551,77 @@ void TurnOnItemFilterMode( void ) } } +// HEADROCK HAM 4: Activate "View Mobile Restrictions" mode. +void TurnOnMobileFilterMode( void ) +{ + // if mode already on, leave, else set and redraw + + if( fShowMobileRestrictionsFlag == FALSE ) + { + fShowMobileRestrictionsFlag = TRUE; + MapBorderButtonOn( MAP_BORDER_MOBILE_BTN ); + // Also turn on Militia mode + fShowMilitia = FALSE; // Fool the function so that it always turns militia ON. + ToggleShowMilitiaMode(); + + + if( fShowMineFlag == TRUE ) + { + fShowMineFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_MINE_BTN ); + } + + if( fShowTeamFlag == TRUE ) + { + fShowTeamFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_TEAMS_BTN ); + } + + if( fShowAircraftFlag == TRUE ) + { + fShowAircraftFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_AIRSPACE_BTN ); + } + + // Turn off items + if( fShowItemsFlag == TRUE ) + { + fShowItemsFlag = FALSE; + MapBorderButtonOff( MAP_BORDER_ITEM_BTN ); + } + + if( ( bSelectedDestChar != -1 ) || ( fPlotForHelicopter == TRUE ) ) + { + AbortMovementPlottingMode( ); + } + + STR16 pwString = NULL; + + // check if player has any Mobile militia + if ( DoesPlayerHaveAnyMobileMilitia( ) == 1 ) + { + // say you need to train mobiles first + pwString = zMarksMapScreenText[ 25 ]; + + MapScreenMessage( FONT_MCOLOR_LTYELLOW, MSG_MAP_UI_POSITION_MIDDLE, pwString ); + } + + if ( !gubFact[ FACT_MOBILE_RESTRICTIONS_VIEWED ] ) + { + // say you need to train mobiles first + pwString = zMarksMapScreenText[ 26 ]; + + MapScreenMessage( FONT_MCOLOR_LTYELLOW, MSG_MAP_UI_POSITION_MIDDLE, pwString ); + + SetFactTrue( FACT_MOBILE_RESTRICTIONS_VIEWED ); + } + + // dirty regions + fMapPanelDirty = TRUE; + fTeamPanelDirty = TRUE; + fCharacterInfoPanelDirty = TRUE; + } +} /* void UpdateLevelButtonStates( void ) @@ -1536,6 +1736,15 @@ void InitializeMapBorderButtonStates( void ) { MapBorderButtonOff( MAP_BORDER_MILITIA_BTN ); } + + if( fShowMobileRestrictionsFlag ) + { + MapBorderButtonOn( MAP_BORDER_MOBILE_BTN ); + } + else + { + MapBorderButtonOff( MAP_BORDER_MOBILE_BTN ); + } } @@ -1562,6 +1771,39 @@ BOOLEAN DoesPlayerHaveAnyMilitia( void ) return( FALSE ); } +// HEADROCK HAM 4: Check for Mobile Militia +UINT8 DoesPlayerHaveAnyMobileMilitia( void ) +{ + INT16 sX, sY; + + if (!gGameExternalOptions.gfAllowMilitiaGroups) + { + // Mobile Militia not allowed at all. + return (0); + } + + // run through list of towns that might have militia..if any return TRUE..else return FALSE + for( sX = 1; sX < MAP_WORLD_X - 1; sX++ ) + { + for( sY = 1; sY < MAP_WORLD_Y - 1; sY++ ) + { + // Look only in sectors where Militia Training is not allowed at all. If any militia are found there, + // it means that they had to MOVE there, hence mobile militia. + if (!MilitiaTrainingAllowedInSector( sX, sY, 0 )) + { + if( ( SectorInfo[ SECTOR( sX, sY )].ubNumberOfCivsAtLevel[ GREEN_MILITIA ] + SectorInfo[ SECTOR( sX, sY )].ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] + + SectorInfo[ SECTOR( sX, sY )].ubNumberOfCivsAtLevel[ ELITE_MILITIA ] ) > 0 ) + { + // found at least one + return( 2 ); + } + } + } + } + + // Militia are allowed, but none have been found. + return( 1 ); +} void CommonBtnCallbackBtnDownChecks( void ) @@ -1591,13 +1833,16 @@ void InitMapScreenFlags( void ) fShowAircraftFlag = FALSE; fShowItemsFlag = FALSE; + + // HEADROCK HAM 4: Militia Restrictions + fShowMobileRestrictionsFlag = FALSE; } void MapBorderButtonOff( UINT8 ubBorderButtonIndex ) { - Assert( ubBorderButtonIndex < 6 ); + Assert( ubBorderButtonIndex < NUM_MAP_BORDER_BTNS ); if( fShowMapInventoryPool ) { @@ -1618,7 +1863,7 @@ void MapBorderButtonOff( UINT8 ubBorderButtonIndex ) void MapBorderButtonOn( UINT8 ubBorderButtonIndex ) { - Assert( ubBorderButtonIndex < 6 ); + Assert( ubBorderButtonIndex < NUM_MAP_BORDER_BTNS ); if( fShowMapInventoryPool ) { @@ -1635,3 +1880,40 @@ void MapBorderButtonOn( UINT8 ubBorderButtonIndex ) ButtonList[ giMapBorderButtons[ ubBorderButtonIndex ] ]->uiFlags |= BUTTON_CLICKED_ON; } + +// HEADROCK HAM 4: Init the coordinates for all Map Border buttons +void InitMapBorderButtonCoordinates() +{ + MAP_BORDER_TOWN_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 152); + MAP_BORDER_TOWN_BTN_Y = (SCREEN_HEIGHT - 160); + MAP_BORDER_MINE_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 109); + MAP_BORDER_MINE_BTN_Y = (SCREEN_HEIGHT - 160); + MAP_BORDER_TEAMS_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 66); + MAP_BORDER_TEAMS_BTN_Y = (SCREEN_HEIGHT - 160); + MAP_BORDER_AIRSPACE_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 20); + MAP_BORDER_AIRSPACE_BTN_Y = (SCREEN_HEIGHT - 160); + MAP_BORDER_ITEM_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 63); + MAP_BORDER_ITEM_BTN_Y = (SCREEN_HEIGHT - 160); + MAP_BORDER_MILITIA_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 - 23); + MAP_BORDER_MILITIA_BTN_Y = (SCREEN_HEIGHT - 160); + MAP_BORDER_MOBILE_BTN_X = 0; + MAP_BORDER_MOBILE_BTN_Y = 0; + + MAP_LEVEL_MARKER_X = (MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 114)); + MAP_LEVEL_MARKER_Y = (SCREEN_HEIGHT - 160); //(SCREEN_HEIGHT - 157) //323 + MAP_LEVEL_MARKER_DELTA = 8; + MAP_LEVEL_MARKER_WIDTH = 55; //( (SCREEN_WIDTH - 20) - MAP_LEVEL_MARKER_X ) + + if (gGameExternalOptions.gfAllowMilitiaGroups) + { + // Mobile button appears next to Militia button. + MAP_BORDER_MOBILE_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 16); + MAP_BORDER_MOBILE_BTN_Y = (SCREEN_HEIGHT - 160); + + // Airspace, Items, ZLevel buttons all moved to the right (+22px, +22px, +10px). + MAP_BORDER_AIRSPACE_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 42); + MAP_BORDER_ITEM_BTN_X = MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 85); + + MAP_LEVEL_MARKER_X = (MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 124)); + } +} diff --git a/Strategic/Map Screen Interface Border.h b/Strategic/Map Screen Interface Border.h index 7430dc96..c12016e2 100644 --- a/Strategic/Map Screen Interface Border.h +++ b/Strategic/Map Screen Interface Border.h @@ -30,6 +30,8 @@ enum{ MAP_BORDER_AIRSPACE_BTN, MAP_BORDER_ITEM_BTN, MAP_BORDER_MILITIA_BTN, + MAP_BORDER_MOBILE_BTN, // HEADROCK HAM 4: Mobile Militia Restrictions button + NUM_MAP_BORDER_BTNS, // end enumeration marker }; @@ -41,10 +43,12 @@ enum{ */ -#define MAP_LEVEL_MARKER_X (MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 114)) //MAP_BORDER_X + MAP_BORDER_X_OFFSET + 384 //(SCREEN_WIDTH - 75) //565 -#define MAP_LEVEL_MARKER_Y (SCREEN_HEIGHT - 160) //(SCREEN_HEIGHT - 157) //323 -#define MAP_LEVEL_MARKER_DELTA 8 -#define MAP_LEVEL_MARKER_WIDTH 55 //( (SCREEN_WIDTH - 20) - MAP_LEVEL_MARKER_X ) +// HEADROCK HAM 4: Turned these into EXTERNS to allow dynamic modification +//#define MAP_LEVEL_MARKER_X (MAP_BORDER_X + ((SCREEN_WIDTH - MAP_BORDER_X) / 2 + 114)) //MAP_BORDER_X + MAP_BORDER_X_OFFSET + 384 //(SCREEN_WIDTH - 75) //565 +extern UINT16 MAP_LEVEL_MARKER_X; +extern UINT16 MAP_LEVEL_MARKER_Y; +extern UINT16 MAP_LEVEL_MARKER_DELTA; +extern UINT16 MAP_LEVEL_MARKER_WIDTH; extern BOOLEAN fShowTownFlag; @@ -54,6 +58,7 @@ extern BOOLEAN fShowMilitia; extern BOOLEAN fShowAircraftFlag; extern BOOLEAN fShowItemsFlag; extern BOOLEAN fZoomFlag; +extern BOOLEAN fShowMobileRestrictionsFlag; // HEADROCK HAM 4: Manual Mobile Militia mode //extern BOOLEAN fShowVehicleFlag; //extern BOOLEAN fMapScrollDueToPanelButton; @@ -77,10 +82,14 @@ void ToggleShowMilitiaMode( void ); void ToggleShowTeamsMode( void ); void ToggleAirspaceMode( void ); void ToggleItemsFilter( void ); +// HEADROCK HAM 4: Toggle Mobile Militia Restrictions Filter +void ToggleMobileFilter( void ); void TurnOnShowTeamsMode( void ); void TurnOnAirSpaceMode( void ); void TurnOnItemFilterMode( void ); +// HEADROCK HAM 4: Turn on Mobile Militia Restrictions Filter +void TurnOnMobileFilterMode( void ); /* // enable disable map border @@ -95,6 +104,8 @@ BOOLEAN CreateButtonsForMapBorder( void ); // render the pop up for eta in path plotting in map screen void RenderMapBorderEtaPopUp( void ); BOOLEAN DoesPlayerHaveAnyMilitia( void ); +// HEADROCK HAM 4: Same with Mobiles. +UINT8 DoesPlayerHaveAnyMobileMilitia( void ); //void UpdateLevelButtonStates( void ); @@ -107,6 +118,7 @@ void InitMapScreenFlags( void ); void MapBorderButtonOff( UINT8 ubBorderButtonIndex ); void MapBorderButtonOn( UINT8 ubBorderButtonIndex ); - +// HEADROCK HAM 4: Initialize coordinates for Map Border buttons +void InitMapBorderButtonCoordinates(); #endif \ No newline at end of file diff --git a/Strategic/Map Screen Interface Bottom.cpp b/Strategic/Map Screen Interface Bottom.cpp index 88a23172..702844b1 100644 --- a/Strategic/Map Screen Interface Bottom.cpp +++ b/Strategic/Map Screen Interface Bottom.cpp @@ -49,6 +49,8 @@ #include "GameSettings.h" #include "_Ja25EnglishText.h" #include "SaveLoadScreen.h" + #include "Interface Control.h" + #include "Sys Globals.h" #include "game init.h" #endif @@ -1928,6 +1930,10 @@ void HandleExitsFromMapScreen( void ) case MAP_EXIT_TO_TACTICAL: SetCurrentWorldSector( sSelMapX, sSelMapY, ( INT8 )iCurrentMapSectorZ ); + // silversurfer: bugfix for panel redraw issue after quickload from tactical screen + // this will make sure that the tactical screen gets refreshed and guiTacticalInterfaceFlags is reset + fFirstTimeInGameScreen = TRUE; + guiTacticalInterfaceFlags &= (~INTERFACE_MAPSCREEN ); break; case MAP_EXIT_TO_OPTIONS: diff --git a/Strategic/Map Screen Interface Map Inventory.cpp b/Strategic/Map Screen Interface Map Inventory.cpp index eb534299..de886a9c 100644 --- a/Strategic/Map Screen Interface Map Inventory.cpp +++ b/Strategic/Map Screen Interface Map Inventory.cpp @@ -849,7 +849,10 @@ void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason ) //CHRISL: Make it possible to right click and pull up stack popup and/or item description boxes WORLDITEM * twItem = &(pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ]); bool fValidPointer = false; - if ( !InSectorStackPopup( ) && !InItemStackPopup( ) && !InItemDescriptionBox( ) && !InKeyRingPopup( ) && twItem->object.exists() == true && (bSelectedInfoChar != -1 && gCharactersList[bSelectedInfoChar].fValid)) + //CHRISL: Try to update InSector value so we don't have to "activate" a sector + if(MercPtrs[gCharactersList[bSelectedInfoChar].usSolID]->sSectorX == sSelMapX && MercPtrs[gCharactersList[bSelectedInfoChar].usSolID]->sSectorY == sSelMapY && MercPtrs[gCharactersList[bSelectedInfoChar].usSolID]->bSectorZ == iCurrentMapSectorZ && !MercPtrs[gCharactersList[bSelectedInfoChar].usSolID]->flags.fBetweenSectors) + MercPtrs[gCharactersList[bSelectedInfoChar].usSolID]->bInSector=TRUE; + if ( !InSectorStackPopup( ) && !InItemStackPopup( ) /*&& !InItemDescriptionBox( ) */ && !InKeyRingPopup( ) && twItem->object.exists() == true && (bSelectedInfoChar != -1 && gCharactersList[bSelectedInfoChar].fValid)) { if(OK_CONTROL_MERC( MercPtrs[gCharactersList[bSelectedInfoChar].usSolID] )) { @@ -863,7 +866,7 @@ void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason ) { if(gpItemPointer->usItem == twItem->object.usItem) fValidPointer = true; - if(ValidAttachment(gpItemPointer->usItem, twItem->object.usItem) == TRUE) + if(ValidAttachment(gpItemPointer->usItem, &(twItem->object)) == TRUE) fValidPointer = true; if(ValidAmmoType(twItem->object.usItem, gpItemPointer->usItem) == TRUE) fValidPointer = true; @@ -871,6 +874,12 @@ void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason ) if(twItem->object.ubNumberOfObjects == 1 && fValidPointer) { fShowInventoryFlag = TRUE; + + if (InItemDescriptionBox( )) + { + DeleteItemDescriptionBox(); + } + MAPInternalInitItemDescriptionBox( &twItem->object, 0, MercPtrs[gCharactersList[bSelectedInfoChar].usSolID] ); } else if(fValidPointer) @@ -1007,6 +1016,17 @@ void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason ) usNewItemIndex = gpItemPointer->usItem; iOldNumberOfObjects = pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object.ubNumberOfObjects; + //CHRISL: Allow CTRL+LMB to clean up stacks just like we do with personal inventory + //Curretly, screen isn't automatically refreshing. You have to move your cursor after CTRL+LMB to see the results. + if ( _KeyDown(CTRL) ) + { + CleanUpStack( &( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object ), gpItemPointer ); + if ( gpItemPointer->exists() == false ) + { + MAPEndItemPointer( ); + } + return; + } // Else, try to place here if ( PlaceObjectInInventoryStash( &( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object ), gpItemPointer ) ) @@ -2672,7 +2692,8 @@ INT32 SellItem( OBJECTTYPE& object, BOOLEAN useModifier ) } iPrice += ( itemPrice * object[bLoop]->data.objectStatus / 100 ); for (attachmentList::iterator iter = object[bLoop]->attachments.begin(); iter != object[bLoop]->attachments.end(); ++iter) { - iPrice += SellItem(*iter, FALSE); + if(iter->exists()) + iPrice += SellItem(*iter, FALSE); } } } @@ -2683,7 +2704,8 @@ INT32 SellItem( OBJECTTYPE& object, BOOLEAN useModifier ) { iPrice += ( itemPrice * object[bLoop]->data.objectStatus / 100 ); for (attachmentList::iterator iter = object[bLoop]->attachments.begin(); iter != object[bLoop]->attachments.end(); ++iter) { - iPrice += SellItem(*iter, FALSE); + if(iter->exists()) + iPrice += SellItem(*iter, FALSE); } } diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index 5cfc87cb..79b210c8 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -48,6 +48,7 @@ #include "Quests.h" #include "connect.h" +#include "Strategic Mines.h" // HEADROCK HAM 3.5: included for detectionlevels #include "Facilities.h" #include "MilitiaSquads.h" @@ -272,6 +273,14 @@ enum{ MAP_SHADE_DK_GREEN, MAP_SHADE_LT_RED, MAP_SHADE_DK_RED, + // HEADROCK HAM 4: Several new shades, used with the new Manual Mobile Militia restrictions, and the greyed-out map display. + MAP_SHADE_MD_RED, + MAP_SHADE_LT_YELLOW, + MAP_SHADE_DK_YELLOW, + MAP_SHADE_LT_CYAN, + MAP_SHADE_DK_CYAN, + MAP_SHADE_LT_GREY, + MAP_SHADE_DK_GREY, }; // the big map .pcx UINT32 guiBIGMAP; @@ -342,8 +351,8 @@ INT16 sElitesOnCursor = 0; INT16 sSelectedMilitiaTown = 0; -extern MINE_LOCATION_TYPE gMineLocation[]; -extern MINE_STATUS_TYPE gMineStatus[]; +//extern MINE_LOCATION_TYPE gMineLocation[]; +//extern MINE_STATUS_TYPE gMineStatus[]; // sublevel graphics UINT32 guiSubLevel1, guiSubLevel2, guiSubLevel3; @@ -374,6 +383,14 @@ UINT16 *pMapLTRedPalette; UINT16 *pMapDKRedPalette; UINT16 *pMapLTGreenPalette; UINT16 *pMapDKGreenPalette; +// HEADROCK HAM 4: Several new palettes for yellow, cyan, grey. +UINT16 *pMapMDRedPalette; +UINT16 *pMapLTYellowPalette; +UINT16 *pMapDKYellowPalette; +UINT16 *pMapLTCyanPalette; +UINT16 *pMapDKCyanPalette; +UINT16 *pMapLTGreyPalette; +UINT16 *pMapDKGreyPalette; // the map border eta pop up @@ -770,42 +787,130 @@ UINT32 DrawMap( void ) // LATE DESIGN CHANGE: darken sectors not yet visited, instead of those under known enemy control if(!is_networked) //hayden - dont darken anything { - if( GetSectorFlagStatus( cnt, cnt2, ( UINT8 ) iCurrentMapSectorZ, SF_ALREADY_VISITED ) == FALSE ) - // if ( IsTheSectorPerceivedToBeUnderEnemyControl( cnt, cnt2, ( INT8 )( iCurrentMapSectorZ ) ) ) + // HEADROCK HAM 4: Mobile View shows all tiles as explored. + if (!fShowMobileRestrictionsFlag && !iCurrentMapSectorZ ) { - if( fShowAircraftFlag && !iCurrentMapSectorZ ) + if( GetSectorFlagStatus( cnt, cnt2, ( UINT8 ) iCurrentMapSectorZ, SF_ALREADY_VISITED ) == FALSE ) + // if ( IsTheSectorPerceivedToBeUnderEnemyControl( cnt, cnt2, ( INT8 )( iCurrentMapSectorZ ) ) ) { - if( !StrategicMap[ cnt + cnt2 * WORLD_MAP_X ].fEnemyAirControlled ) + if( fShowAircraftFlag && !iCurrentMapSectorZ ) { - // sector not visited, not air controlled - ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_GREEN ); + if( !StrategicMap[ cnt + cnt2 * WORLD_MAP_X ].fEnemyAirControlled ) + { + // sector not visited, not air controlled + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_GREEN ); + } + else + { + // sector not visited, controlled and air not + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_RED ); + } + } + // HEADROCK HAM 4: Show Manual Mobile Militia Restrictions + else if (fShowMobileRestrictionsFlag && !iCurrentMapSectorZ ) + { + /* For now, Mobile View Mode shows all tiles as explored. + UINT8 ubManualMobileMovementAllowed = ManualMobileMovementAllowed( SECTOR(cnt,cnt2) ); + switch ( ubManualMobileMovementAllowed ) + { + case 0: + // Sector not visited, Mobiles not allowed here at all. + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_RED ); + break; + case 1: + // sector not visited, Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_YELLOW ); + break; + case 2: + // sector not visited, Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_CYAN ); + break; + case 3: + // sector not visited, Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_GREEN ); + break; + }*/ } else { - // sector not visited, controlled and air not - ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_RED ); + // not visited + if (gGameSettings.fOptions[TOPTION_ALT_MAP_COLOR]) + { + // HEADROCK HAM 4: An alternate display for the map in normal mode. Unexplored sectors + // are in grey, similar to a recon map. Others are left in normal vivid color. + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_GREY ); + } + else + { + ShadeMapElem( cnt, cnt2, MAP_SHADE_BLACK ); + } } } else { - // not visited - ShadeMapElem( cnt, cnt2, MAP_SHADE_BLACK ); + if( fShowAircraftFlag && !iCurrentMapSectorZ ) + { + if( !StrategicMap[ cnt + cnt2 * WORLD_MAP_X ].fEnemyAirControlled ) + { + // sector visited and air controlled + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_GREEN); + } + else + { + // sector visited but not air controlled + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_RED ); + } + } + // HEADROCK HAM 4: Show Manual Mobile Militia Restrictions + else if (fShowMobileRestrictionsFlag && !iCurrentMapSectorZ ) + { + /* For now, Mobile View Mode shows all tiles as explored. + UINT8 ubManualMobileMovementAllowed = ManualMobileMovementAllowed( SECTOR(cnt, cnt2) ); + switch ( ubManualMobileMovementAllowed ) + { + case 0: + // Sector not visited, Mobiles not allowed here at all. + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_RED ); + break; + case 1: + // sector not visited, Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_YELLOW ); + break; + case 2: + // sector not visited, Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_CYAN ); + break; + case 3: + // sector not visited, Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_GREEN ); + break; + }*/ + } } } - else + else if (fShowMobileRestrictionsFlag && !iCurrentMapSectorZ) { - if( fShowAircraftFlag && !iCurrentMapSectorZ ) + // HEADROCK HAM 4: Show Manual Mobile Militia Restrictions + + UINT8 ubManualMobileMovementAllowed = ManualMobileMovementAllowed( SECTOR(cnt, cnt2) ); + switch ( ubManualMobileMovementAllowed ) { - if( !StrategicMap[ cnt + cnt2 * WORLD_MAP_X ].fEnemyAirControlled ) - { - // sector visited and air controlled - ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_GREEN); - } - else - { - // sector visited but not air controlled - ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_RED ); - } + case 0: + // Mobiles not allowed here at all. + ShadeMapElem( cnt, cnt2, MAP_SHADE_DK_GREY ); + break; + case 1: + // Mobiles forbidden by player + ShadeMapElem( cnt, cnt2, MAP_SHADE_MD_RED ); + break; + case 2: + // Mobiles can enter but not leave + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_YELLOW ); + break; + case 3: + // Mobiles can enter + ShadeMapElem( cnt, cnt2, MAP_SHADE_LT_GREEN ); + break; } } } @@ -835,7 +940,8 @@ UINT32 DrawMap( void ) // draw mine icons for( iCounter = 0; iCounter < MAX_NUMBER_OF_MINES; iCounter++ ) { - BlitMineIcon( gMineLocation[ iCounter ].sSectorX, gMineLocation[ iCounter ].sSectorY ); + //BlitMineIcon( gMineLocation[ iCounter ].sSectorX, gMineLocation[ iCounter ].sSectorY ); + BlitMineIcon( gMineStatus[ iCounter ].sSectorX, gMineStatus[ iCounter ].sSectorY ); } @@ -845,7 +951,8 @@ UINT32 DrawMap( void ) // show mine name/production text for( iCounter = 0; iCounter < MAX_NUMBER_OF_MINES; iCounter++ ) { - BlitMineText( gMineLocation[ iCounter ].sSectorX, gMineLocation[ iCounter ].sSectorY ); + //BlitMineText( gMineLocation[ iCounter ].sSectorX, gMineLocation[ iCounter ].sSectorY ); + BlitMineText( gMineStatus[ iCounter ].sSectorX, gMineStatus[ iCounter ].sSectorY ); } } @@ -1434,7 +1541,6 @@ BOOLEAN ShadeMapElem( INT16 sMapX, INT16 sMapY, INT32 iColor ) UnLockVideoSurface( guiSAVEBUFFER ); break; - case( MAP_SHADE_DK_RED ): // grab video surface and set palette CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); @@ -1454,8 +1560,135 @@ BOOLEAN ShadeMapElem( INT16 sMapX, INT16 sMapY, INT32 iColor ) // unlock source and dest buffers UnLockVideoSurface( guiBIGMAP ); - UnLockVideoSurface( guiSAVEBUFFER ); - break; + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + ///////////////////////////////////////////////////////// + // HEADROCK HAM 4: New colors for map shaders + ///////////////////////////////////////////////////////// + + case( MAP_SHADE_MD_RED ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapMDRedPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + case( MAP_SHADE_LT_YELLOW ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapLTYellowPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + case( MAP_SHADE_DK_YELLOW ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapDKYellowPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + case( MAP_SHADE_LT_CYAN ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapLTCyanPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + case( MAP_SHADE_DK_CYAN ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapDKCyanPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + case( MAP_SHADE_LT_GREY ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapLTGreyPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + case( MAP_SHADE_DK_GREY ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapDKGreyPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + Blt8BPPDataTo16BPPBufferHalfRect( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY, &clip ); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + break; + + /////////////////////////////////////////////// + // HEADROCK HAM 4: End new shaders + /////////////////////////////////////////////// } // restore original palette @@ -1643,6 +1876,45 @@ BOOLEAN ShadeMapElemZoomIn(INT16 sMapX, INT16 sMapY, INT32 iColor ) break; + + // HEADROCK HAM 4: Add two new colors here. + case( MAP_SHADE_LT_YELLOW ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapLTYellowPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + // now blit + Blt8BPPDataSubTo16BPPBuffer( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY , &clip); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + + break; + + case( MAP_SHADE_DK_YELLOW ): + // grab video surface and set palette + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + hSrcVSurface->p16BPPPalette = pMapDKYellowPalette; + + // lock source and dest buffers + pDestBuf = (UINT16*)LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES); + CHECKF( GetVideoSurface( &hSrcVSurface, guiBIGMAP) ); + pSrcBuf = LockVideoSurface( guiBIGMAP, &uiSrcPitchBYTES); + + // now blit + Blt8BPPDataSubTo16BPPBuffer( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf,uiSrcPitchBYTES, sScreenX, sScreenY , &clip); + + // unlock source and dest buffers + UnLockVideoSurface( guiBIGMAP ); + UnLockVideoSurface( guiSAVEBUFFER ); + + break; } } @@ -1674,8 +1946,17 @@ BOOLEAN InitializePalettesForMap( void ) // set up various palettes pMapLTRedPalette = Create16BPPPaletteShaded( pPalette, 400, 0, 0, TRUE ); pMapDKRedPalette = Create16BPPPaletteShaded( pPalette, 200, 0, 0, TRUE ); - pMapLTGreenPalette = Create16BPPPaletteShaded( pPalette, 0, 400, 0, TRUE ); + pMapLTGreenPalette = Create16BPPPaletteShaded( pPalette, 100, 300, 0, TRUE ); pMapDKGreenPalette = Create16BPPPaletteShaded( pPalette, 0, 200, 0, TRUE ); + // HEADROCK HAM 4: Several new palettes for Yellow, Cyan, Grey + pMapMDRedPalette = Create16BPPPaletteShaded( pPalette, 300, 0, 0, TRUE ); + pMapLTYellowPalette = Create16BPPPaletteShaded( pPalette, 400, 350, 0, TRUE ); + pMapDKYellowPalette = Create16BPPPaletteShaded( pPalette, 200, 200, 0, TRUE ); + pMapLTCyanPalette = Create16BPPPaletteShaded( pPalette, 0, 350, 350, TRUE ); + pMapDKCyanPalette = Create16BPPPaletteShaded( pPalette, 0, 200, 200, TRUE ); + pMapLTGreyPalette = Create16BPPPaletteShaded( pPalette, 400, 400, 400, TRUE ); + pMapDKGreyPalette = Create16BPPPaletteShaded( pPalette, 250, 250, 250, TRUE ); + // delete image DeleteVideoSurfaceFromIndex(uiTempMap); @@ -1692,14 +1973,26 @@ void ShutDownPalettesForMap( void ) MemFree( pMapDKRedPalette ); MemFree( pMapLTGreenPalette ); MemFree( pMapDKGreenPalette ); + // HEADROCK HAM 4: Several new palettes (see also below) + MemFree( pMapMDRedPalette ); + MemFree( pMapLTYellowPalette ); + MemFree( pMapDKYellowPalette ); + MemFree( pMapLTCyanPalette ); + MemFree( pMapDKCyanPalette ); + MemFree( pMapLTGreyPalette ); + MemFree( pMapDKGreyPalette ); pMapLTRedPalette = NULL; pMapDKRedPalette = NULL; pMapLTGreenPalette = NULL; pMapDKGreenPalette = NULL; - - - + pMapMDRedPalette = NULL; + pMapLTYellowPalette = NULL; + pMapDKYellowPalette = NULL; + pMapLTCyanPalette = NULL; + pMapDKCyanPalette = NULL; + pMapLTGreyPalette = NULL; + pMapDKGreyPalette = NULL; return; } @@ -2038,9 +2331,12 @@ void DisplayHelicopterTempPath( void ) return; } +extern BOOLEAN HeliCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum ); void PlotPathForHelicopter( INT16 sX, INT16 sY ) { + SOLDIERTYPE *pSkyRider = NULL; + // will plot the path for the helicopter // no heli...go back @@ -2058,6 +2354,12 @@ void PlotPathForHelicopter( INT16 sX, INT16 sY ) // set up mvt group for helicopter SetUpHelicopterForMovement( ); + //CHRISL: If we've plotted a path through enemy controlled airspace, we have a new Skyrider speech we want to hear. + if( GetNumUnSafeSectorsInPath( ) > 0 && !gGameSettings.fOptions[TOPTION_SILENT_SKYRIDER] ) + { + HeliCharacterDialogue( pSkyRider, HELI_PATH_THROUGH_ENEMEY_AIRSPACE ); + } + // move to beginning of list //pHelicopterPath = MoveToBeginningOfPathList( pVehicleList[ iHelicopterVehicleId ].pMercPath ); MoveToBeginningOfPathList( pVehicleList[ iHelicopterVehicleId ].pMercPath ); @@ -4723,7 +5025,7 @@ void BlitMineText( INT16 sMapX, INT16 sMapY ) if (PlayerControlsMine(ubMineIndex) && !gMineStatus[ ubMineIndex ].fEmpty) { // show current production - swprintf( wSubString, L"%d", PredictDailyIncomeFromAMine(ubMineIndex) ); + swprintf( wSubString, L"%d", PredictDailyIncomeFromAMine(ubMineIndex, TRUE) ); InsertCommasForDollarFigure( wSubString ); InsertDollarSignInToString( wSubString ); wcscpy( wString, wSubString ); @@ -4741,9 +5043,9 @@ void BlitMineText( INT16 sMapX, INT16 sMapY ) if (GetMaxPeriodicRemovalFromMine(ubMineIndex) > 0) { #ifdef CHINESE - swprintf( wSubString, L" (%d%%%)", (PredictDailyIncomeFromAMine(ubMineIndex) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) ); + swprintf( wSubString, L" (%d%%%)", (PredictDailyIncomeFromAMine(ubMineIndex, TRUE) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) ); #else - swprintf( wSubString, L" (%d%%%%)", (PredictDailyIncomeFromAMine(ubMineIndex) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) ); + swprintf( wSubString, L" (%d%%%%)", (PredictDailyIncomeFromAMine(ubMineIndex, TRUE) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) ); #endif wcscat( wString, wSubString ); @@ -4879,7 +5181,8 @@ void BlitMineGridMarkers( void ) { if( fZoomFlag ) { - GetScreenXYFromMapXYStationary( ( INT16 )( gMineLocation[ iCounter ].sSectorX), ( INT16 )( gMineLocation[ iCounter ].sSectorY ) , &sScreenX, &sScreenY ); + //GetScreenXYFromMapXYStationary( ( INT16 )( gMineLocation[ iCounter ].sSectorX), ( INT16 )( gMineLocation[ iCounter ].sSectorY ) , &sScreenX, &sScreenY ); + GetScreenXYFromMapXYStationary( ( INT16 )( gMineStatus[ iCounter ].sSectorX), ( INT16 )( gMineStatus[ iCounter ].sSectorY ) , &sScreenX, &sScreenY ); sScreenX -= MAP_GRID_X; sScreenY -= MAP_GRID_Y; @@ -4889,7 +5192,8 @@ void BlitMineGridMarkers( void ) else { // get location on screen - GetScreenXYFromMapXY( ( INT16 )( gMineLocation[ iCounter ].sSectorX ), ( INT16 )( gMineLocation[ iCounter ].sSectorY ), &sScreenX, &sScreenY ); + //GetScreenXYFromMapXY( ( INT16 )( gMineLocation[ iCounter ].sSectorX ), ( INT16 )( gMineLocation[ iCounter ].sSectorY ), &sScreenX, &sScreenY ); + GetScreenXYFromMapXY( ( INT16 )( gMineStatus[ iCounter ].sSectorX ), ( INT16 )( gMineStatus[ iCounter ].sSectorY ), &sScreenX, &sScreenY ); sWidth = MAP_GRID_X; sHeight= MAP_GRID_Y; @@ -6451,7 +6755,7 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) // There's also a special case flag used when players encounter enemies in a sector, then retreat. You can only // see the size of their force while the clock is paused. When unpaused, the flag is reset. if ( CanMercsScoutThisSector( sSectorX, sSectorY, 0 ) || - CanNearbyMilitiaScoutThisSector( sSectorX, sSectorY ) || + CanSomeoneNearbyScoutThisSector( sSectorX, sSectorY, FALSE ) || // merged militia check with scouting check - SANDRO ( uiSectorFlags & SF_PLAYER_KNOWS_ENEMIES_ARE_HERE ) ) { fDetection = TRUE; @@ -6463,6 +6767,18 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) fCount = TRUE; } } + // SADNRO - Scouting trait check for detection of nearby enemies + if (CanSomeoneNearbyScoutThisSector( sSectorX, sSectorY, TRUE )) // scouting trait check + { + if (gSkillTraitValues.fSCCanDetectEnemyPresenseAround) + { + // show their presence + fDetection = TRUE; + // show their numbers + if (gSkillTraitValues.fSCCanDetermineEnemyNumbersAround) + fCount = TRUE; + } + } // Explored Sector Detection // Enemy can be detected in any previously-visited sector. diff --git a/Strategic/Map Screen Interface TownMine Info.cpp b/Strategic/Map Screen Interface TownMine Info.cpp index 68d510a5..c8909577 100644 --- a/Strategic/Map Screen Interface TownMine Info.cpp +++ b/Strategic/Map Screen Interface TownMine Info.cpp @@ -30,6 +30,7 @@ #include "debug.h" #endif +#include "Strategic Mines.h" #define BOX_BUTTON_WIDTH 100 #define BOX_BUTTON_HEIGHT 20 @@ -52,8 +53,9 @@ UINT32 guiMapButtonInventory[2]; UINT16 sTotalButtonWidth = 0; -extern MINE_LOCATION_TYPE gMineLocation[]; -extern MINE_STATUS_TYPE gMineStatus[]; +//extern MINE_LOCATION_TYPE gMineLocation[]; +//extern MINE_STATUS_TYPE gMineStatus[]; + extern BOOLEAN fMapScreenBottomDirty; //extern UINT8 gubMonsterMineInfestation[]; @@ -435,7 +437,7 @@ void AddTextToMineBox( void ) swprintf( wString, L"%s:", pwMineStrings[ 3 ]); AddMonoString( &hStringHandle, wString ); - swprintf( wString, L"%d", PredictDailyIncomeFromAMine( ubMineIndex ) ); + swprintf( wString, L"%d", PredictDailyIncomeFromAMine( ubMineIndex, TRUE ) ); InsertCommasForDollarFigure( wString ); InsertDollarSignInToString( wString ); AddSecondColumnMonoString( &hStringHandle, wString ); @@ -457,7 +459,7 @@ void AddTextToMineBox( void ) // production rate (current production as a percentage of potential production) swprintf( wString, L"%s:", pwMineStrings[ 10 ]); AddMonoString( &hStringHandle, wString ); - swprintf( wString, L"%d%%%%", (PredictDailyIncomeFromAMine(ubMineIndex) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) ); + swprintf( wString, L"%d%%%%", (PredictDailyIncomeFromAMine(ubMineIndex, TRUE) * 100 ) / GetMaxDailyRemovalFromMine(ubMineIndex) ); AddSecondColumnMonoString( &hStringHandle, wString ); } @@ -465,16 +467,19 @@ void AddTextToMineBox( void ) // town control percentage swprintf( wString, L"%s:", pwMineStrings[ 12 ]); AddMonoString( &hStringHandle, wString ); - swprintf( wString, L"%d%%%%", (GetTownSectorsUnderControl( gMineLocation[ ubMineIndex ].bAssociatedTown ) * 100) / GetTownSectorSize( gMineLocation[ ubMineIndex ].bAssociatedTown )); + //swprintf( wString, L"%d%%%%", (GetTownSectorsUnderControl( gMineLocation[ ubMineIndex ].bAssociatedTown ) * 100) / GetTownSectorSize( gMineLocation[ ubMineIndex ].bAssociatedTown )); + swprintf( wString, L"%d%%%%", (GetTownSectorsUnderControl( gMineStatus[ ubMineIndex ].bAssociatedTown ) * 100) / GetTownSectorSize( gMineStatus[ ubMineIndex ].bAssociatedTown )); AddSecondColumnMonoString( &hStringHandle, wString ); - ubTown = gMineLocation[ ubMineIndex ].bAssociatedTown; + //ubTown = gMineLocation[ ubMineIndex ].bAssociatedTown; + ubTown = gMineStatus[ ubMineIndex ].bAssociatedTown; if( gTownLoyalty[ ubTown ].fStarted && gfTownUsesLoyalty[ ubTown ]) { // town loyalty percentage swprintf( wString, L"%s:", pwMineStrings[ 13 ]); AddMonoString( &hStringHandle, wString ); - swprintf( wString, L"%d%%%%", gTownLoyalty[ gMineLocation[ ubMineIndex ].bAssociatedTown ].ubRating); + //swprintf( wString, L"%d%%%%", gTownLoyalty[ gMineLocation[ ubMineIndex ].bAssociatedTown ].ubRating); + swprintf( wString, L"%d%%%%", gTownLoyalty[ gMineStatus[ ubMineIndex ].bAssociatedTown ].ubRating); AddSecondColumnMonoString( &hStringHandle, wString ); } diff --git a/Strategic/Map Screen Interface.cpp b/Strategic/Map Screen Interface.cpp index 818441ce..0eef660d 100644 --- a/Strategic/Map Screen Interface.cpp +++ b/Strategic/Map Screen Interface.cpp @@ -2699,7 +2699,8 @@ void GoToPrevCharacterInList( void ) -void HandleMinerEvent( UINT8 bMinerNumber, INT16 sSectorX, INT16 sSectorY, INT16 sQuoteNumber, BOOLEAN fForceMapscreen ) +//void HandleMinerEvent( UINT8 bMinerNumber, INT16 sSectorX, INT16 sSectorY, INT16 sQuoteNumber, BOOLEAN fForceMapscreen ) +void HandleMinerEvent( UINT8 ubHeadMinerIndex, INT16 sSectorX, INT16 sSectorY, INT16 sQuoteNumber, BOOLEAN fForceMapscreen ) { BOOLEAN fFromMapscreen = FALSE; @@ -2719,6 +2720,8 @@ void HandleMinerEvent( UINT8 bMinerNumber, INT16 sSectorX, INT16 sSectorY, INT16 } } + HEAD_MINER_TYPE* miner = &gHeadMinerData[ubHeadMinerIndex]; + if ( fFromMapscreen ) { // if not showing map surface level @@ -2735,14 +2738,18 @@ void HandleMinerEvent( UINT8 bMinerNumber, INT16 sSectorX, INT16 sSectorY, INT16 fMapPanelDirty = TRUE; // post dialogue events for miners to say this quote and flash the sector where his mine is - CharacterDialogueWithSpecialEvent( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, bMinerNumber , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, START_RED_SECTOR_LOCATOR, 1 ); - CharacterDialogue( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, ( UINT8 )( UINT8 )uiExternalStaticNPCFaces[ bMinerNumber ], DIALOGUE_EXTERNAL_NPC_UI, FALSE , FALSE ); - CharacterDialogueWithSpecialEvent( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, bMinerNumber , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, STOP_RED_SECTOR_LOCATOR, 1 ); + //CharacterDialogueWithSpecialEvent( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, bMinerNumber , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, START_RED_SECTOR_LOCATOR, 1 ); + //CharacterDialogue( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, ( UINT8 )( UINT8 )uiExternalStaticNPCFaces[ bMinerNumber ], DIALOGUE_EXTERNAL_NPC_UI, FALSE , FALSE ); + //CharacterDialogueWithSpecialEvent( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, bMinerNumber , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, STOP_RED_SECTOR_LOCATOR, 1 ); + CharacterDialogueWithSpecialEvent( ( UINT8 )miner->usProfileId, sQuoteNumber, miner->ubExternalFaceIndex, DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE, DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, START_RED_SECTOR_LOCATOR, 1 ); + CharacterDialogue( ( UINT8 )miner->usProfileId, sQuoteNumber, ( UINT8 )uiExternalStaticNPCFaces[miner->ubExternalFaceIndex], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE ); + CharacterDialogueWithSpecialEvent( ( UINT8 )miner->usProfileId, sQuoteNumber, miner->ubExternalFaceIndex, DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE, DIALOGUE_SPECIAL_EVENT_MINESECTOREVENT, STOP_RED_SECTOR_LOCATOR, 1 ); } else // stay in tactical { // no need to to highlight mine sector - CharacterDialogue( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, ( UINT8 )( UINT8 )uiExternalStaticNPCFaces[ bMinerNumber ], DIALOGUE_EXTERNAL_NPC_UI, FALSE , FALSE ); + //CharacterDialogue( ( UINT8 )uiExternalFaceProfileIds[ bMinerNumber ], sQuoteNumber, ( UINT8 )( UINT8 )uiExternalStaticNPCFaces[ bMinerNumber ], DIALOGUE_EXTERNAL_NPC_UI, FALSE , FALSE ); + CharacterDialogue( ( UINT8 )miner->usProfileId, sQuoteNumber, ( UINT8 )uiExternalStaticNPCFaces[miner->ubExternalFaceIndex], DIALOGUE_EXTERNAL_NPC_UI, FALSE , FALSE ); } } diff --git a/Strategic/Map Screen Interface.h b/Strategic/Map Screen Interface.h index d6386a8d..0358f6b5 100644 --- a/Strategic/Map Screen Interface.h +++ b/Strategic/Map Screen Interface.h @@ -511,7 +511,8 @@ void GoToPrevCharacterInList( void ); void GoToNextCharacterInList( void ); // this does the whole miner giving player info speil -void HandleMinerEvent( UINT8 bMinerNumber, INT16 sSectorX, INT16 sSectorY, INT16 sQuoteNumber, BOOLEAN fForceMapscreen ); +//void HandleMinerEvent( UINT8 bMinerNumber, INT16 sSectorX, INT16 sSectorY, INT16 sQuoteNumber, BOOLEAN fForceMapscreen ); +void HandleMinerEvent( UINT8 ubHeadMinerIndex, INT16 sSectorX, INT16 sSectorY, INT16 sQuoteNumber, BOOLEAN fForceMapscreen ); // set up the event of animating a mine sector void SetUpAnimationOfMineSectors( INT32 iEvent ); diff --git a/Strategic/Merc Contract.cpp b/Strategic/Merc Contract.cpp index 987cbb49..b3dd1af7 100644 --- a/Strategic/Merc Contract.cpp +++ b/Strategic/Merc Contract.cpp @@ -839,7 +839,8 @@ void CheckIfMercGetsAnotherContract( SOLDIERTYPE *pSoldier ) // multiply by experience level iChance *= pSoldier->stats.bExpLevel; - if( (INT32) Random( 100 ) < iChance ) + //tais: disabled mercs going on other assignment after being fired.. + if( (INT32) Random( 100 ) < iChance && gGameExternalOptions.fMercsOnAssignment < 2 ) { // B'bye! pSoldier->flags.fSignedAnotherContract = TRUE; @@ -1100,7 +1101,9 @@ void NotifyPlayerOfMercDepartureAndPromptEquipmentPlacement( SOLDIERTYPE *pSoldi } //if the character is an RPC - if( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < FIRST_NPC ) + //if( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < FIRST_NPC ) + //new profiles by Jazz + if ( gProfilesRPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile ) { if( gMercProfiles[ pSoldier->ubProfile ].bSex == MALE ) { diff --git a/Strategic/Merc Contract.h b/Strategic/Merc Contract.h index a47015f3..388dab03 100644 --- a/Strategic/Merc Contract.h +++ b/Strategic/Merc Contract.h @@ -11,6 +11,7 @@ enum CONTRACT_EXTEND_1_DAY, CONTRACT_EXTEND_1_WEEK, CONTRACT_EXTEND_2_WEEK, + NUM_CONTRACT_EXTEND, }; diff --git a/Strategic/MilitiaSquads.cpp b/Strategic/MilitiaSquads.cpp index 807f7029..ac54e9eb 100644 --- a/Strategic/MilitiaSquads.cpp +++ b/Strategic/MilitiaSquads.cpp @@ -66,6 +66,8 @@ INT32 iRestrictedSectorArraySize; UINT32 gRestrictMilitia[256]; +// HEADROCK HAM 4: Yet ANOTHER array, this one holds player-set restrictions. +UINT8 gubManualRestrictMilitia[ 256 ]; // HEADROCK HAM B1: Alternate array keeps track of dynamically unrestricted sectors BOOLEAN gDynamicRestrictMilitia[ 256 ]; // HEADROCK HAM B1: Function that dynamically unrestricts sectors as we take over towns. @@ -173,6 +175,8 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, UINT8 ubTargetRegularPercent = 0; UINT8 ubTempLeadership = ubBestLeadership; + UINT8 ubActualyAdded = 0; // Added by SANDRO + // Does trainer have enough leadership to train a squad? if ( ubBestLeadership < gGameExternalOptions.ubMinimumLeadershipToTrainMobileMilitia ) { @@ -311,6 +315,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, 1); ubTargetElite--; ubMilitiaToTrain--; + ubActualyAdded++; } else if (ubTargetRegular > 0) { @@ -318,6 +323,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, 1); ubTargetRegular--; ubMilitiaToTrain--; + ubActualyAdded++; } else if (ubTargetGreen > 0) { @@ -325,6 +331,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, StrategicAddMilitiaToSector( sTMapX, sTMapY, GREEN_MILITIA, 1); ubTargetGreen--; ubMilitiaToTrain--; + ubActualyAdded++; } else { @@ -347,6 +354,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, 1); ubTargetElite--; ubMilitiaToTrain--; + ubActualyAdded++; } else if (ubTargetRegular > 0 && // Got a regular (!gGameExternalOptions.gfTrainVeteranMilitia || // Not allowed to train Elites @@ -356,6 +364,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, StrategicAddMilitiaToSector( sTMapX, sTMapY, ELITE_MILITIA, 1); ubTargetElite--; ubMilitiaToTrain--; + ubActualyAdded++; } // Else, we've got more men to train but no room for them. In this case, upgrade existing // militia to the next class, using our remainder men as "upgrade points". @@ -376,12 +385,14 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, // Comes at a cost of one regular that we were supposed to train. ubTargetRegular--; ubMilitiaToTrain--; + ubActualyAdded++; } else { // No regulars to train? Remove two greens instead. ubTargetGreen -= 2; ubMilitiaToTrain -= 2; + ubActualyAdded += 2; } } // Else elite training was not allowed or we simply did not have enough points to add an elite @@ -391,6 +402,7 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, StrategicAddMilitiaToSector( sTMapX, sTMapY, REGULAR_MILITIA, 1); ubTargetGreen--; ubMilitiaToTrain--; + ubActualyAdded++; } else { @@ -407,6 +419,11 @@ void GenerateMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, } } + // SANDRO - merc records (num militia trained) + if( ubActualyAdded > 0 ) + RecordNumMilitiaTrainedForMercs( sMapX, sMapY, 0, ubActualyAdded, TRUE ); + + // This reduces the group back to "maximum" size. It starts by eliminating extra greens, then regulars, then elites. // That produces a group of max size, with only the best troops remaining. while( CountMilitia(pTargetSector) > gGameExternalOptions.iMaxMilitiaPerSector ) @@ -463,13 +480,45 @@ void MoveMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, BOOL { // Wilderness->Wilderness movement. Calculate Spread Out chance based on threats. - if (NumEnemiesInFiveSectors( sMapX, sMapY ) == 0 && - NumEnemiesInFiveSectors( sTMapX, sTMapY ) > 0 ) + UINT8 ubNumEnemiesNearOrigin = NumEnemiesInFiveSectors( sMapX, sMapY ); + UINT8 ubNumEnemiesNearTarget = NumEnemiesInFiveSectors( sTMapX, sTMapY ); + + if (ubNumEnemiesNearOrigin == 0 && + ubNumEnemiesNearTarget > 0 ) { // Target sector is threatened, while source sector is not. // Target sector gets all the militia it can, in preperation for a possible enemy attack. ubChanceToSpreadOut = 0; } + else if (ubNumEnemiesNearOrigin > 0 && + ubNumEnemiesNearTarget == 0 ) + { + // Source sector is threatened, while destination is not. The group does not + // move at all, as it is already in a good position to defend. + return; + } + + else if (ubNumEnemiesNearOrigin > 0 && + ubNumEnemiesNearTarget > 0 ) + { + // Both sectors threatened. + + if (gGameExternalOptions.gfAllowReinforcements && !gGameExternalOptions.gfAllowReinforcementsOnlyInCity) + { + // Militia will spread out between the two sectors to maximize defensive capability, since they can + // always reinforce one another if either sector is attacked. + ubChanceToSpreadOut = 100; + } + else + { + // Militia chance to spread out is based on whether the Origin or the Destination are under greater + // threat. If the destination is more threatened, militia are more likely to reinforce it + // (move en-masse). If the origin is more threatened, militia are more likely to spread out evenly + // between the two sectors, to give at least some chance of defeating ONE of the enemy groups. + UINT16 usTotalNumEnemies = ubNumEnemiesNearTarget + ubNumEnemiesNearOrigin; + ubChanceToSpreadOut = __min( 100, (ubNumEnemiesNearOrigin * 100) / usTotalNumEnemies ); + } + } else if (NumEnemiesInFiveSectors( sMapX, sMapY ) > 0 && NumEnemiesInFiveSectors( sTMapX, sTMapY ) > 0 ) { @@ -507,6 +556,13 @@ void MoveMilitiaSquad(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY, BOOL // Target sector is empty, source group is not full. Do not spread out. ubChanceToSpreadOut = 0; } + + // HEADROCK HAM 4: Groups moving into a NO_LEAVE sector will always reinforce it. + // this ignores any of the possible options above. + if (gubManualRestrictMilitia[ SECTOR(sTMapX, sTMapY) ] == MANUAL_MOBILE_NO_LEAVE ) + { + ubChanceToSpreadOut = 0; + } } } @@ -902,6 +958,11 @@ UINT16 CountDirectionRating( INT16 sMapX, INT16 sMapY, UINT8 uiDir ) iRes = 0; } + // HEADROCK HAM 4: Increase desire to move into a NO-LEAVE sector (Player-Set restrictions system) + if (gubManualRestrictMilitia[ SECTOR(sDMapX, sDMapY) ] == MANUAL_MOBILE_NO_LEAVE ) + { + iRes = (INT32)((FLOAT)iRes * 1.5); + } // Test for player mercs in target sector. if( PlayerMercsInSector_MSE( (UINT8)sDMapX, (UINT8)sDMapY, FALSE )) @@ -1338,6 +1399,12 @@ void UpdateMilitiaSquads(INT16 sMapX, INT16 sMapY ) UINT8 uiMilitiaCount; BOOLEAN fSourceCityAllowsRoaming; + // HEADROCK HAM 4: Player can set a sector to NO_LEAVE, forcing Mobiles to stay put if they enter the sector at all. + if (gubManualRestrictMilitia[ SECTOR( sMapX, sMapY ) ] == MANUAL_MOBILE_NO_LEAVE ) + { + // NO_LEAVE zone. Militia can't even consider moving. + return; + } // If we don't want roaming militia // We shouldn't be here. @@ -1696,7 +1763,7 @@ void DoMilitiaHelpFromAdjacentSectors( INT16 sMapX, INT16 sMapY ) if (gfStrategicMilitiaChangesMade) { RemoveMilitiaFromTactical(); - if(is_server && MILITIA_ENABLED==1) + if(is_server && gMilitiaEnabled == 1) PrepareMilitiaForTactical(FALSE); } } @@ -2120,11 +2187,16 @@ void AdjustRoamingRestrictions() gDynamicRestrictMilitia[cnt] = false; } - for (cnt=0; (cnt < 5001 && gDynamicRestrictions[cnt].bSectorID >= 0); cnt++) + for (cnt=0; (cnt < 5001 && gDynamicRestrictions[cnt].sSectorID >= 0); cnt++) { if (!(~uiCapturedTownsFlag & gDynamicRestrictions[cnt].uiReqTownFlags)) { - gDynamicRestrictMilitia[gDynamicRestrictions[cnt].bSectorID] = true; + gDynamicRestrictMilitia[gDynamicRestrictions[cnt].sSectorID] = true; + // HEADROCK HAM 4: Also adjust Player-based restrictions. + if (gubManualRestrictMilitia[ gDynamicRestrictions[cnt].sSectorID ] == MANUAL_MOBILE_RESTRICTED) + { + gubManualRestrictMilitia[ gDynamicRestrictions[cnt].sSectorID ] = MANUAL_MOBILE_NO_RESTRICTION; + } } } } @@ -2290,8 +2362,13 @@ BOOLEAN IsSectorRoamingAllowed( UINT32 uiSector ) // Has the sector ever been visited? if ( SectorInfo[ uiSector ].fSurfaceWasEverPlayerControlled ) { - // Always return TRUE. - return TRUE; + // HEADROCK HAM 4: Take player-based restrictions into account... + if ( gubManualRestrictMilitia[ uiSector ] == MANUAL_MOBILE_NO_RESTRICTION || + gubManualRestrictMilitia[ uiSector ] == MANUAL_MOBILE_NO_LEAVE ) + { + // Always return TRUE. + return TRUE; + } } } // Please note that with exploration restrictions, an UNVISITED sector is not neccesarily RESTRICTED. @@ -2307,7 +2384,21 @@ BOOLEAN IsSectorRoamingAllowed( UINT32 uiSector ) return FALSE; } } - + else + { + // HEADROCK HAM 4: Take player restrictions into account + if ( gubManualRestrictMilitia[ uiSector ] == MANUAL_MOBILE_NO_ENTER ) + { + if ( !NumEnemiesInSector( SECTORX(uiSector), SECTORY(uiSector) ) ) + { + // The player has disallowed movement into this sector, manually. As the condition above + // dictates, this only takes effect if there are no enemies in the target sector. Otherwise, + // militia can move to intercept them anyway. + return FALSE; + } + } + } + return TRUE; } @@ -2350,3 +2441,83 @@ UINT16 MilitiaUpgradeSlotsCheck( SECTORINFO * pSectorInfo ) return (usNumUpgradeSlots); } +// HEADROCK HAM 4: Returns whether sector is allowed for militia roaming, taking into account player-set restrictions. +UINT8 ManualMobileMovementAllowed( UINT8 ubSector ) +{ + BOOLEAN fRestricted = TRUE; + + if (gGameExternalOptions.gflimitedRoaming) + { + if (gGameExternalOptions.fUnrestrictVisited) + { + // Has the sector ever been visited? + if ( SectorInfo[ ubSector ].fSurfaceWasEverPlayerControlled ) + { + // Always return TRUE. + fRestricted = FALSE; + } + } + + if(gGameExternalOptions.fDynamicRestrictRoaming) + { + if (gDynamicRestrictMilitia[ ubSector ] ) + { + fRestricted = FALSE; + } + } + } + else + { + fRestricted = FALSE; + } + + if (fRestricted) + { + // Restricted roaming! Militia can't go here ever. + return (0); + } + else + { + if (gubManualRestrictMilitia[ ubSector ] == MANUAL_MOBILE_NO_ENTER ) + { + // Player-restricted. Militia can potentially go here, if the player removed the restriction. + return (1); + } + else if (gubManualRestrictMilitia[ ubSector ] == MANUAL_MOBILE_NO_LEAVE ) + { + // Militia allowed to enter, but not leave. + return (2); + } + else + { + // Roaming allowed. + return (3); + } + } +} + +void InitManualMobileRestrictions() +{ + UINT16 x; + for ( x = 0; x < 256; x++ ) + { + UINT8 ubTownID = GetTownIdForSector( SECTORX(x), SECTORY(x) ); + if (ubTownID != BLANK_SECTOR ) + { + if (gfMilitiaAllowedInTown[ubTownID]) + { + // Major town. Set to NO-ENTER by default. + gubManualRestrictMilitia[x] = MANUAL_MOBILE_NO_ENTER; + continue; + } + else + { + // Minor town. Set to NO_RESTRICTIONS by default. + gubManualRestrictMilitia[x] = MANUAL_MOBILE_NO_RESTRICTION; + continue; + } + } + // By default, all other sectors are "go". + gubManualRestrictMilitia[x] = MANUAL_MOBILE_NO_RESTRICTION; + } +} diff --git a/Strategic/MilitiaSquads.h b/Strategic/MilitiaSquads.h index 7efcc042..f2531be9 100644 --- a/Strategic/MilitiaSquads.h +++ b/Strategic/MilitiaSquads.h @@ -26,6 +26,8 @@ void MilitiaFollowPlayer( INT16 sMapX, INT16 sMapY, INT16 sDMapX, INT16 sDMapY ) // HEADROCK HAM B1: Changes the allowed militia sectors extern void AdjustRoamingRestrictions(); +// HEADROCK HAM 4: Yet ANOTHER array, this one holds player-set restrictions. It interacts with the dynamic one below. +extern UINT8 gubManualRestrictMilitia[ 256 ]; // HEADROCK HAM B1: Alternate array keeps track of dynamically unrestricted sectors extern BOOLEAN gDynamicRestrictMilitia[ 256 ]; // HEADROCK HAM B2.7: Wonder why this function wasn't declared here. It is now, to allow Town Militia.cpp to @@ -40,7 +42,7 @@ void GenerateDirectionInfosForTraining( INT16 sMapX, INT16 sMapY, UINT8* uiDirNu // HEADROCK HAM 3.4: Stores restriction data from XML, including required cities for each sector to be allowed. typedef struct DYNAMICRESTRICTIONS { - INT8 bSectorID; + INT16 sSectorID; UINT32 uiReqTownFlags; } DYNAMICRESTRICTIONS; @@ -56,4 +58,10 @@ void AddToBlockMoveList(INT16 sMapX, INT16 sMapY); // And this: UINT8 CountMilitia(SECTORINFO *pSectorInfo); +// HEADROCK HAM 4: Returns whether sector is allowed for militia roaming, taking into account player-set restrictions. +UINT8 ManualMobileMovementAllowed( UINT8 ubSector ); + +// HEADROCK HAM 4: Initialize all manual restrictions; +void InitManualMobileRestrictions(); + #endif \ No newline at end of file diff --git a/Strategic/PreBattle Interface.cpp b/Strategic/PreBattle Interface.cpp index c9f91dfd..8c60ebce 100644 --- a/Strategic/PreBattle Interface.cpp +++ b/Strategic/PreBattle Interface.cpp @@ -44,6 +44,9 @@ #include "Soldier macros.h" #include "history.h" #include "Cheats.h" + // added by SANDRO + #include "Tactical Save.h" + #include "message.h" #endif extern void InitializeTacticalStatusAtBattleStart(); @@ -262,6 +265,7 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) INT8 bBestExpLevel = 0; BOOLEAN fRetreatAnOption = TRUE; SECTORINFO *pSector; + BOOLEAN fScoutPresent = FALSE; // Added by SANDRO // ARM: Feb01/98 - Cancel out of mapscreen movement plotting if PBI subscreen is coming up if( ( bSelectedDestChar != -1 ) || ( fPlotForHelicopter == TRUE ) ) @@ -493,7 +497,8 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) ubGroupID = MercPtrs[ i ]->ubGroupID; if( !gpBattleGroup ) gpBattleGroup = GetGroup( ubGroupID ); - if( bBestExpLevel > MercPtrs[ i ]->stats.bExpLevel ) + //if( bBestExpLevel > MercPtrs[ i ]->stats.bExpLevel ) // SANDRO - WTF!! This is a bug! + if( bBestExpLevel < MercPtrs[ i ]->stats.bExpLevel ) // SANDRO - WTF!! This is a bug! bBestExpLevel = MercPtrs[ i ]->stats.bExpLevel; if( MercPtrs[ i ]->ubPrevSectorID == 255 ) { //Not able to retreat (calculate it for group) @@ -508,6 +513,12 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) fUsePluralVersion = TRUE; } guiNumInvolved ++; + + // SANDRO - added check if we have a scout in group, needed later + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( MercPtrs[ i ], SCOUTING_NT ) && gSkillTraitValues.fSCPreventsTheEnemyToAmbushMercs ) + { + fScoutPresent = TRUE; + } } else { guiNumUninvolved++; @@ -518,6 +529,8 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) ubNumStationaryEnemies = NumStationaryEnemiesInSector( gubPBSectorX, gubPBSectorY ); ubNumMobileEnemies = NumMobileEnemiesInSector( gubPBSectorX, gubPBSectorY ); ubNumMercs = PlayerMercsInSector( gubPBSectorX, gubPBSectorY, gubPBSectorZ ); + + BOOLEAN fAmbushPrevented = FALSE; if( gfPersistantPBI ) { @@ -542,63 +555,111 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) { if( Chance( 90 ) ) { - gubEnemyEncounterCode = ENEMY_AMBUSH_CODE; + // SANDRO - Scout prevents ambushes no matter what + if ( !fScoutPresent ) + { + gubEnemyEncounterCode = ENEMY_AMBUSH_CODE; + } + else + { + fAmbushPrevented = TRUE; + if ( gSkillTraitValues.fSCThrowMessageIfAmbushPrevented ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_ENEMY_AMBUSH_PREVENTED] ); + } } } else if( gfAutoAmbush && ubNumMobileEnemies > ubNumMercs ) { - gubEnemyEncounterCode = ENEMY_AMBUSH_CODE; + // SANDRO - Scout prevents ambushes no matter what + if ( !fScoutPresent ) + { + gubEnemyEncounterCode = ENEMY_AMBUSH_CODE; + } + else + { + fAmbushPrevented = TRUE; + if ( gSkillTraitValues.fSCThrowMessageIfAmbushPrevented ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_ENEMY_AMBUSH_PREVENTED] ); + } } // Madd: // WANNE: Added an ja2_options.ini Property "ENABLE_CHANCE_OF_ENEMY_AMBUSHES_ON_INSANE_DIFFICULT" - else if( gGameExternalOptions.fEnableChanceOfEnemyAmbushesOnInsaneDifficult && - gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE && - CurrentPlayerProgressPercentage() >= 25 ) - { //if the enemy outnumbers the players, then there is a chance of the enemies ambushing the group - if( ubNumMobileEnemies > ubNumMercs ) + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - changed this a lot, now on any difficulty, the enemy can ambush your squad + // based on difficulty level, number of mercs/enemies and other aspects + else if( gGameExternalOptions.fEnableChanceOfEnemyAmbushes ) + { + INT32 iChance; + // Basic chance - progress level/2 minus highest merc exp level*2, and 10% on top + iChance = (UINT8)( ((CurrentPlayerProgressPercentage() / 2 ) - bBestExpLevel*2 ) + 15 ); + + pSector = &SectorInfo[ SECTOR( gubPBSectorX, gubPBSectorY ) ]; + if( pSector->uiFlags & SF_ENEMY_AMBUSH_LOCATION ) + iChance += 20; + + if( gfCantRetreatInPBI ) + iChance += 20; + + // adjust the chance for size of our squad + if( ubNumMercs == 1 ) // one person is almost invisible to an army group, so reduce the chance a lot + iChance -= 40; + else if ( ubNumMercs == 2 ) // 2 persons are still hardly detectable + iChance -= 25; + else if ( ubNumMercs <= 10 ) // 3 to 10 mercs + iChance -= (5 * (5 - ubNumMercs)); // -5% adjustment per merc (-10% to +25%) + else // more than 10 mercs + iChance += 30; // maximum of +30% per squad size + + // the more enemies are there the lesser the chance to be ambushed + // (large groups of enemies can be seen from afar, so the chance is lesser) + if ((ubNumMobileEnemies + ubNumStationaryEnemies) <= 2 ) + iChance += 20; // can make hunting retreated enemies easier + else if ((ubNumMobileEnemies + ubNumStationaryEnemies) <= 6 ) // smaller groups actually increase the chance + iChance += (3 * (6 - (ubNumMobileEnemies + ubNumStationaryEnemies))); // +3% adjustment per enemy + else + iChance -= (2 * ((ubNumMobileEnemies + ubNumStationaryEnemies) - 6)); // -2% adjustment per enemy beyond 6 + + // adjust the chance for difficulty setting + if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY ) + iChance -= 15; + else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_MEDIUM ) + iChance += 5; + else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_HARD ) + iChance += 12; + else if( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) + iChance += 25; + + // adjust the chance for what we know about the sector + if( WhatPlayerKnowsAboutEnemiesInSector( gubPBSectorX, gubPBSectorY ) == KNOWS_NOTHING ) + iChance += 20; + else if( WhatPlayerKnowsAboutEnemiesInSector( gubPBSectorX, gubPBSectorY ) == KNOWS_THEYRE_THERE ) + iChance += 5; + //if( GetSectorFlagStatus( gubPBSectorX, gubPBSectorY, 0, SF_ALREADY_VISITED ) == TRUE ) + // iChance -= 10; // if we already visited this sector + + // there is always a little chance + if( iChance <= 0 ) + iChance = 1; + + // externalized modifier + if( gGameExternalOptions.bChanceModifierEnemyAmbushes != 0 ) + iChance = ((iChance * (100 + gGameExternalOptions.bChanceModifierEnemyAmbushes)) / 100); + + if( (INT32)PreRandom( 100 ) < iChance ) { - INT32 iChance; - pSector = &SectorInfo[ SECTOR( gubPBSectorX, gubPBSectorY ) ]; - iChance = (UINT8)( (CurrentPlayerProgressPercentage() - bBestExpLevel*2 ) ); - if( pSector->uiFlags & SF_ENEMY_AMBUSH_LOCATION ) - { - iChance += 20; - } - if( gfCantRetreatInPBI ) - { - iChance += 20; - } - if( (INT32)PreRandom( 100 ) < iChance ) + if ( !fScoutPresent ) { gubEnemyEncounterCode = ENEMY_AMBUSH_CODE; } - } - } - else if( WhatPlayerKnowsAboutEnemiesInSector( gubPBSectorX, gubPBSectorY ) == KNOWS_NOTHING && - CurrentPlayerProgressPercentage() >= 30 - gGameOptions.ubDifficultyLevel * 5 ) - { //if the enemy outnumbers the players, then there is a small chance of the enemies ambushing the group - if( ubNumMobileEnemies > ubNumMercs ) - { - INT32 iChance; - pSector = &SectorInfo[ SECTOR( gubPBSectorX, gubPBSectorY ) ]; - if( !(pSector->uiFlags & SF_ALREADY_VISITED) ) + else { - iChance = (UINT8)( 4 - bBestExpLevel + 2 * gGameOptions.ubDifficultyLevel + CurrentPlayerProgressPercentage() / 10 ); - if( pSector->uiFlags & SF_ENEMY_AMBUSH_LOCATION ) - { - iChance += 20; - } - if( gfCantRetreatInPBI ) - { - iChance += 20; - } - if( (INT32)PreRandom( 100 ) < iChance ) - { - gubEnemyEncounterCode = ENEMY_AMBUSH_CODE; - } + fAmbushPrevented = TRUE; + if ( gSkillTraitValues.fSCThrowMessageIfAmbushPrevented ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_ENEMY_AMBUSH_PREVENTED] ); } } } + ////////////////////////////////////////////////////////////////////////////////////////////////////////////// } } } @@ -628,6 +689,26 @@ void InitPreBattleInterface( GROUP *pBattleGroup, BOOLEAN fPersistantPBI ) gfHighPotentialForAmbush = FALSE; + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - ambush experienced + if( gubEnemyEncounterCode == ENEMY_AMBUSH_CODE || gubEnemyEncounterCode == BLOODCAT_AMBUSH_CODE || fAmbushPrevented ) + { + for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) + { + if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) ) + { + if ( PlayerMercInvolvedInThisCombat( MercPtrs[ i ] ) && MercPtrs[ i ]->ubProfile != NO_PROFILE ) + { + if ( gubEnemyEncounterCode == ENEMY_AMBUSH_CODE || gubEnemyEncounterCode == BLOODCAT_AMBUSH_CODE ) + gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.usAmbushesExperienced++; + else if ( fAmbushPrevented && HAS_SKILL_TRAIT( MercPtrs[ i ], SCOUTING_NT ) ) // Scouts actually get this as number of prevented ambushes + gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.usAmbushesExperienced++; + } + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if( gfAutomaticallyStartAutoResolve ) { DisableButton( iPBButton[1] ); @@ -1395,6 +1476,18 @@ void RetreatMercsCallback( GUI_BUTTON *btn, INT32 reason ) { if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) { + ///////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - times retreated counter + for( UINT8 i = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; i <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; i++ ) + { + if ( MercPtrs[i]->bActive && MercPtrs[i]->stats.bLife >= OKLIFE ) + { + if ( PlayerMercInvolvedInThisCombat( MercPtrs[i] ) && MercPtrs[i]->ubProfile != NO_PROFILE ) + gMercProfiles[ MercPtrs[i]->ubProfile ].records.usBattlesRetreated++; + } + } + ///////////////////////////////////////////////////////////////////////////////// + // get them outta here! RetreatAllInvolvedPlayerGroups(); diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index e7ca1b2c..87e3ecbb 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -561,7 +561,7 @@ BOOLEAN PrepareEnemyForSectorBattle() pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ]; // OJW - 20090403 - override max ai in co-op - if (is_networked && is_server && OVERRIDE_MAX_AI == 1) + if (is_networked && is_server && gMaxEnemiesEnabled == 1) { float totalEnemies = (float)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); ubTotalAdmins = (unsigned int)(((float)pSector->ubNumAdmins / totalEnemies) * mapMaximumNumberOfEnemies); @@ -1314,7 +1314,7 @@ void AddPossiblePendingEnemiesToBattle() // haydent if (is_networked) { - if ((is_client && !is_server) || ENEMY_ENABLED==0) + if ((is_client && !is_server) || gEnemyEnabled == 0) { return; } @@ -1475,7 +1475,11 @@ void AddPossiblePendingEnemiesToBattle() ubInsertionCode = INSERTION_CODE_NORTH; else { - Assert(0); + // WANNE: Hack: If no valid insertion is found, get random insertion instead of Assert() error + UINT32 rndInsertionCode = GetRndNum(3); + ubInsertionCode = rndInsertionCode; + + //Assert(0); } } else if( pGroup->ubNextX && pGroup->ubNextY ) @@ -1490,7 +1494,11 @@ void AddPossiblePendingEnemiesToBattle() ubInsertionCode = INSERTION_CODE_NORTH; else { - Assert(0); + // WANNE: Hack: If no valid insertion is found, get random insertion instead of Assert() error + UINT32 rndInsertionCode = GetRndNum(3); + ubInsertionCode = rndInsertionCode; + + //Assert(0); } } else @@ -1914,10 +1922,10 @@ void EnemyCapturesPlayerSoldier( SOLDIERTYPE *pSoldier ) // TODO.WANNE: Hardcoded grid number - static INT32 sAlmaCaptureGridNos[] = { 9208, 9688, 9215 }; - static INT32 sAlmaCaptureItemsGridNo[] = { 12246, 12406, 13046 }; + static INT32 sAlmaCaptureGridNos[] = { 9208, 9688, 9215 }; //dnl!!! + static INT32 sAlmaCaptureItemsGridNo[] = { 12246, 12406, 13046 }; //dnl!!! - static INT32 sInterrogationItemGridNo[] = { 12089, 12089, 12089 }; + static INT32 sInterrogationItemGridNo[] = { 12089, 12089, 12089 }; //dnl!!! AssertNotNIL(pSoldier); @@ -1940,6 +1948,7 @@ void EnemyCapturesPlayerSoldier( SOLDIERTYPE *pSoldier ) if ( AM_AN_EPC( pSoldier ) ) { pSoldier->stats.bLife = 0; + pSoldier->iHealableInjury = 0; // added by SANDRO HandleSoldierDeath( pSoldier, &fMadeCorpse ); return; } @@ -2069,6 +2078,8 @@ void EnemyCapturesPlayerSoldier( SOLDIERTYPE *pSoldier ) { pSoldier->stats.bLife += (INT8)(10 - Random( 21 ) ); } + // SANDRO - make the lost life insta-healable + pSoldier->iHealableInjury = ((pSoldier->stats.bLifeMax - pSoldier->stats.bLife) * 100); // make him quite exhausted when found pSoldier->bBreath = pSoldier->bBreathMax = 50; @@ -2089,6 +2100,7 @@ void HandleEnemyStatusInCurrentMapBeforeLoadingNewMap() if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife ) { MercPtrs[ i ]->stats.bLife = 0; + MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse ); bKilledEnemies++; } @@ -2109,6 +2121,7 @@ void HandleEnemyStatusInCurrentMapBeforeLoadingNewMap() if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife ) { MercPtrs[ i ]->stats.bLife = 0; + MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse ); bKilledRebels++; } @@ -2119,6 +2132,7 @@ void HandleEnemyStatusInCurrentMapBeforeLoadingNewMap() if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife ) { MercPtrs[ i ]->stats.bLife = 0; + MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse ); bKilledCivilians++; } diff --git a/Strategic/Quest Debug System.cpp b/Strategic/Quest Debug System.cpp index adc2bbb9..15baede0 100644 --- a/Strategic/Quest Debug System.cpp +++ b/Strategic/Quest Debug System.cpp @@ -3301,7 +3301,9 @@ void AddNPCsInSectorToArray() if ( ( pSoldier != NULL ) && pSoldier->bActive ) { //if soldier is a NPC, add him to the local NPC array - if( ( pSoldier->ubProfile >= FIRST_RPC ) && ( pSoldier->ubProfile < GASTON ) ) + //if( ( pSoldier->ubProfile >= FIRST_RPC ) && ( pSoldier->ubProfile < GASTON ) ) + //new profiles by Jazz + if ( gProfilesRPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesNPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesVehicle[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile ) { gubCurrentNpcInSector[ i ] = pSoldier->ubProfile; i++; @@ -3698,7 +3700,9 @@ void RefreshAllNPCInventory() if( Menptr[ usCnt ].bActive == 1 ) { //is the merc a rpc or npc - if( Menptr[ usCnt ].ubProfile >= FIRST_RPC && Menptr[ usCnt ].ubProfile < GASTON ) + //if( Menptr[ usCnt ].ubProfile >= FIRST_RPC && Menptr[ usCnt ].ubProfile < GASTON ) + //new profiles by Jazz + if ( gProfilesRPC[Menptr[ usCnt ].ubProfile].ProfilId == Menptr[ usCnt ].ubProfile || gProfilesNPC[Menptr[ usCnt ].ubProfile].ProfilId == Menptr[ usCnt ].ubProfile || gProfilesVehicle[Menptr[ usCnt ].ubProfile].ProfilId == Menptr[ usCnt ].ubProfile ) { //refresh the mercs inventory for ( usItemCnt = 0; usItemCnt< Menptr[ usCnt ].inv.size(); usItemCnt++ ) @@ -3982,7 +3986,9 @@ UINT8 WhichPanelShouldTalkingMercUse( ) return( QDS_NO_PANEL ); } - if( gTalkingMercSoldier->ubProfile < FIRST_RPC || gTalkingMercSoldier->ubProfile >= GASTON ) + //if( gTalkingMercSoldier->ubProfile < FIRST_RPC || gTalkingMercSoldier->ubProfile >= GASTON ) + //new profiles by Jazz + if ( gProfilesAIM[gTalkingMercSoldier->ubProfile].ProfilId == gTalkingMercSoldier->ubProfile || gProfilesMERC[gTalkingMercSoldier->ubProfile].ProfilId == gTalkingMercSoldier->ubProfile || gProfilesIMP[gTalkingMercSoldier->ubProfile].ProfilId == gTalkingMercSoldier->ubProfile ) { return( QDS_REGULAR_PANEL ); } diff --git a/Strategic/Quests.cpp b/Strategic/Quests.cpp index fa3a9b97..2ff42164 100644 --- a/Strategic/Quests.cpp +++ b/Strategic/Quests.cpp @@ -331,6 +331,23 @@ BOOLEAN CheckNPCIsEPC( UINT8 ubProfileID ) return( (pNPC->ubWhatKindOfMercAmI == MERC_TYPE__EPC ) ); } +BOOLEAN CheckNPCIsRPC( UINT8 ubProfileID ) +{ + SOLDIERTYPE * pNPC; + + if ( gMercProfiles[ ubProfileID ].bMercStatus == MERC_IS_DEAD ) + { + return( FALSE ); + } + + pNPC = FindSoldierByProfileID( ubProfileID, TRUE ); + if (!pNPC) + { + return( FALSE ); + } + return( (pNPC->ubWhatKindOfMercAmI == MERC_TYPE__NPC ) ); +} + BOOLEAN NPCInRoom( UINT8 ubProfileID, UINT8 ubRoomID ) { SOLDIERTYPE * pNPC; @@ -914,10 +931,10 @@ BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID ) case FACT_RECEIVING_INCOME_FROM_DCAC: gubFact[usFact] = ( - ( PredictDailyIncomeFromAMine( MINE_DRASSEN ) > 0 ) && - ( PredictDailyIncomeFromAMine( MINE_ALMA ) > 0 ) && - ( PredictDailyIncomeFromAMine( MINE_CAMBRIA ) > 0 ) && - ( PredictDailyIncomeFromAMine( MINE_CHITZENA ) > 0 ) ); + ( PredictDailyIncomeFromAMine( MINE_DRASSEN, TRUE ) > 0 ) && + ( PredictDailyIncomeFromAMine( MINE_ALMA, TRUE ) > 0 ) && + ( PredictDailyIncomeFromAMine( MINE_CAMBRIA, TRUE ) > 0 ) && + ( PredictDailyIncomeFromAMine( MINE_CHITZENA, TRUE ) > 0 ) ); break; case FACT_PLAYER_BEEN_TO_K4: @@ -994,15 +1011,21 @@ BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID ) break; case FACT_PLAYER_OWNS_2_TOWNS_INCLUDING_OMERTA: - gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() == 3 ) && IsTownUnderCompleteControlByPlayer( OMERTA ) ); + gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() == gGameExternalOptions.ubEarlyRebelsRecruitment[1] || gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 1 + || ( gubQuest[QUEST_FOOD_ROUTE] == QUESTDONE && gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 4 ) ) && IsTownUnderCompleteControlByPlayer( OMERTA ) ); break; case FACT_PLAYER_OWNS_3_TOWNS_INCLUDING_OMERTA: - gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() == 5 ) && IsTownUnderCompleteControlByPlayer( OMERTA ) ); + gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() == gGameExternalOptions.ubEarlyRebelsRecruitment[2] || gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 1 + || ( gubQuest[QUEST_FOOD_ROUTE] == QUESTDONE && gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 4 ) ) && IsTownUnderCompleteControlByPlayer( OMERTA ) ); break; case FACT_PLAYER_OWNS_4_TOWNS_INCLUDING_OMERTA: - gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() >= 6 ) && IsTownUnderCompleteControlByPlayer( OMERTA ) ); + gubFact[usFact] = ( ( GetNumberOfWholeTownsUnderControl() >= gGameExternalOptions.ubEarlyRebelsRecruitment[3] || gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 1 + || ( gubQuest[QUEST_FOOD_ROUTE] == QUESTDONE && gGameExternalOptions.ubEarlyRebelsRecruitment[0] == 4 ) ) && IsTownUnderCompleteControlByPlayer( OMERTA ) ); + // silversurfer: this is the highest requirement and therefore we will automatically enable recruitment of Miguel + if ( gubFact[usFact] ) + SetFactTrue(40); // Miguel will now be willing to join and so will the other RPC break; case FACT_PLAYER_FOUGHT_THREE_TIMES_TODAY: @@ -1224,8 +1247,8 @@ BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID ) gubFact[usFact] = !BoxerExists(); break; - case 245: // Can dimitri be recruited? should be true if already true, OR if Miguel has been recruited already - gubFact[usFact] = ( gubFact[usFact] || FindSoldierByProfileID( MIGUEL, TRUE ) ); + case 245: // Can dimitri be recruited? should be true if already true, OR if Miguel has been recruited already OR is available for recruitment + gubFact[usFact] = ( gubFact[usFact] || FindSoldierByProfileID( MIGUEL, TRUE ) || gubFact[40] ); /* case FACT_: gubFact[usFact] = ; @@ -1269,8 +1292,67 @@ void EndQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY ) void InternalEndQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY, BOOLEAN fUpdateHistory ) { - if ( gubQuest[ubQuest ] == QUESTINPROGRESS ) + // SANDRO merc records - quests handled counter + if ( gubQuest[ubQuest] != QUESTDONE && fUpdateHistory ) // only public quests { + switch (ubQuest) + { + case QUEST_FOOD_ROUTE : + // food quest is handled differently (completing when spoken to father Walker) + break; + case QUEST_DELIVER_LETTER : + case QUEST_LEATHER_SHOP_DREAM : + GiveQuestRewardPoint( sSectorX, sSectorY, 3, NO_PROFILE ); + break; + case QUEST_ESCORT_SKYRIDER : + case QUEST_CHOPPER_PILOT : + case QUEST_FREE_CHILDREN : + case QUEST_RESCUE_MARIA : + case QUEST_FIND_SCIENTIST : + case QUEST_DELIVER_VIDEO_CAMERA : + case QUEST_FIND_HERMIT : + GiveQuestRewardPoint( sSectorX, sSectorY, 4, NO_PROFILE ); + break; + case QUEST_FREE_DYNAMO : + // don't give Dynamo reward for himself + if( gMercProfiles[ DYNAMO ].bMercStatus != MERC_IS_DEAD ) + GiveQuestRewardPoint( sSectorX, sSectorY, 4, DYNAMO ); + break; + case QUEST_KINGPIN_IDOL : + case QUEST_CHITZENA_IDOL : + case QUEST_HELD_IN_ALMA : + case QUEST_RUNAWAY_JOEY : + case QUEST_ESCORT_TOURISTS : + GiveQuestRewardPoint( sSectorX, sSectorY, 5, NO_PROFILE ); + break; + case QUEST_ARMY_FARM : + case QUEST_KINGPIN_MONEY : + GiveQuestRewardPoint( sSectorX, sSectorY, 6, NO_PROFILE ); + break; + case QUEST_BLOODCATS : + GiveQuestRewardPoint( sSectorX, sSectorY, 7, NO_PROFILE ); + break; + case QUEST_INTERROGATION : // we get here only if wiped out enemies after interrogation + case QUEST_CREATURES : + GiveQuestRewardPoint( sSectorX, sSectorY, 8, NO_PROFILE ); + break; + case QUEST_KILL_TERRORISTS : // only reduced experiences if we chosen Slay over Carmen + if( gMercProfiles[ CARMEN ].bMercStatus == MERC_IS_DEAD ) + GiveQuestRewardPoint( sSectorX, sSectorY, 5, NO_PROFILE ); + else + GiveQuestRewardPoint( sSectorX, sSectorY, 9, NO_PROFILE ); + break; + case QUEST_KILL_DEIDRANNA : + GiveQuestRewardPoint( sSectorX, sSectorY, 25, NO_PROFILE ); + break; + default : + GiveQuestRewardPoint( sSectorX, sSectorY, 4, NO_PROFILE ); + break; + } + } + + if ( gubQuest[ubQuest ] == QUESTINPROGRESS ) + { gubQuest[ubQuest] = QUESTDONE; if ( fUpdateHistory ) @@ -1290,7 +1372,6 @@ void InternalEndQuest( UINT8 ubQuest, INT16 sSectorX, INT16 sSectorY, BOOLEAN fU gMercProfiles[ MADAME ].bNPCData = 0; gMercProfiles[ MADAME ].bNPCData2 = 0; } - }; void InitQuestEngine() @@ -1390,7 +1471,27 @@ BOOLEAN LoadQuestInfoFromSavedGameFile( HWFILE hFile ) return( TRUE ); } +// SANDRO - a function to add quest-done point to merc records, and award some exp possibly +void GiveQuestRewardPoint( INT16 sQuestSectorX, INT16 sQuestsSectorY, INT8 bExpReward, UINT8 bException ) +{ + ScreenMsg( FONT_MCOLOR_LTBLUE, MSG_TESTVERSION, L"QUEST COMPLETED - Adding to merc records and awarding experiences (%d).", (bExpReward * gGameExternalOptions.usAwardSpecialExpForQuests) ); + for ( UINT8 i = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; i <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; i++ ) + { + if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife >= CONSCIOUSNESS && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) && MercPtrs[ i ]->ubProfile != NO_PROFILE && + MercPtrs[ i ]->sSectorX == sQuestSectorX && MercPtrs[ i ]->sSectorY == sQuestsSectorY && !MercPtrs[ i ]->flags.fBetweenSectors && MercPtrs[ i ]->bTeam == gbPlayerNum && + MercPtrs[ i ]->bAssignment != IN_TRANSIT && MercPtrs[ i ]->bAssignment != ASSIGNMENT_DEAD && gMercProfiles[ MercPtrs[ i ]->ubProfile ].ubBodyType != 21 ) // != ROBOTNOWEAPON ) + { + if ( MercPtrs[ i ]->ubProfile != bException ) + { + gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.ubQuestsHandled++; + + if ( bExpReward > 0 && gGameExternalOptions.usAwardSpecialExpForQuests > 0 ) + StatChange( MercPtrs[ i ], EXPERAMT, (bExpReward * gGameExternalOptions.usAwardSpecialExpForQuests), FALSE ); + } + } + } +} diff --git a/Strategic/Quests.h b/Strategic/Quests.h index a66ce9b1..c6b94ad5 100644 --- a/Strategic/Quests.h +++ b/Strategic/Quests.h @@ -516,6 +516,8 @@ enum Facts FACT_CONRAD_SHOULD_GO = 367, FACT_PLAYER_KILLED_BOXERS = 368, + // HEADROCK HAM 4: Seen Mobile Militia screen after having at least one mobile unit? + FACT_MOBILE_RESTRICTIONS_VIEWED = 369, } ; //** END FACTS ************************* @@ -563,6 +565,38 @@ void InitQuestEngine(); BOOLEAN LoadQuestInfoFromSavedGameFile( HWFILE hFile ); BOOLEAN SaveQuestInfoToSavedGameFile( HWFILE hFile ); +// added by SANDRO +void GiveQuestRewardPoint( INT16 sQuestSectorX, INT16 sQuestsSectorY, INT8 bExpReward, UINT8 bException ); + +extern BOOLEAN CheckNPCWounded( UINT8 ubProfileID, BOOLEAN fByPlayerOnly ); +extern BOOLEAN CheckNPCInOkayHealth( UINT8 ubProfileID ); +extern BOOLEAN CheckNPCBleeding( UINT8 ubProfileID ); +extern BOOLEAN CheckNPCWithin( UINT8 ubFirstNPC, UINT8 ubSecondNPC, UINT8 ubMaxDistance ); +extern BOOLEAN CheckGuyVisible( UINT8 ubNPC, UINT8 ubGuy ); +extern BOOLEAN CheckNPCAt( UINT8 ubNPC, INT32 sGridNo ); +extern BOOLEAN CheckNPCIsEnemy( UINT8 ubProfileID ); +extern BOOLEAN CheckIfMercIsNearNPC( SOLDIERTYPE *pMerc, UINT8 ubProfileId ); +extern INT8 NumWoundedMercsNearby( UINT8 ubProfileID ); +extern INT8 NumMercsNear( UINT8 ubProfileID, UINT8 ubMaxDist ); +extern BOOLEAN CheckNPCIsEPC( UINT8 ubProfileID ); +extern BOOLEAN NPCInRoom( UINT8 ubProfileID, UINT8 ubRoomID ); +extern BOOLEAN NPCInRoomRange( UINT8 ubProfileID, UINT8 ubRoomID1, UINT8 ubRoomID2 ); +extern BOOLEAN PCInSameRoom( UINT8 ubProfileID ); +extern INT8 NumMalesPresent( UINT8 ubProfileID ); +extern BOOLEAN FemalePresent( UINT8 ubProfileID ); +extern BOOLEAN CheckPlayerHasHead( void ); +extern BOOLEAN CheckNPCSector( UINT8 ubProfileID, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ); +extern BOOLEAN AIMMercWithin( INT32 sGridNo, INT16 sDistance ); +extern BOOLEAN CheckNPCCowering( UINT8 ubProfileID ); +extern BOOLEAN CheckNPCIsUnderFire( UINT8 ubProfileID ); +extern BOOLEAN NPCHeardShot( UINT8 ubProfileID ); +extern BOOLEAN InTownSectorWithTrainingLoyalty( INT16 sSectorX, INT16 sSectorY ); +extern BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID ); +extern BOOLEAN CheckNPCIsRPC( UINT8 ubProfileID ); +extern BOOLEAN CheckTalkerStrong( void ); +extern BOOLEAN CheckForNewShipment( void ); +extern BOOLEAN CheckTalkerFemale( void ); +extern BOOLEAN CheckTalkerUnpropositionedFemale( void ); #endif diff --git a/Strategic/Reinforcement.cpp b/Strategic/Reinforcement.cpp index f92f2fe4..26c9f0ad 100644 --- a/Strategic/Reinforcement.cpp +++ b/Strategic/Reinforcement.cpp @@ -263,6 +263,7 @@ UINT8 DoReinforcementAsPendingEnemy( INT16 sMapX, INT16 sMapY ) gfPendingEnemies = TRUE; ResetMortarsOnTeamCount(); + ResetNumSquadleadersInArmyGroup(); // added by SANDRO } } @@ -385,7 +386,7 @@ void AddPossiblePendingMilitiaToBattle() // Haydent if (is_networked) { - if ((is_client && !is_server) || MILITIA_ENABLED==0) + if ((is_client && !is_server) || gMilitiaEnabled == 0) { return; } diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 85624224..965ab249 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -628,10 +628,12 @@ BOOLEAN PlayerForceTooStrong( UINT8 ubSectorID, UINT16 usOffensePoints, UINT16 * ubSectorY = (UINT8)SECTORY( ubSectorID ); pSector = &SectorInfo[ ubSectorID ]; - *pusDefencePoints = pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] * 1 + - pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] * 2 + - pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] * 3 + - PlayerMercsInSector( ubSectorX, ubSectorY, 0 ) * 5; + // SANDRO - EVALUATE THE STRENGTH OF MILITIA BASED ON INI SETTING + *pusDefencePoints = PlayerMercsInSector( ubSectorX, ubSectorY, 0 ) * 5; + *pusDefencePoints += (pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] * 1 * (100 + gGameExternalOptions.sGreenMilitiaAutoresolveStrength )/100); + *pusDefencePoints += (pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] * 2 * (100 + gGameExternalOptions.sRegularMilitiaAutoresolveStrength)/100); + *pusDefencePoints += (pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] * 3 * (100 + gGameExternalOptions.sVeteranMilitiaAutoresolveStrength)/100); + if( *pusDefencePoints > usOffensePoints ) { return TRUE; @@ -1513,18 +1515,116 @@ void InitStrategicAI() //final thing to do is choose 1 cache map out of 5 possible maps. Simply select the sector randomly, //set up the flags to use the alternate map, then place 8-12 regular troops there (no ai though). //changing MAX_STRATEGIC_TEAM_SIZE may require changes to to the defending force here. - if ( !gGameExternalOptions.fEnableAllWeaponCaches ) + if ( !gGameOptions.fEnableAllWeaponCaches ) // SANDRO - weapon caches settings changed { - switch( Random( 5 ) ) + // added a chance to have more than one weapon caches in game + INT8 ubPicked[2] = { 0,0 }; + UINT8 cnt, cnt2, ubNumberCaches, ubSector; + + ubNumberCaches = ( Chance( 50 ) ? (Chance( 25 ) ? 3 : 2 ) : 1); + cnt2 = 0; + + for (cnt = 0; cnt < ubNumberCaches; cnt++) { - case 0: pSector = &SectorInfo[ SEC_E11 ]; break; - case 1: pSector = &SectorInfo[ SEC_H5 ]; break; - case 2: pSector = &SectorInfo[ SEC_H10 ]; break; - case 3: pSector = &SectorInfo[ SEC_J12 ]; break; - case 4: pSector = &SectorInfo[ SEC_M9 ]; break; + ubSector = (1 + Random ( 5 )); + switch( ubSector ) + { + case 1: + if( ubPicked[0] != ubSector && ubPicked[1] != ubSector ) + { + pSector = &SectorInfo[ SEC_E11 ]; + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + pSector->ubNumTroops = (UINT8)(6 + gGameOptions.ubDifficultyLevel * 2); + if (ubPicked[0] == 0) + ubPicked[0] = ubSector; + else if (ubPicked[1] == 0) + ubPicked[1] = ubSector; + else + cnt2 += 25; + } + else + { + cnt--; + } + break; + case 2: + if( ubPicked[0] != ubSector && ubPicked[1] != ubSector ) + { + pSector = &SectorInfo[ SEC_H5 ]; + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + pSector->ubNumTroops = (UINT8)(6 + gGameOptions.ubDifficultyLevel * 2); + if (ubPicked[0] == 0) + ubPicked[0] = ubSector; + else if (ubPicked[1] == 0) + ubPicked[1] = ubSector; + else + cnt2 += 25; + } + else + { + cnt--; + } + break; + case 3: + if( ubPicked[0] != ubSector && ubPicked[1] != ubSector ) + { + pSector = &SectorInfo[ SEC_H10 ]; + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + pSector->ubNumTroops = (UINT8)(6 + gGameOptions.ubDifficultyLevel * 2); + if (ubPicked[0] == 0) + ubPicked[0] = ubSector; + else if (ubPicked[1] == 0) + ubPicked[1] = ubSector; + else + cnt2 += 25; + } + else + { + cnt--; + } + break; + case 4: + if( ubPicked[0] != ubSector && ubPicked[1] != ubSector ) + { + pSector = &SectorInfo[ SEC_J12 ]; + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + pSector->ubNumTroops = (UINT8)(6 + gGameOptions.ubDifficultyLevel * 2); + if (ubPicked[0] == 0) + ubPicked[0] = ubSector; + else if (ubPicked[1] == 0) + ubPicked[1] = ubSector; + else + cnt2 += 25; + } + else + { + cnt--; + } + break; + case 5: + if( ubPicked[0] != ubSector && ubPicked[1] != ubSector ) + { + pSector = &SectorInfo[ SEC_M9 ]; + pSector->uiFlags |= SF_USE_ALTERNATE_MAP; + pSector->ubNumTroops = (UINT8)(6 + gGameOptions.ubDifficultyLevel * 2); + if (ubPicked[0] == 0) + ubPicked[0] = ubSector; + else if (ubPicked[1] == 0) + ubPicked[1] = ubSector; + else + cnt2 += 25; + } + else + { + cnt--; + } + break; + } + + cnt2++; + if (cnt2 > 25) + break; } - pSector->uiFlags |= SF_USE_ALTERNATE_MAP; - pSector->ubNumTroops = (UINT8)(6 + gGameOptions.ubDifficultyLevel * 2); } else { @@ -1959,10 +2059,12 @@ BOOLEAN ReinforcementsApproved( INT32 iGarrisonID, UINT16 *pusDefencePoints ) ubSectorX = (UINT8)SECTORX( gGarrisonGroup[ iGarrisonID ].ubSectorID ); ubSectorY = (UINT8)SECTORY( gGarrisonGroup[ iGarrisonID ].ubSectorID ); - *pusDefencePoints = pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] * 1 + - pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] * 2 + - pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] * 3 + - PlayerMercsInSector( ubSectorX, ubSectorY, 0 ) * 4; + // SANDRO - EVALUATE THE MILITIA STRENGTH REGARDING THE GAME SETTINGS + *pusDefencePoints = PlayerMercsInSector( ubSectorX, ubSectorY, 0 ) * 5; + *pusDefencePoints += (pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] * 1 * (100 + gGameExternalOptions.sGreenMilitiaAutoresolveStrength )/100); + *pusDefencePoints += (pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] * 2 * (100 + gGameExternalOptions.sRegularMilitiaAutoresolveStrength)/100); + *pusDefencePoints += (pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] * 3 * (100 + gGameExternalOptions.sVeteranMilitiaAutoresolveStrength)/100); + usOffensePoints = gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bAdminPercentage * 2 + gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bTroopPercentage * 3 + gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bElitePercentage * 4 + @@ -4553,10 +4655,15 @@ void HourlyCheckStrategicAI() #ifdef JA2BETAVERSION -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" +#include "sgp_logger.h" -static CLog& s_stratD = *CLog::create(L"Strategic Decisions.txt", true); +static struct StratDecLog { + sgp::Logger_ID id; + StratDecLog() { + id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(id, L"Strategic Decisions.txt", false, sgp::Logger::FLUSH_ON_DELETE); + } +} s_stratD; void LogStrategicMsg( STR8 str, ... ) { @@ -4576,7 +4683,7 @@ void LogStrategicMsg( STR8 str, ... ) #ifndef USE_VFS fprintf( fp, "%s\n", string ); #else - s_stratD << string << CLog::ENDL; + SGP_LOG(s_stratD.id, string); #endif if( gfDisplayStrategicAILogs ) @@ -4612,7 +4719,7 @@ void LogStrategicEvent( STR8 str, ... ) fprintf( fp, "\n%S:\n", WORLDTIMESTR ); fprintf( fp, "%s\n", string ); #else - s_stratD.endl() << WORLDTIMESTR << ":" << CLog::ENDL << string << CLog::ENDL; + SGP_LOG(s_stratD.id) << sgp::endl << WORLDTIMESTR << ":" << sgp::endl << string << sgp::endl; #endif if( gfDisplayStrategicAILogs ) { @@ -4639,7 +4746,7 @@ void ClearStrategicLog() fclose( fp ); #else - s_stratD.flush(); + SGP_LOG(s_stratD.id) << sgp::flush; #endif } #endif diff --git a/Strategic/Strategic Event Handler.cpp b/Strategic/Strategic Event Handler.cpp index 009f6cf0..abc52831 100644 --- a/Strategic/Strategic Event Handler.cpp +++ b/Strategic/Strategic Event Handler.cpp @@ -33,7 +33,9 @@ #endif #include "BobbyRMailOrder.h" +#include "Luaglobal.h" #include "connect.h" +#include "LuaInitNPCs.h" //forward declarations of common classes to eliminate includes class OBJECTTYPE; @@ -52,6 +54,8 @@ UINT32 guiPabloExtraDaysBribed = 0; UINT8 gubCambriaMedicalObjects; +extern INT8 NumMercsNear( UINT8 ubProfileID, UINT8 ubMaxDist ); + // WANNE: No more used for the new airport code //void DropOffItemsInMeduna( UINT8 ubOrderNum ); @@ -722,8 +726,10 @@ void HandleNPCSystemEvent( UINT32 uiEvent ) } break; case NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE: - //IC: - //TriggerNPCRecord( 85, 9 ); + // silversurfer: reenabled this + // but only play Brendas quote when we are near enough to hear her + if ( NumMercsNear( 85, 8 ) > 0 ) + TriggerNPCRecord( 85, 9 ); SetFactTrue( FACT_BRENDA_PATIENCE_TIMER_EXPIRED ); break; case NPC_ACTION_SET_DELAY_TILL_GIRLS_AVAILABLE: @@ -799,16 +805,25 @@ void HandleNPCSystemEvent( UINT32 uiEvent ) void HandleEarlyMorningEvents( void ) { +#ifdef LUA_STRATEGY_EVENT_HANDLER + LetLuaHandleEarlyMorningEvents(0); +#else + UINT32 cnt; UINT32 uiAmount; // loop through all *NPCs* and reset "default response used recently" flags - for (cnt = FIRST_RPC; cnt < GASTON; cnt++) + //for (cnt = FIRST_RPC; cnt < GASTON; cnt++) + for (cnt = 0; cnt < NUM_PROFILES; cnt++) { - gMercProfiles[cnt].bFriendlyOrDirectDefaultResponseUsedRecently = FALSE; - gMercProfiles[cnt].bRecruitDefaultResponseUsedRecently = FALSE; - gMercProfiles[cnt].bThreatenDefaultResponseUsedRecently = FALSE; - gMercProfiles[cnt].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_BANDAGED_TODAY); + //new profiles by Jazz + if ( gProfilesRPC[cnt].ProfilId == cnt || gProfilesNPC[cnt].ProfilId == cnt || gProfilesVehicle[cnt].ProfilId == cnt ) + { + gMercProfiles[cnt].bFriendlyOrDirectDefaultResponseUsedRecently = FALSE; + gMercProfiles[cnt].bRecruitDefaultResponseUsedRecently = FALSE; + gMercProfiles[cnt].bThreatenDefaultResponseUsedRecently = FALSE; + gMercProfiles[cnt].ubMiscFlags2 &= (~PROFILE_MISC_FLAG2_BANDAGED_TODAY); + } } // reset Father Walker's drunkenness level! gMercProfiles[ FATHER ].bNPCData = (INT8) Random( 4 ); @@ -834,8 +849,8 @@ void HandleEarlyMorningEvents( void ) if( gMercProfiles[ TONY ].ubLastDateSpokenTo > 0 && !( gWorldSectorX == 5 && gWorldSectorY == MAP_ROW_C && gbWorldSectorZ == 0 ) ) { - // San Mona C5 is not loaded so make Tony possibly not available - if (Random( 4 )) + // San Mona C5 is not loaded so make Tony possibly not availableif + if (Random( 99 ) < gGameExternalOptions.ubChanceTonyAvailable) // silversurfer/SANDRO { // Tony IS available SetFactFalse( FACT_TONY_NOT_AVAILABLE ); @@ -1026,7 +1041,7 @@ void HandleEarlyMorningEvents( void ) { CheckForMissingHospitalSupplies(); } - +#endif } void MakeCivGroupHostileOnNextSectorEntrance( UINT8 ubCivGroup ) diff --git a/Strategic/Strategic Merc Handler.cpp b/Strategic/Strategic Merc Handler.cpp index e2902a5c..a3d60fc7 100644 --- a/Strategic/Strategic Merc Handler.cpp +++ b/Strategic/Strategic Merc Handler.cpp @@ -248,7 +248,7 @@ void MercDailyUpdate() // CJC: For some personalities, reset personality quote said flag if ( pSoldier->ubProfile != NO_PROFILE ) { - switch( gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait ) + switch( gMercProfiles[ pSoldier->ubProfile ].bDisability ) { case HEAT_INTOLERANT: case CLAUSTROPHOBIC: @@ -282,7 +282,9 @@ void MercDailyUpdate() { } //if the character is an RPC - else if( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < FIRST_NPC ) + //else if( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < FIRST_NPC ) + //new profiles by Jazz + else if ( gProfilesRPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile ) { INT16 sSalary = gMercProfiles[ pSoldier->ubProfile ].sSalary; INT32 iMoneyOwedToMerc = 0; @@ -397,9 +399,11 @@ void MercDailyUpdate() } } } - - //Loop through all the profiles - for( cnt = 0; cnt < NUM_PROFILES; cnt++) + + // WANNE: Only send mails from the original 1.13 merc, and not from the wildfire merc, + // otherwise we get wrong mails cause of hardcoded Email.edt structure!!!!! + UINT16 numOriginalProfiles = 255; + for( cnt = 0; cnt < numOriginalProfiles; cnt++) { pProfile = &(gMercProfiles[ cnt ]); @@ -461,8 +465,23 @@ void MercDailyUpdate() //remove the Flag, so if the merc goes on another assignment, the player can leave an email. pProfile->ubMiscFlags3 &= ~PROFILE_MISC_FLAG3_PLAYER_LEFT_MSG_FOR_MERC_AT_AIM; - // TO DO: send E-mail to player telling him the merc has returned from an assignment - AddEmail( ( UINT8 )( iOffset + ( cnt * AIM_REPLY_LENGTH_BARRY ) ), AIM_REPLY_LENGTH_BARRY, ( UINT8 )( 6 + cnt ), GetWorldTotalMin(), -1 ); + // Read from Email.edt + if (cnt < 170) + { + // TO DO: send E-mail to player telling him the merc has returned from an assignment + AddEmail( ( UINT8 )( iOffset + ( cnt * AIM_REPLY_LENGTH_BARRY ) ), AIM_REPLY_LENGTH_BARRY, ( UINT8 )( 6 + cnt ), GetWorldTotalMin(), -1 ); + } + else + { + UINT16 iMsgLength = cnt; + UINT8 sender = cnt - 119; // SenderNameList.xml + + // Fake Barry Unger mail, but with the msgLength of the WF merc ID -> Correct in PreProcessEmail() + AddEmailWFMercLevelUp( ( UINT8 )( iOffset + 0 * AIM_REPLY_LENGTH_BARRY ), iMsgLength, sender, GetWorldTotalMin(), -1 ); + } + + // WANNE: Should we stop time compression. I don't know. + //StopTimeCompression(); } } } @@ -473,7 +492,8 @@ void MercDailyUpdate() if( IsProfileIdAnAimOrMERCMerc( (UINT8)cnt ) ) { // check to see if he goes on another assignment - if (cnt < MAX_NUMBER_MERCS) + //if (cnt < MAX_NUMBER_MERCS) + if ( gProfilesAIM[ cnt ].ProfilId == cnt ) //new profiles by Jazz { // A.I.M. merc uiChance = 2 * pProfile->bExpLevel; @@ -481,7 +501,7 @@ void MercDailyUpdate() // player has now had a chance to hire him, so he'll eligible to get killed off on another job pProfile->ubMiscFlags3 |= PROFILE_MISC_FLAG3_PLAYER_HAD_CHANCE_TO_HIRE; } - else + else if ( gProfilesMERC[ cnt ].ProfilId == cnt ) //new profiles by Jazz { // M.E.R.C. merc - very rarely get other work uiChance = 1 * pProfile->bExpLevel; @@ -493,8 +513,8 @@ void MercDailyUpdate() pProfile->ubMiscFlags3 |= PROFILE_MISC_FLAG3_PLAYER_HAD_CHANCE_TO_HIRE; } } - - if (Random(100) < uiChance) + // tais: disable mercs being on assignment + if (Random(100) < uiChance && gGameExternalOptions.fMercsOnAssignment < 2) { pProfile->bMercStatus = MERC_WORKING_ELSEWHERE; pProfile->uiDayBecomesAvailable = 1 + Random(6 + (pProfile->bExpLevel / 2) ); // 1-(6 to 11) days @@ -1098,41 +1118,178 @@ void HourlyCamouflageUpdate( void ) { if ( pSoldier->bActive ) { - // if the merc has non-zero camo, degrade it by 1% - if( ( pSoldier->bCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED) ) ) ) + // SANDRO - new Ranger trait reduces camo degrading, which replaces camouflage trait + // may be a little awkward solution with chances, but can work + if (gGameOptions.fNewTraitSystem) { - pSoldier->bCamo -= 2; - if (pSoldier->bCamo <= 0) + if( pSoldier->bCamo > 0 ) { - pSoldier->bCamo = 0; - camoWoreOff = TRUE; + if (HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + { + pSoldier->bCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->bCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + pSoldier->bCamo -= 2; + + if (pSoldier->bCamo <= 0) + { + pSoldier->bCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } + } + if( pSoldier->urbanCamo > 0 ) + { + if (HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + { + pSoldier->urbanCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->urbanCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + pSoldier->urbanCamo -= 2; + + if (pSoldier->urbanCamo <= 0) + { + pSoldier->urbanCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gUrbanCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } + } + if( pSoldier->desertCamo > 0 ) + { + if (HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + { + pSoldier->desertCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->desertCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + pSoldier->desertCamo -= 2; + + if (pSoldier->desertCamo <= 0) + { + pSoldier->desertCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gDesertCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } + } + if( pSoldier->snowCamo > 0 ) + { + if (HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + { + pSoldier->snowCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->snowCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + pSoldier->snowCamo -= 2; + + if (pSoldier->snowCamo <= 0) + { + pSoldier->snowCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gSnowCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } } } - if( ( pSoldier->urbanCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN) ) ) ) + else { - pSoldier->urbanCamo -= 2; - if (pSoldier->urbanCamo <= 0) + // if the merc has non-zero camo, degrade it by 1% + // SANDRO - different types of Camouflaged trait have been merged together + if( ( pSoldier->bCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_OT) ) ) ) { - pSoldier->urbanCamo = 0; - camoWoreOff = TRUE; + pSoldier->bCamo -= 2; + if (pSoldier->bCamo <= 0) + { + pSoldier->bCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } } - } - if( ( pSoldier->desertCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT) ) ) ) - { - pSoldier->desertCamo -= 2; - if (pSoldier->desertCamo <= 0) + if( ( pSoldier->urbanCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_OT) ) ) ) { - pSoldier->desertCamo = 0; - camoWoreOff = TRUE; + pSoldier->urbanCamo -= 2; + if (pSoldier->urbanCamo <= 0) + { + pSoldier->urbanCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gUrbanCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } } - } - if( ( pSoldier->snowCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_SNOW) ) ) ) - { - pSoldier->snowCamo -= 2; - if (pSoldier->snowCamo <= 0) + if( ( pSoldier->desertCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_OT) ) ) ) { - pSoldier->snowCamo = 0; - camoWoreOff = TRUE; + pSoldier->desertCamo -= 2; + if (pSoldier->desertCamo <= 0) + { + pSoldier->desertCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gDesertCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } + } + if( ( pSoldier->snowCamo > 0) && ( !( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_OT) ) ) ) + { + pSoldier->snowCamo -= 2; + if (pSoldier->snowCamo <= 0) + { + pSoldier->snowCamo = 0; + camoWoreOff = TRUE; + + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + //legion camo, remove camo face and create face + gCamoFace[pSoldier->ubProfile].gSnowCamoface = FALSE; + DeleteSoldierFace( pSoldier ); + pSoldier->iFaceIndex = InitSoldierFace( pSoldier ); + } + } } } @@ -1144,7 +1301,38 @@ void HourlyCamouflageUpdate( void ) pSoldier->CreateSoldierPalettes( ); } - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WORN_OFF], pSoldier->name ); + if ( pSoldier->bCamo <= 0 ) + { + gCamoFace[pSoldier->ubProfile].gCamoface = FALSE; + DeleteSoldierFace( pSoldier );// remove face + pSoldier->iFaceIndex = InitSoldierFace( pSoldier );// create new face + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_JUNGLE_WORN_OFF], pSoldier->name ); + } + else if ( pSoldier->urbanCamo <= 0 ) + { + gCamoFace[pSoldier->ubProfile].gUrbanCamoface = FALSE; + DeleteSoldierFace( pSoldier );// remove face + pSoldier->iFaceIndex = InitSoldierFace( pSoldier );// create new face + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_URBAN_WORN_OFF], pSoldier->name ); + } + else if ( pSoldier->snowCamo <= 0 ) + { + gCamoFace[pSoldier->ubProfile].gSnowCamoface = FALSE; + DeleteSoldierFace( pSoldier );// remove face + pSoldier->iFaceIndex = InitSoldierFace( pSoldier );// create new face + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_SNOW_WORN_OFF], pSoldier->name ); + } + else if ( pSoldier->desertCamo <= 0 ) + { + gCamoFace[pSoldier->ubProfile].gDesertCamoface = FALSE; + DeleteSoldierFace( pSoldier );// remove face + pSoldier->iFaceIndex = InitSoldierFace( pSoldier );// create new face + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_DESERT_WORN_OFF], pSoldier->name ); + } + + // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WORN_OFF], pSoldier->name ); + + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); camoWoreOff = FALSE; } diff --git a/Strategic/Strategic Mines LUA.cpp b/Strategic/Strategic Mines LUA.cpp new file mode 100644 index 00000000..45f1fb51 --- /dev/null +++ b/Strategic/Strategic Mines LUA.cpp @@ -0,0 +1,567 @@ +#include +#include +#include +#include + +#include "DEBUG.H" +#include "Dialogue Control.h" +#include "FileMan.h" +#include "GameSettings.h" +#include "Soldier Profile.h" +#include "strategic.h" +#include "strategicmap.h" +#include "Strategic Mines.h" +#include "Strategic Mines LUA.h" +#include "UndergroundInit.h" +#include // for CBasicException + +#include "connect.h" + +using namespace std; + +static bool locationStrToCoords(string str, INT16* x, INT16* y); + + +// global +LuaMines g_luaMines; + + +///////////////////////////////////////// +//////////////////////////////////////// + +LuaMines::LuaMines() + : m_log(L"initmines.log", false) +{ + m_L = lua_open(); + luaL_openlibs(m_L); +} + + +void LuaMines::LoadScript() +{ + char * filename = "scripts\\initmines.lua"; + UINT32 size, bytesRead; + + + HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); + + if (!file) + { + string msg("Cannot open file: "); + msg.append(filename); + m_log << msg << vfs::Log::endl; + SGP_THROW(msg); + } + + size = FileSize(filename); + vector buffer = vector(size+1); + buffer[size] = 0; + FileRead(file, &buffer[0], size, &bytesRead); + FileClose(file); + + + if (luaL_dostring(m_L, &buffer[0])) + { + string error("lua parsing error: "); + error.append(lua_tostring(m_L, -1)); + m_log << error << vfs::Log::endl; + lua_pop(m_L, 1); + SGP_THROW(error); + } + else + { + lua_getglobal(m_L, "InitializeMines"); + if (!lua_isfunction(m_L, -1)) + { + string error("missing LUA function 'InitializeMines'"); + m_log << error << vfs::Log::endl; + lua_pop(m_L, 1); + SGP_THROW(error); + } + else + m_initMinesFuncID = luaL_ref(m_L, LUA_REGISTRYINDEX); + + lua_getglobal(m_L, "InitializeHeadMiners"); + if (!lua_isfunction(m_L, -1)) + { + string error("missing LUA function 'InitializeHeadMiners'"); + m_log << error << vfs::Log::endl; + lua_pop(m_L, 1); + SGP_THROW(error); + } + else + m_initMinersFuncID = luaL_ref(m_L, LUA_REGISTRYINDEX); + + + lua_getglobal(m_L, "logging"); + if (!lua_isnil(m_L, -1) && lua_isboolean(m_L, -1) && lua_toboolean(m_L, -1)) + m_log.ToggleLogging(true); + lua_pop(m_L, 1); + } +} + + +void LuaMines::Reset() +{ + gMineStatus.clear(); + gHeadMinerData.clear(); + + // just to be sure + ShutdownStaticExternalNPCFaces(); + InitalizeStaticExternalNPCFaces(); +} + + +void LuaMines::InitMinerFaces() +{ + if (gHeadMinerData.size() > 0) + { + for (vector::iterator miner = gHeadMinerData.begin(); + miner != gHeadMinerData.end(); ++miner) + { + // load external face + UINT32 extFaceIndex = static_cast( + InitFace(static_cast(miner->usProfileId), NOBODY, FACE_FORCE_SMALL) ); + if (extFaceIndex != -1) + { + miner->ubExternalFaceIndex = uiExternalStaticNPCFaces.size(); + uiExternalStaticNPCFaces.push_back(extFaceIndex); + } + else + miner->ubExternalFaceIndex = -1; + } + } +} + + +void LuaMines::InitializeMines() +{ + Reset(); + + m_log << "Calling 'InitializeMines'" << vfs::Log::endl; + + // WANNE: Init mines in a multiplayer game, only if we already received the server game difficulty level (ubDifficultyLevel > 0)!! + // set global, maybe pass as parameter instead? + if (!is_networked || gGameOptions.ubDifficultyLevel > 0) + { + AssertT(gGameOptions.ubDifficultyLevel > 0); + lua_pushinteger(m_L, gGameOptions.ubDifficultyLevel); + + lua_setglobal(m_L, "newDIFFICULTY_LEVEL"); + m_log << "global newDIFFICULTY_LEVEL=" << static_cast(gGameOptions.ubDifficultyLevel) << vfs::Log::endl; + + // quick fix for ini override option + lua_pushinteger(m_L, gGameExternalOptions.bWhichMineRunsOut); + lua_setglobal(m_L, "iniWHICH_MINE_SHUTS_DOWN"); + m_log << "global iniWHICH_MINE_SHUTS_DOWN=" << static_cast(gGameExternalOptions.bWhichMineRunsOut) << vfs::Log::endl; + + + // load and call lua function + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_initMinesFuncID); + if (lua_pcall(m_L, 0, 1, 0) != 0) + { + string error(lua_tostring(m_L, -1)); + lua_pop(m_L, 1); + SGP_THROW(error); + } + + + // The script is supposed to return an array of tables. + // Iterate over each table. + int currentTable = 1; // first table, lua indexing is 1-based + while (1) + { + MINE_STATUS_TYPE mineStatus = MINE_STATUS_TYPE(); + + // load table + lua_pushinteger(m_L, currentTable); + lua_gettable(m_L, -2); + + if (lua_isnil(m_L, -1)) + // done, no more tables + break; + + + lua_getfield(m_L, -1, "Location"); + string loc = lua_tostring(m_L, -1); + lua_pop(m_L, 1); + + lua_getfield(m_L, -1, "Type"); + mineStatus.ubMineType = lua_tointeger(m_L, -1); + lua_pop(m_L, 1); + + lua_getfield(m_L, -1, "MaxRemovalRate"); + mineStatus.uiMaxRemovalRate = lua_tointeger(m_L, -1); + lua_pop(m_L, 1); + + lua_getfield(m_L, -1, "RemainingOreSupply"); + mineStatus.uiRemainingOreSupply = lua_tointeger(m_L, -1); + lua_pop(m_L, 1); + + lua_getfield(m_L, -1, "Infectible"); + mineStatus.fInfectible = lua_tointeger(m_L, -1) != 0; + lua_pop(m_L, 1); + + + lua_getfield(m_L, -1, "AssociatedUnderground"); + if (!lua_isnil(m_L, -1)) + { + // again, this field is a table/array + int currentSubTable = 1; // first lua index + while (1) + { + // get next array element + lua_pushinteger(m_L, currentSubTable); + lua_gettable(m_L, -2); + if (lua_isnil(m_L, -1)) + // done + break; + string str(lua_tostring(m_L, -1)); + + AssociatedMineSector sector; + if (locationStringToCoordinates(str, §or.x, §or.y, §or.z)) + { + sector.mineID = gMineStatus.size(); + associatedMineSectors.push_back(sector); + } + + lua_pop(m_L, 1); + currentSubTable++; + } + lua_pop(m_L, 1); // pop nil + } + lua_pop(m_L, 1); // pop field or nil value + + + if (locationStrToCoords(loc, &mineStatus.sSectorX, &mineStatus.sSectorY)) + { + // valid location, add new mine + mineStatus.fEmpty = mineStatus.uiMaxRemovalRate == 0; + mineStatus.fRunningOut = FALSE; + mineStatus.fWarnedOfRunningOut = FALSE; + mineStatus.fShutDown = FALSE; + mineStatus.fPrevInvadedByMonsters = FALSE; + mineStatus.fSpokeToHeadMiner = FALSE; + mineStatus.fMineHasProducedForPlayer = FALSE; + mineStatus.fQueenRetookProducingMine = FALSE; + mineStatus.fShutDownIsPermanent = FALSE; + + // this was usually set to 0 except for the mine that is supposed to + // be running out (in which case the calculation below applies) + // TODO: see if this works for all mines + mineStatus.uiOreRunningOutPoint = mineStatus.uiRemainingOreSupply / 4; + + // gather associated town id from sector coordinates + int index = CALCULATE_STRATEGIC_INDEX(mineStatus.sSectorX, mineStatus.sSectorY); + mineStatus.bAssociatedTown = StrategicMap[index].bNameId; + + gMineStatus.push_back(mineStatus); + + // log + m_log << "create mine" << vfs::Log::endl; + m_log << "\tSector: " << string(1, 'A'-1+mineStatus.sSectorY) << mineStatus.sSectorX << vfs::Log::endl; + m_log << "\tType: " << (mineStatus.ubMineType ? "gold" : "silver") << vfs::Log::endl; + m_log << "\tMaxRemovalRate: " << mineStatus.uiMaxRemovalRate << vfs::Log::endl; + m_log << "\tRemainingOreSupply: " << mineStatus.uiRemainingOreSupply << vfs::Log::endl; + m_log << "\tOreRunningOutPoint: " << mineStatus.uiOreRunningOutPoint << vfs::Log::endl; + m_log << "\tInfectible: " << (mineStatus.fInfectible ? 1 : 0 ) << vfs::Log::endl; + } + else + { + m_log << "WARNING: not creating mine #" << currentTable << " due to bad location string (" + << loc << ")" << vfs::Log::endl; + } + + lua_pop(m_L, 1); // pop this table + currentTable++; + } + + // update global + MAX_NUMBER_OF_MINES = gMineStatus.size(); + + + lua_pop(m_L, 1); // pop nil value + + + lua_pop(m_L, 1); // pop return value + } +} + + +BOOLEAN LuaMines::InitializeHeadMiners(UINT8 firstMineID) +{ + m_log << vfs::Log::endl; + m_log << "Calling 'InitializeHeadMiners'" << vfs::Log::endl; + + lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_initMinersFuncID); + + m_log << "parameter 1 ('mines')" << vfs::Log::endl; + // push parameters + lua_newtable(m_L); + for (size_t i = 0; i < gMineStatus.size(); i++) + { + int luaIndex = i + 1; + lua_pushnumber(m_L, luaIndex); + + m_log << "\tindex #" << luaIndex << ": "; + + lua_newtable(m_L); + { + MINE_STATUS_TYPE& mine = gMineStatus[i]; + lua_pushstring(m_L, "MaxRemovalRate"); + lua_pushinteger(m_L, mine.uiMaxRemovalRate); + + m_log << "\t\tMaxRemovalRate:" << mine.uiMaxRemovalRate << vfs::Log::endl; + + lua_settable(m_L, -3); + } + lua_settable(m_L, -3); + } + + // add 1 due to lua indexing starting at 1 + int luaFirstMine = firstMineID + 1; + lua_pushnumber(m_L, luaFirstMine); + m_log << "parameter 2 ('currentMine'): " << luaFirstMine << vfs::Log::endl; + + if (lua_pcall(m_L, 2, 1, 0) != 0) + { + string error(lua_tostring(m_L, -1)); + lua_pop(m_L, 1); + SGP_THROW(error); + } + + if (lua_isnil(m_L, -1)) + { + // lua script did not initialize head miners yet + lua_pop(m_L, 1); // pop return value (nil) + m_log << "script returned nil" << vfs::Log::endl; + return FALSE; + } + + // The script is supposed to return an array of tables. + // Iterate over each element. + int currentTable = 1; + while (1) + { + HEAD_MINER_TYPE headMiner; + + // get this element of result array + lua_pushinteger(m_L, currentTable); + lua_gettable(m_L, -2); + + if (lua_isnil(m_L, -1)) + // done, no more elements in result + break; + + + lua_getfield(m_L, -1, "Profile"); + headMiner.usProfileId = lua_tointeger(m_L, -1); + lua_pop(m_L, 1); + + + lua_getfield(m_L, -1, "Quotes"); + INT8 quotes[4] = { -1, -1, -1, -1 }; + for (int quoteIndex = 0; quoteIndex < 4; quoteIndex++) + { + lua_pushinteger(m_L, quoteIndex+1); // 1-based lua index + lua_gettable(m_L, -2); + + if (lua_isnil(m_L, -1)) + { + // not enough quote ids, issue warning? + lua_pop(m_L, 1); // pop nil + break; + } + quotes[quoteIndex] = lua_tointeger(m_L, -1); + lua_pop(m_L, 1); + } + memcpy(headMiner.bQuoteNum, quotes, 4); + lua_pop(m_L, 1); // pop quotes array + + + int mineId = -1; + lua_getfield(m_L, -1, "MineID"); + if (!lua_isnil(m_L, -1)) + mineId = lua_tointeger(m_L, -1) - 1; // lua is 1-based, convert to 0-based + lua_pop(m_L, 1); + + + if (mineId > -1 && mineId < int(gMineStatus.size())) + { + MINE_STATUS_TYPE* mine = &gMineStatus[mineId]; + MERCPROFILESTRUCT* minerProfile = &gMercProfiles[headMiner.usProfileId]; + + // place miner + minerProfile->bTown = mine->bAssociatedTown; + minerProfile->sSectorX = mine->sSectorX; + minerProfile->sSectorY = mine->sSectorY; + minerProfile->bSectorZ = 0; + + gHeadMinerData.push_back(headMiner); + + // log + m_log << "create miner" << vfs::Log::endl; + m_log << "\tProfileID: " << headMiner.usProfileId << vfs::Log::endl; + m_log << "\tQuotes:"; + for (int i = 0; i < 4; i++) + m_log << " " << headMiner.bQuoteNum[i]; + m_log << vfs::Log::endl; + m_log << "\tMineID: " << mineId << vfs::Log::endl; + m_log << "\tAssociated Town: " << minerProfile->bTown << vfs::Log::endl; + m_log << "\tSector: " << string(1, 'A'-1+minerProfile->sSectorY) << minerProfile->sSectorX << vfs::Log::endl; + } + else + { + m_log << "WARNING: not creating miner #" << currentTable << " due to illegal mine id (" << mineId << ")" << vfs::Log::endl; + } + + lua_pop(m_L, 1); // pop current element of result table + currentTable++; + } + + lua_pop(m_L, 1); // pop nil value + + lua_pop(m_L, 1); // pop return value + + InitMinerFaces(); + + // update global + NUM_HEAD_MINERS = gHeadMinerData.size(); + + return TRUE; +} + +LuaMines::~LuaMines() +{ + lua_close(m_L); +} + +BOOLEAN LuaMines::Load(HWFILE hFile) +{ + Reset(); + + UINT32 uiNumBytesRead; + INT32 numMines; + MINE_STATUS_TYPE mineStatus; + + gMineStatus.clear(); + FileRead(hFile, &numMines, sizeof(INT32), &uiNumBytesRead); + if (uiNumBytesRead != sizeof(INT32)) + return FALSE; + + for (int i = 0; i < numMines; i++) + { + FileRead(hFile, &mineStatus, sizeof(MINE_STATUS_TYPE), &uiNumBytesRead); + if (uiNumBytesRead != sizeof(MINE_STATUS_TYPE)) + return FALSE; + gMineStatus.push_back(mineStatus); + } + + MAX_NUMBER_OF_MINES = gMineStatus.size(); + + + INT32 numSectors; + AssociatedMineSector sector; + associatedMineSectors.clear(); + FileRead(hFile, &numSectors, sizeof(INT32), &uiNumBytesRead); + if (uiNumBytesRead != sizeof(INT32)) + return FALSE; + for (int i = 0; i < numSectors; i++) + { + FileRead(hFile, §or, sizeof(AssociatedMineSector), &uiNumBytesRead); + if (uiNumBytesRead != sizeof(AssociatedMineSector)) + return FALSE; + associatedMineSectors.push_back(sector); + } + + + INT32 numHeadMiners; + HEAD_MINER_TYPE miner; + gHeadMinerData.clear(); + FileRead(hFile, &numHeadMiners, sizeof(INT32), &uiNumBytesRead); + if (uiNumBytesRead != sizeof(INT32)) + return FALSE; + for (int i = 0; i < numHeadMiners; i++) + { + FileRead(hFile, &miner, sizeof(HEAD_MINER_TYPE), &uiNumBytesRead); + if (uiNumBytesRead != sizeof(HEAD_MINER_TYPE)) + return FALSE; + gHeadMinerData.push_back(miner); + } + NUM_HEAD_MINERS = gHeadMinerData.size(); + + InitMinerFaces(); + + return TRUE; +} + +BOOLEAN LuaMines::Save(HWFILE hFile) +{ + UINT32 uiNumBytesWritten; + INT32 numMines = gMineStatus.size(); + + FileWrite(hFile, &numMines, sizeof(INT32), &uiNumBytesWritten); + if (uiNumBytesWritten != sizeof(INT32)) + return FALSE; + + for (std::vector::iterator it = gMineStatus.begin(); + it != gMineStatus.end(); ++it) + { + FileWrite(hFile, &*it, sizeof(MINE_STATUS_TYPE), &uiNumBytesWritten); + if (uiNumBytesWritten != sizeof(MINE_STATUS_TYPE)) + return FALSE; + } + + + INT32 numSectors = associatedMineSectors.size(); + FileWrite(hFile, &numSectors, sizeof(INT32), &uiNumBytesWritten); + if (uiNumBytesWritten != sizeof(INT32)) + return FALSE; + + for (std::vector::iterator it = associatedMineSectors.begin(); + it != associatedMineSectors.end(); ++it) + { + FileWrite(hFile, &*it, sizeof(AssociatedMineSector), &uiNumBytesWritten); + if (uiNumBytesWritten != sizeof(AssociatedMineSector)) + return FALSE; + } + + + INT32 numMiners = gHeadMinerData.size(); + FileWrite(hFile, &numMiners, sizeof(INT32), &uiNumBytesWritten); + if (uiNumBytesWritten != sizeof(INT32)) + return FALSE; + + for (std::vector::iterator it = gHeadMinerData.begin(); + it != gHeadMinerData.end(); ++it) + { + FileWrite(hFile, &*it, sizeof(HEAD_MINER_TYPE), &uiNumBytesWritten); + if (uiNumBytesWritten != sizeof(HEAD_MINER_TYPE)) + return FALSE; + } + + return TRUE; +} + +/////////////////////////////////////////// +////////////////////////////////////////////// + +static bool locationStrToCoords(string str, INT16* x, INT16* y) +{ + if (str.length() < 2 || str.length() > 3) + return false; + + char yy = tolower(str[0]); + if (yy < 'a' || yy > 'p') + return false; + *y = yy - 'a' + 1; + + str = str.substr(1); + stringstream ss; + ss << str; + ss >> *x; + if (*x < 1 || *x > 16) + return false; + + return true; +} diff --git a/Strategic/Strategic Mines LUA.h b/Strategic/Strategic Mines LUA.h new file mode 100644 index 00000000..ff1f129f --- /dev/null +++ b/Strategic/Strategic Mines LUA.h @@ -0,0 +1,66 @@ +#ifndef STRATEGIC_MINES_LUA_H +#define STRATEGIC_MINES_LUA_H + +#include "Types.h" + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +} + +#include "UndergroundInit.h" + +//#include +//class LuaLogger +//{ +// bool m_active; +// vfs::Log& m_log; +// +//public: +// enum LoggingState +// { +// OFF, +// ON, +// }; +// +// LuaLogger(const vfs::Path filename, bool enable = true, bool append = false, vfs::Log::EFlushMode flushMode = vfs::Log::FLUSH_ON_ENDL) +// : m_log(*vfs::Log::create(filename, append, flushMode)), m_active(enable) {} +// ~LuaLogger() { Flush(); } +// void ToggleLogging(bool enable) { m_active = enable; } +// void Flush() { m_log.flush(); } +// +// template LuaLogger& operator<<(const T& message) { if (m_active) m_log << message; return *this; } +// template <> LuaLogger& operator<<(const vfs::Log::_endl& endl) { if (m_active) m_log << vfs::Log::endl; return *this; } +// template <> LuaLogger& operator<<(const LoggingState& state) { m_active = state == ON; return *this; } +// +//}; + +class LuaMines +{ +public: + void LoadScript(); + void InitializeMines(); + BOOLEAN InitializeHeadMiners(UINT8 firstMineID); + + BOOLEAN Save(HWFILE hFile); + BOOLEAN Load(HWFILE hFile); + + LuaMines(); + virtual ~LuaMines(); + +private: + void Reset(); + void InitMinerFaces(); + + int m_initMinesFuncID; + int m_initMinersFuncID; + lua_State * m_L; + + LuaLogger m_log; +}; + +extern LuaMines g_luaMines; + + +#endif diff --git a/Strategic/Strategic Mines.cpp b/Strategic/Strategic Mines.cpp index 86a146a5..c90bd552 100644 --- a/Strategic/Strategic Mines.cpp +++ b/Strategic/Strategic Mines.cpp @@ -24,6 +24,8 @@ #include "Facilities.h" #endif +#include "Strategic Mines LUA.h" +#include // this .c file will handle the strategic level of mines and income from them @@ -63,49 +65,53 @@ INT32 GetCurrentWorkRateOfMineForEnemy( INT8 bMineIndex ); // DATA TABLES // this table holds mine values that change during the course of the game and must be saved -MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ]; +//MINE_STATUS_TYPE gMineStatus[ MAX_NUMBER_OF_MINES ]; +std::vector gMineStatus; +INT32 MAX_NUMBER_OF_MINES; // equals gMineStatus.size() +std::vector associatedMineSectors; // this table holds mine values that never change and don't need to be saved -MINE_LOCATION_TYPE gMineLocation[MAX_NUMBER_OF_MINES] = -{ - { 4, 4, SAN_MONA }, - { 13, 4, DRASSEN }, - { 14, 9, ALMA }, - { 8, 8, CAMBRIA }, - { 2, 2, CHITZENA }, - { 3, 8, GRUMM }, -}; +//MINE_LOCATION_TYPE gMineLocation[MAX_NUMBER_OF_MINES] = +//{ +// { 4, 4, SAN_MONA }, +// { 13, 4, DRASSEN }, +// { 14, 9, ALMA }, +// { 8, 8, CAMBRIA }, +// { 2, 2, CHITZENA }, +// { 3, 8, GRUMM }, +//}; // the are not being randomized at all at this time -UINT8 gubMineTypes[]={ - GOLD_MINE, // SAN MONA - SILVER_MINE, // DRASSEN - SILVER_MINE, // ALMA - SILVER_MINE, // CAMBRIA - SILVER_MINE, // CHITZENA - GOLD_MINE, // GRUMM -}; +//UINT8 gubMineTypes[]={ +// GOLD_MINE, // SAN MONA +// SILVER_MINE, // DRASSEN +// SILVER_MINE, // ALMA +// SILVER_MINE, // CAMBRIA +// SILVER_MINE, // CHITZENA +// GOLD_MINE, // GRUMM +//}; // These values also determine the most likely ratios of mine sizes after random production increases are done -UINT32 guiMinimumMineProduction[]={ - 0, // SAN MONA - 1000, // DRASSEN - 1500, // ALMA - 1500, // CAMBRIA - 500, // CHITZENA - 2000, // GRUMM -}; +//UINT32 guiMinimumMineProduction[]={ +// 0, // SAN MONA +// 1000, // DRASSEN +// 1500, // ALMA +// 1500, // CAMBRIA +// 500, // CHITZENA +// 2000, // GRUMM +//}; - -HEAD_MINER_TYPE gHeadMinerData[NUM_HEAD_MINERS] = -{ - // Profile # running out creatures! all dead! creatures again! external face graphic - { FRED, 17, 18, 27, 26, MINER_FRED_EXTERNAL_FACE }, - { MATT, -1, 18, 32, 31, MINER_MATT_EXTERNAL_FACE }, - { OSWALD, 14, 15, 24, 23, MINER_OSWALD_EXTERNAL_FACE }, - { CALVIN, 14, 15, 24, 23, MINER_CALVIN_EXTERNAL_FACE }, - { CARL, 14, 15, 24, 23, MINER_CARL_EXTERNAL_FACE }, -}; +std::vector gHeadMinerData; +INT32 NUM_HEAD_MINERS; // equals gHeadMinerData.size() +//HEAD_MINER_TYPE gHeadMinerData[NUM_HEAD_MINERS] = +//{ +// // Profile # running out creatures! all dead! creatures again! external face graphic +// { FRED, 17, 18, 27, 26, MINER_FRED_EXTERNAL_FACE }, +// { MATT, -1, 18, 32, 31, MINER_MATT_EXTERNAL_FACE }, +// { OSWALD, 14, 15, 24, 23, MINER_OSWALD_EXTERNAL_FACE }, +// { CALVIN, 14, 15, 24, 23, MINER_CALVIN_EXTERNAL_FACE }, +// { CARL, 14, 15, 24, 23, MINER_CARL_EXTERNAL_FACE }, +//}; @@ -124,7 +130,7 @@ UINT8 gubMonsterMineInfestation[]={ */ // the static NPC dialogue faces -extern UINT32 uiExternalStaticNPCFaces[]; +//extern UINT32 uiExternalStaticNPCFaces[]; extern FACETYPE *gpCurrentTalkingFace; extern UINT8 gubCurrentTalkingID; @@ -132,6 +138,9 @@ extern UINT8 gubCurrentTalkingID; void InitializeMines( void ) { + // Don't execute hardcoded logic. Leave initialization to the Lua script. + g_luaMines.InitializeMines(); +#if 0 UINT8 ubMineIndex; MINE_STATUS_TYPE *pMineStatus; UINT8 ubMineProductionIncreases; @@ -250,6 +259,7 @@ void InitializeMines( void ) pMineStatus->uiOreRunningOutPoint = 0; } } +#endif } @@ -316,7 +326,8 @@ void HourlyMinesUpdate(void) if ( gubQuest[ QUEST_CREATURES ] == QUESTNOTSTARTED ) { // start it now! - StartQuest( QUEST_CREATURES, gMineLocation[ ubMineIndex ].sSectorX, gMineLocation[ ubMineIndex ].sSectorY ); + //StartQuest( QUEST_CREATURES, gMineLocation[ ubMineIndex ].sSectorX, gMineLocation[ ubMineIndex ].sSectorY ); + StartQuest( QUEST_CREATURES, gMineStatus[ ubMineIndex ].sSectorX, gMineStatus[ ubMineIndex ].sSectorY ); } } @@ -392,27 +403,8 @@ INT8 GetTownAssociatedWithMine( INT8 bMineIndex ) { Assert( ( bMineIndex >= 0 ) && ( bMineIndex < MAX_NUMBER_OF_MINES ) ); - return ( gMineLocation[ bMineIndex ].bAssociatedTown ); -} - - -INT8 GetMineAssociatedWithThisTown( INT8 bTownId ) -{ - INT8 bCounter = 0; - - // run through list of mines - for( bCounter = 0; bCounter < MAX_NUMBER_OF_MINES; bCounter++ ) - { - if( gMineLocation[ bCounter ].bAssociatedTown == bTownId ) - { - // town found, return the fact - return( gMineLocation[ bCounter ].bAssociatedTown ); - } - } - - // return that no town found..a 0 - return( 0 ); - + //return ( gMineLocation[ bMineIndex ].bAssociatedTown ); + return ( gMineStatus[ bMineIndex ].bAssociatedTown ); } @@ -451,7 +443,8 @@ UINT32 ExtractOreFromMine( INT8 bMineIndex, UINT32 uiAmount ) GetMineSector( bMineIndex, &sSectorX, &sSectorY ); StrategicHandleMineThatRanOut( ( UINT8 ) SECTOR( sSectorX, sSectorY ) ); - AddHistoryToPlayersLog( HISTORY_MINE_RAN_OUT, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + //AddHistoryToPlayersLog( HISTORY_MINE_RAN_OUT, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + AddHistoryToPlayersLog( HISTORY_MINE_RAN_OUT, gMineStatus[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineStatus[ bMineIndex ].sSectorX, gMineStatus[ bMineIndex ].sSectorY ); } else // still some left after this extraction { @@ -477,7 +470,8 @@ UINT32 ExtractOreFromMine( INT8 bMineIndex, UINT32 uiAmount ) // that mine's head miner tells player that the mine is running out IssueHeadMinerQuote( bMineIndex, HEAD_MINER_STRATEGIC_QUOTE_RUNNING_OUT ); gMineStatus[ bMineIndex ].fWarnedOfRunningOut = TRUE; - AddHistoryToPlayersLog( HISTORY_MINE_RUNNING_OUT, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + //AddHistoryToPlayersLog( HISTORY_MINE_RUNNING_OUT, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + AddHistoryToPlayersLog( HISTORY_MINE_RUNNING_OUT, gMineStatus[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineStatus[ bMineIndex ].sSectorX, gMineStatus[ bMineIndex ].sSectorY ); } } } @@ -509,7 +503,8 @@ INT32 GetAvailableWorkForceForMineForPlayer( INT8 bMineIndex ) } - bTownId = gMineLocation[ bMineIndex ].bAssociatedTown; + //bTownId = gMineLocation[ bMineIndex ].bAssociatedTown; + bTownId = gMineStatus[ bMineIndex ].bAssociatedTown; Assert ( GetTownSectorSize( bTownId ) != 0 ); @@ -546,7 +541,8 @@ INT32 GetAvailableWorkForceForMineForEnemy( INT8 bMineIndex ) return ( 0 ); } - bTownId = gMineLocation[ bMineIndex ].bAssociatedTown; + //bTownId = gMineLocation[ bMineIndex ].bAssociatedTown; + bTownId = gMineStatus[ bMineIndex ].bAssociatedTown; if( GetTownSectorSize( bTownId ) == 0 ) { @@ -695,7 +691,7 @@ void HandleIncomeFromMines( void ) } -UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex ) +UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex, BOOLEAN fIncludeFacilities ) { // predict income from this mine, estimate assumes mining situation will not change during next 4 income periods // (miner loyalty, % town controlled, monster infestation level, and current max removal rate may all in fact change) @@ -714,7 +710,7 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex ) // yes reduce to value of mine uiAmtExtracted = gMineStatus[ bMineIndex ].uiRemainingOreSupply; } - if (bMineIndex) + if (bMineIndex && fIncludeFacilities) { // HEADROCK HAM 3.6: Facility modifier applied as a percentage iFacilityModifier = 100 + MineIncomeModifierFromFacility( bMineIndex ); @@ -727,7 +723,7 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex ) } -INT32 PredictIncomeFromPlayerMines( void ) +INT32 PredictIncomeFromPlayerMines( BOOLEAN fIncludeFacilities ) { INT32 iTotal = 0; INT8 bCounter = 0; @@ -735,7 +731,7 @@ INT32 PredictIncomeFromPlayerMines( void ) for( bCounter = 0; bCounter < MAX_NUMBER_OF_MINES; bCounter++ ) { // add up the total - iTotal += PredictDailyIncomeFromAMine( bCounter ); + iTotal += PredictDailyIncomeFromAMine( bCounter, fIncludeFacilities ); } return( iTotal ); @@ -768,7 +764,8 @@ INT8 GetMineIndexForSector( INT16 sX, INT16 sY ) for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ ) { - if( ( gMineLocation[ ubMineIndex ].sSectorX == sX ) && ( gMineLocation[ ubMineIndex ].sSectorY == sY ) ) + //if( ( gMineLocation[ ubMineIndex ].sSectorX == sX ) && ( gMineLocation[ ubMineIndex ].sSectorY == sY ) ) + if( ( gMineStatus[ ubMineIndex ].sSectorX == sX ) && ( gMineStatus[ ubMineIndex ].sSectorY == sY ) ) { // yep mine here return( ubMineIndex ); @@ -782,8 +779,10 @@ void GetMineSector( UINT8 ubMineIndex, INT16 * psX, INT16 * psY ) { Assert( ( ubMineIndex >= 0 ) && ( ubMineIndex < MAX_NUMBER_OF_MINES ) ); - *psX = gMineLocation[ ubMineIndex ].sSectorX; - *psY = gMineLocation[ ubMineIndex ].sSectorY; + //*psX = gMineLocation[ ubMineIndex ].sSectorX; + //*psY = gMineLocation[ ubMineIndex ].sSectorY; + *psX = gMineStatus[ ubMineIndex ].sSectorX; + *psY = gMineStatus[ ubMineIndex ].sSectorY; } @@ -795,7 +794,8 @@ INT8 GetMineIndexForTown( INT8 bTownId ) // given town id, send sector value of mine, a 0 means no mine for this town for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ ) { - if( gMineLocation[ ubMineIndex ].bAssociatedTown == bTownId ) + //if( gMineLocation[ ubMineIndex ].bAssociatedTown == bTownId ) + if( gMineStatus[ ubMineIndex ].bAssociatedTown == bTownId ) { return( ubMineIndex ); } @@ -814,9 +814,11 @@ INT16 GetMineSectorForTown( INT8 bTownId ) // given town id, send sector value of mine, a 0 means no mine for this town for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ ) { - if( gMineLocation[ ubMineIndex ].bAssociatedTown == bTownId ) + //if( gMineLocation[ ubMineIndex ].bAssociatedTown == bTownId ) + if( gMineStatus[ ubMineIndex ].bAssociatedTown == bTownId ) { - sMineSector = gMineLocation[ ubMineIndex ].sSectorX + ( gMineLocation[ ubMineIndex ].sSectorY * MAP_WORLD_X ); + //sMineSector = gMineLocation[ ubMineIndex ].sSectorX + ( gMineLocation[ ubMineIndex ].sSectorY * MAP_WORLD_X ); + sMineSector = gMineStatus[ ubMineIndex ].sSectorX + ( gMineStatus[ ubMineIndex ].sSectorY * MAP_WORLD_X ); break; } } @@ -833,7 +835,8 @@ BOOLEAN IsThereAMineInThisSector( INT16 sX, INT16 sY ) // run through the list...if a mine here, great for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ ) { - if( ( gMineLocation[ ubMineIndex ].sSectorX == sX ) && ( gMineLocation[ ubMineIndex ].sSectorY == sY ) ) + //if( ( gMineLocation[ ubMineIndex ].sSectorX == sX ) && ( gMineLocation[ ubMineIndex ].sSectorY == sY ) ) + if( ( gMineStatus[ ubMineIndex ].sSectorX == sX ) && ( gMineStatus[ ubMineIndex ].sSectorY == sY ) ) { return( TRUE ); } @@ -845,7 +848,8 @@ BOOLEAN IsThereAMineInThisSector( INT16 sX, INT16 sY ) BOOLEAN PlayerControlsMine(INT8 bMineIndex) { // a value of TRUE is from the enemy's point of view - if (StrategicMap[( gMineLocation[ bMineIndex ].sSectorX ) + ( MAP_WORLD_X * ( gMineLocation[ bMineIndex ].sSectorY ) )].fEnemyControlled == TRUE ) + //if (StrategicMap[( gMineLocation[ bMineIndex ].sSectorX ) + ( MAP_WORLD_X * ( gMineLocation[ bMineIndex ].sSectorY ) )].fEnemyControlled == TRUE ) + if (StrategicMap[( gMineStatus[ bMineIndex ].sSectorX ) + ( MAP_WORLD_X * ( gMineStatus[ bMineIndex ].sSectorY ) )].fEnemyControlled == TRUE ) return(FALSE); else { @@ -864,6 +868,9 @@ BOOLEAN PlayerControlsMine(INT8 bMineIndex) BOOLEAN SaveMineStatusToSaveGameFile( HWFILE hFile ) { + return g_luaMines.Save(hFile); + +#if 0 UINT32 uiNumBytesWritten; //Save the MineStatus @@ -874,11 +881,15 @@ BOOLEAN SaveMineStatusToSaveGameFile( HWFILE hFile ) } return( TRUE ); +#endif } BOOLEAN LoadMineStatusFromSavedGameFile( HWFILE hFile ) { + return g_luaMines.Load(hFile); + +#if 0 UINT32 uiNumBytesRead; //Load the MineStatus @@ -889,6 +900,7 @@ BOOLEAN LoadMineStatusFromSavedGameFile( HWFILE hFile ) } return( TRUE ); +#endif } @@ -899,7 +911,8 @@ void ShutOffMineProduction( INT8 bMineIndex ) if ( !gMineStatus[ bMineIndex ].fShutDown ) { gMineStatus[ bMineIndex ].fShutDown = TRUE; - AddHistoryToPlayersLog( HISTORY_MINE_SHUTDOWN, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + //AddHistoryToPlayersLog( HISTORY_MINE_SHUTDOWN, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + AddHistoryToPlayersLog( HISTORY_MINE_SHUTDOWN, gMineStatus[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineStatus[ bMineIndex ].sSectorX, gMineStatus[ bMineIndex ].sSectorY ); } } @@ -913,7 +926,8 @@ void RestartMineProduction( INT8 bMineIndex ) if ( gMineStatus[ bMineIndex ].fShutDown ) { gMineStatus[ bMineIndex ].fShutDown = FALSE; - AddHistoryToPlayersLog( HISTORY_MINE_REOPENED, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + //AddHistoryToPlayersLog( HISTORY_MINE_REOPENED, gMineLocation[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY ); + AddHistoryToPlayersLog( HISTORY_MINE_REOPENED, gMineStatus[ bMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineStatus[ bMineIndex ].sSectorX, gMineStatus[ bMineIndex ].sSectorY ); } } } @@ -948,22 +962,27 @@ UINT8 GetHeadMinerIndexForMine( INT8 bMineIndex ) { usProfileId = gHeadMinerData[ ubMinerIndex ].usProfileId; - if (gMercProfiles[ usProfileId ].bTown == gMineLocation[ bMineIndex ].bAssociatedTown) + //if (gMercProfiles[ usProfileId ].bTown == gMineLocation[ bMineIndex ].bAssociatedTown) + if (gMercProfiles[ usProfileId ].bTown == gMineStatus[ bMineIndex ].bAssociatedTown) { return(ubMinerIndex); } } // not found - yack! - Assert( FALSE ); - return( 0 ); + //Assert( FALSE ); + //return( 0 ); + + // Do not assert but use an error code instead, + // as a mod might intentionally want to not have a head miner at every mine. + return -1; } -UINT16 GetHeadMinerProfileIdForMine( INT8 bMineIndex ) -{ - return(gHeadMinerData[ GetHeadMinerIndexForMine( bMineIndex ) ].usProfileId); -} +//UINT16 GetHeadMinerProfileIdForMine( INT8 bMineIndex ) +//{ +// return(gHeadMinerData[ GetHeadMinerIndexForMine( bMineIndex ) ].usProfileId); +//} void IssueHeadMinerQuote( INT8 bMineIndex, UINT8 ubQuoteType ) @@ -981,6 +1000,8 @@ void IssueHeadMinerQuote( INT8 bMineIndex, UINT8 ubQuoteType ) Assert( CheckFact( FACT_MINERS_PLACED, 0 ) ); ubHeadMinerIndex = GetHeadMinerIndexForMine( bMineIndex ); + if (ubHeadMinerIndex == -1) + return; usHeadMinerProfileId = gHeadMinerData[ ubHeadMinerIndex ].usProfileId; // make sure the miner ain't dead @@ -992,9 +1013,11 @@ void IssueHeadMinerQuote( INT8 bMineIndex, UINT8 ubQuoteType ) } bQuoteNum = gHeadMinerData[ ubHeadMinerIndex ].bQuoteNum[ ubQuoteType ]; - Assert( bQuoteNum != -1 ); + //Assert( bQuoteNum != -1 ); + if (bQuoteNum == -1) + return; - ubFaceIndex = ( UINT8 ) uiExternalStaticNPCFaces[ gHeadMinerData[ ubHeadMinerIndex ].ubExternalFace ]; + ubFaceIndex = ( UINT8 ) uiExternalStaticNPCFaces[ gHeadMinerData[ ubHeadMinerIndex ].ubExternalFaceIndex ]; // transition to mapscreen is not necessary for "creatures gone" quote - player is IN that mine, so he'll know if ( ubQuoteType != HEAD_MINER_STRATEGIC_QUOTE_CREATURES_GONE ) @@ -1025,7 +1048,7 @@ void IssueHeadMinerQuote( INT8 bMineIndex, UINT8 ubQuoteType ) // there's no head miner in San Mona, this is an error! case MINE_SAN_MONA: default: - Assert( FALSE ); + //Assert( FALSE ); sXPos = DEFAULT_EXTERN_PANEL_X_POS, sYPos = DEFAULT_EXTERN_PANEL_Y_POS; break; } @@ -1033,7 +1056,9 @@ void IssueHeadMinerQuote( INT8 bMineIndex, UINT8 ubQuoteType ) SetExternMapscreenSpeechPanelXY( sXPos, sYPos ); // cause this quote to come up for this profile id and an indicator to flash over the mine sector - HandleMinerEvent( gHeadMinerData[ ubHeadMinerIndex ].ubExternalFace, gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY, (INT16) bQuoteNum, fForceMapscreen ); + //HandleMinerEvent( gHeadMinerData[ ubHeadMinerIndex ].ubExternalFace, gMineLocation[ bMineIndex ].sSectorX, gMineLocation[ bMineIndex ].sSectorY, (INT16) bQuoteNum, fForceMapscreen ); + //HandleMinerEvent( gHeadMinerData[ ubHeadMinerIndex ].ubExternalFace, gMineStatus[ bMineIndex ].sSectorX, gMineStatus[ bMineIndex ].sSectorY, (INT16) bQuoteNum, fForceMapscreen ); + HandleMinerEvent( ubHeadMinerIndex, gMineStatus[ bMineIndex ].sSectorX, gMineStatus[ bMineIndex ].sSectorY, (INT16) bQuoteNum, fForceMapscreen ); // stop time compression with any miner quote - these are important events. StopTimeCompression(); @@ -1047,7 +1072,8 @@ UINT8 GetHeadMinersMineIndex( UINT8 ubMinerProfileId) // find which mine this guy represents for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ ) { - if (gMineLocation[ ubMineIndex ].bAssociatedTown == gMercProfiles[ ubMinerProfileId ].bTown) + //if (gMineLocation[ ubMineIndex ].bAssociatedTown == gMercProfiles[ ubMinerProfileId ].bTown) + if (gMineStatus[ ubMineIndex ].bAssociatedTown == gMercProfiles[ ubMinerProfileId ].bTown) { return(ubMineIndex); } @@ -1068,7 +1094,8 @@ void PlayerSpokeToHeadMiner( UINT8 ubMinerProfileId ) // if this is our first time set a history fact if( gMineStatus[ ubMineIndex ].fSpokeToHeadMiner == FALSE ) { - AddHistoryToPlayersLog( HISTORY_TALKED_TO_MINER, gMineLocation[ ubMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ ubMineIndex ].sSectorX, gMineLocation[ ubMineIndex ].sSectorY ); + //AddHistoryToPlayersLog( HISTORY_TALKED_TO_MINER, gMineLocation[ ubMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineLocation[ ubMineIndex ].sSectorX, gMineLocation[ ubMineIndex ].sSectorY ); + AddHistoryToPlayersLog( HISTORY_TALKED_TO_MINER, gMineStatus[ ubMineIndex ].bAssociatedTown, GetWorldTotalMin( ), gMineStatus[ ubMineIndex ].sSectorX, gMineStatus[ ubMineIndex ].sSectorY ); gMineStatus[ ubMineIndex ].fSpokeToHeadMiner = TRUE; } } @@ -1096,7 +1123,8 @@ BOOLEAN IsHisMineDisloyal( UINT8 ubMinerProfileId ) ubMineIndex = GetHeadMinersMineIndex( ubMinerProfileId ); - if (gTownLoyalty[ gMineLocation[ ubMineIndex ].bAssociatedTown ].ubRating < LOW_MINE_LOYALTY_THRESHOLD) + //if (gTownLoyalty[ gMineLocation[ ubMineIndex ].bAssociatedTown ].ubRating < LOW_MINE_LOYALTY_THRESHOLD) + if (gTownLoyalty[ gMineStatus[ ubMineIndex ].bAssociatedTown ].ubRating < LOW_MINE_LOYALTY_THRESHOLD) { // pretty disloyal return(TRUE); @@ -1252,6 +1280,7 @@ INT8 GetIdOfMineForSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) { bMineIndex = GetMineIndexForSector( sSectorX, sSectorY ); } +#if 0 // handle for first level else if( bSectorZ == 1 ) { @@ -1300,37 +1329,47 @@ INT8 GetIdOfMineForSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) break; } } +#endif + for (std::vector::iterator it = associatedMineSectors.begin(); + it != associatedMineSectors.end(); ++it) + { + if (it->x == sSectorX && it->y == sSectorY && bSectorZ == it->z) + { + return it->mineID; + } + } - return( bMineIndex ); + return( bMineIndex ); // == -1 } // use this for miner (civilian) quotes when *underground* in a mine -BOOLEAN PlayerForgotToTakeOverMine( UINT8 ubMineIndex ) -{ - MINE_STATUS_TYPE *pMineStatus; - - - Assert( ( ubMineIndex >= 0 ) && ( ubMineIndex < MAX_NUMBER_OF_MINES ) ); - - pMineStatus = &(gMineStatus[ ubMineIndex ]); - - // mine surface sector is player controlled - // mine not empty - // player hasn't spoken to the head miner, but hasn't attacked him either - // miner is alive - if ( (StrategicMap[( gMineLocation[ ubMineIndex ].sSectorX ) + ( MAP_WORLD_X * ( gMineLocation[ ubMineIndex ].sSectorY ) )].fEnemyControlled == FALSE ) && - ( !pMineStatus->fEmpty ) && - ( !pMineStatus->fSpokeToHeadMiner ) && - ( !pMineStatus->fAttackedHeadMiner ) && - ( gMercProfiles[ GetHeadMinerProfileIdForMine( ubMineIndex ) ].bLife > 0 ) ) - { - return( TRUE ); - } - - return( FALSE ); -} +//BOOLEAN PlayerForgotToTakeOverMine( UINT8 ubMineIndex ) +//{ +// MINE_STATUS_TYPE *pMineStatus; +// +// +// Assert( ( ubMineIndex >= 0 ) && ( ubMineIndex < MAX_NUMBER_OF_MINES ) ); +// +// pMineStatus = &(gMineStatus[ ubMineIndex ]); +// +// // mine surface sector is player controlled +// // mine not empty +// // player hasn't spoken to the head miner, but hasn't attacked him either +// // miner is alive +// //if ( (StrategicMap[( gMineLocation[ ubMineIndex ].sSectorX ) + ( MAP_WORLD_X * ( gMineLocation[ ubMineIndex ].sSectorY ) )].fEnemyControlled == FALSE ) && +// if ( (StrategicMap[( gMineStatus[ ubMineIndex ].sSectorX ) + ( MAP_WORLD_X * ( gMineStatus[ ubMineIndex ].sSectorY ) )].fEnemyControlled == FALSE ) && +// ( !pMineStatus->fEmpty ) && +// ( !pMineStatus->fSpokeToHeadMiner ) && +// ( !pMineStatus->fAttackedHeadMiner ) && +// ( gMercProfiles[ GetHeadMinerProfileIdForMine( ubMineIndex ) ].bLife > 0 ) ) +// { +// return( TRUE ); +// } +// +// return( FALSE ); +//} diff --git a/Strategic/Strategic Mines.h b/Strategic/Strategic Mines.h index c2082aba..b7ad4048 100644 --- a/Strategic/Strategic Mines.h +++ b/Strategic/Strategic Mines.h @@ -4,7 +4,8 @@ // the .h to the mine management system #include "Types.h" - +#include "strategicmap.h" +#include "mapscreen.h" // the mines enum{ @@ -14,17 +15,17 @@ enum{ MINE_CAMBRIA, MINE_CHITZENA, MINE_GRUMM, - MAX_NUMBER_OF_MINES, + //MAX_NUMBER_OF_MINES, }; -enum{ - MINER_FRED = 0, - MINER_MATT, - MINER_OSWALD, - MINER_CALVIN, - MINER_CARL, - NUM_HEAD_MINERS, -}; +//enum{ +// MINER_FRED = 0, +// MINER_MATT, +// MINER_OSWALD, +// MINER_CALVIN, +// MINER_CARL, +// NUM_HEAD_MINERS, +//}; // different types of mines enum{ @@ -55,15 +56,20 @@ enum{ }; +struct AssociatedMineSector +{ + UINT8 mineID; + UINT8 x, y, z; +}; // the strategic mine structures -typedef struct MINE_LOCATION_TYPE -{ - INT16 sSectorX; // x value of sector mine is in - INT16 sSectorY; // y value of sector mine is in - INT8 bAssociatedTown; // associated town of this mine - -} MINE_LOCATION_TYPE; +//typedef struct MINE_LOCATION_TYPE +//{ +// INT16 sSectorX; // x value of sector mine is in +// INT16 sSectorY; // y value of sector mine is in +// INT8 bAssociatedTown; // associated town of this mine +// +//} MINE_LOCATION_TYPE; typedef struct MINE_STATUS_TYPE { @@ -90,16 +96,30 @@ typedef struct MINE_STATUS_TYPE BYTE filler[11]; // reserved for expansion + // merge in MINE_LOCATION_TYPE + INT16 sSectorX; // x value of sector mine is in + INT16 sSectorY; // y value of sector mine is in + INT8 bAssociatedTown; // associated town of this mine + + UINT32 StrategicIndex() { return CALCULATE_STRATEGIC_INDEX(sSectorX, sSectorY); }; + + BOOLEAN fInfectible; + } MINE_STATUS_TYPE; typedef struct HEAD_MINER_TYPE { UINT16 usProfileId; INT8 bQuoteNum[NUM_HEAD_MINER_STRATEGIC_QUOTES]; - UINT8 ubExternalFace; + UINT8 ubExternalFaceIndex; } HEAD_MINER_TYPE; +extern INT32 MAX_NUMBER_OF_MINES; +extern INT32 NUM_HEAD_MINERS; +extern std::vector gMineStatus; +extern std::vector associatedMineSectors; +extern std::vector gHeadMinerData; // init mines void InitializeMines( void ); @@ -116,9 +136,6 @@ UINT32 GetMaxDailyRemovalFromMine( INT8 bMineIndex ); // which town does this mine belong to? INT8 GetTownAssociatedWithMine( INT8 bMineIndex ); -// which mine belongs tot his town -INT8 GetMineAssociatedWithThisTown( INT8 bTownValue ); - // posts the actual mine production events daily void PostEventsForMineProduction(void); @@ -126,10 +143,10 @@ void PostEventsForMineProduction(void); void HandleIncomeFromMines( void ); // predict income from mines -INT32 PredictIncomeFromPlayerMines( void ); +INT32 PredictIncomeFromPlayerMines( BOOLEAN fIncludeFacilities ); // predict income from a mine -UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex ); +UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex, BOOLEAN fIncludeFacilities ); // calculate maximum possible daily income from all mines INT32 CalcMaxPlayerIncomeFromMines( void ); @@ -162,7 +179,7 @@ void MineShutdownIsPermanent( INT8 bMineIndex ); BOOLEAN IsMineShutDown( INT8 bMineIndex ); UINT8 GetHeadMinerIndexForMine( INT8 bMineIndex ); -UINT16 GetHeadMinerProfileIdForMine( INT8 bMineIndex ); +//UINT16 GetHeadMinerProfileIdForMine( INT8 bMineIndex ); // Find the sector location of a mine void GetMineSector( UINT8 ubMineIndex, INT16 * psX, INT16 * psY ); @@ -193,7 +210,7 @@ BOOLEAN HasHisMineBeenProducingForPlayerForSomeTime( UINT8 ubMinerProfileId ); INT8 GetIdOfMineForSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ); // use this for miner (civilian) quotes when *underground* in a mine -BOOLEAN PlayerForgotToTakeOverMine( UINT8 ubMineIndex ); +//BOOLEAN PlayerForgotToTakeOverMine( UINT8 ubMineIndex ); // use this to determine whether or not to place miners into a underground mine level BOOLEAN AreThereMinersInsideThisMine( UINT8 ubMineIndex ); diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index 8876e324..15cef762 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -71,10 +71,9 @@ GROUP *gpPendingSimultaneousGroup = NULL; extern BOOLEAN fMapScreenBottomDirty; extern BOOLEAN gfUsePersistantPBI; -#ifdef JA2BETAVERSION - extern BOOLEAN gfExitViewer; - void ValidateGroups( GROUP *pGroup ); -#endif +extern BOOLEAN gfExitViewer; +BOOLEAN ValidateGroups( GROUP *pGroup ); + extern BOOLEAN gubNumAwareBattles; extern INT8 SquadMovementGroups[ ]; @@ -1168,9 +1167,11 @@ BOOLEAN CheckConditionsForBattle( GROUP *pGroup ) //then we will go straight to autoresolve, where the enemy will likely annihilate them or capture them. //If there are no alive mercs, then there is nothing anybody can do. The enemy will completely ignore //this, and continue on. - #ifdef JA2BETAVERSION - ValidateGroups( pGroup ); - #endif + + // WANNE: ValidateGroups now returns a BOOLEAN Value (TRUE/FALSE) if the attacking is valid. + // This fixes the problem that 0 enemies could attack a sector + if (!ValidateGroups( pGroup )) + return FALSE; StopTimeCompression(); @@ -1581,7 +1582,7 @@ void AddCorpsesToBloodcatLair( INT16 sSectorX, INT16 sSectorY ) Corpse.usFlags = ROTTING_CORPSE_FIND_SWEETSPOT_FROM_GRIDNO; // 1st gridno - Corpse.sGridNo = 14319; + Corpse.sGridNo = 14319; //dnl!!! ConvertGridNoToXY( Corpse.sGridNo, &sXPos, &sYPos ); Corpse.dXPos = (FLOAT)( CenterX( sXPos ) ); Corpse.dYPos = (FLOAT)( CenterY( sYPos ) ); @@ -1591,7 +1592,7 @@ void AddCorpsesToBloodcatLair( INT16 sSectorX, INT16 sSectorY ) // 2nd gridno - Corpse.sGridNo = 9835; + Corpse.sGridNo = 9835; //dnl!!! ConvertGridNoToXY( Corpse.sGridNo, &sXPos, &sYPos ); Corpse.dXPos = (FLOAT)( CenterX( sXPos ) ); Corpse.dYPos = (FLOAT)( CenterY( sYPos ) ); @@ -1601,7 +1602,7 @@ void AddCorpsesToBloodcatLair( INT16 sSectorX, INT16 sSectorY ) // 3rd gridno - Corpse.sGridNo = 11262; + Corpse.sGridNo = 11262; //dnl!!! ConvertGridNoToXY( Corpse.sGridNo, &sXPos, &sYPos ); Corpse.dXPos = (FLOAT)( CenterX( sXPos ) ); Corpse.dYPos = (FLOAT)( CenterY( sYPos ) ); @@ -3102,6 +3103,43 @@ INT32 GetSectorMvtTimeForGroup( UINT8 ubSector, UINT8 ubDirection, GROUP *pGroup if( iTraverseTime < iBestTraverseTime ) iBestTraverseTime = iTraverseTime; } + + /////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits - ranger reduces time needed for travelling around + if( pGroup->fPlayer && !fAir && gGameOptions.fNewTraitSystem) + { + // see if we have any ranger here + UINT8 ubRangerHere = 0; + curr = pGroup->pPlayerList; + while( curr ) + { + pSoldier = curr->pSoldier; + if( HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + ubRangerHere += NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); + + curr = curr->next; + } + // yes, we have... + if( ubRangerHere > 0 ) + { + // no more than certain number of simultaneous bonuses + ubRangerHere = min( gSkillTraitValues.ubRAMaxBonusesToTravelSpeed, ubRangerHere ); + // on foot, the bonus should be higher + if( fFoot ) + { + // however, we cannot be quicker than the helicopter + iBestTraverseTime = max( 10, (iBestTraverseTime * (100 - ( ubRangerHere * gSkillTraitValues.ubRAGroupTimeSpentForTravellingFoot )) / 100)); + } + // all other types (except air) + else + { + // however, we cannot be quicker than the helicopter + iBestTraverseTime = max( 10, (iBestTraverseTime * (100 - ( ubRangerHere * gSkillTraitValues.ubRAGroupTimeSpentForTravellingVehicle )) / 100)); + } + } + } + /////////////////////////////////////////////////////////////////////////////// + return iBestTraverseTime; } @@ -3277,6 +3315,7 @@ void HandleArrivalOfReinforcements( GROUP *pGroup ) { gfPendingEnemies = TRUE; ResetMortarsOnTeamCount(); + ResetNumSquadleadersInArmyGroup(); // added by SANDRO AddPossiblePendingEnemiesToBattle(); } //Update the known number of enemies in the sector. @@ -4816,18 +4855,75 @@ BOOLEAN TestForBloodcatAmbush( GROUP *pGroup ) if( !fAlreadyAmbushed && PlacementType != BLOODCAT_PLACEMENT_STATIC && pSector->bBloodCats > 0 && !pGroup->fVehicle && !NumEnemiesInSector( pGroup->ubSectorX, pGroup->ubSectorY ) ) { - // Wilderness ambush, or the player has unwittingly entered the lair? - if( PlacementType == BLOODCAT_PLACEMENT_AMBUSH || !gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] ) + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits - Scouting prevents the ambush of bloodcats + BOOLEAN fBloodCatAmbushPrevented = FALSE; + // The player has entered the lair + if(( PlacementType == BLOODCAT_PLACEMENT_LAIR )&& !gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] ) { - // Ambush occurs. - gubEnemyEncounterCode = BLOODCAT_AMBUSH_CODE; + // We know about the lair + if( gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] ) + { + gubEnemyEncounterCode = ENTERING_BLOODCAT_LAIR_CODE; + } + else + { + if ( gGameOptions.fNewTraitSystem && ScoutIsPresentInSquad( pGroup->ubSectorX, pGroup->ubSectorY ) && gSkillTraitValues.fSCPreventsBloodcatsAmbushes) + { + // Ha..! We've found the lair, safely + if ( gSkillTraitValues.fSCThrowMessageIfAmbushPrevented ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_BLOODCATS_AMBUSH_PREVENTED] ); + + fBloodCatAmbushPrevented = TRUE; + + gubEnemyEncounterCode = ENTERING_BLOODCAT_LAIR_CODE; + gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] = TRUE; + } + else + { + // Ambush in the lair. + gubEnemyEncounterCode = BLOODCAT_AMBUSH_CODE; + } + } } + // Wilderness ambush else { - // Player knowingly enters lair. - gubEnemyEncounterCode = ENTERING_BLOODCAT_LAIR_CODE; + if ( gGameOptions.fNewTraitSystem && ScoutIsPresentInSquad( pGroup->ubSectorX, pGroup->ubSectorY ) && gSkillTraitValues.fSCPreventsBloodcatsAmbushes) + { + // We are safe + if ( gSkillTraitValues.fSCThrowMessageIfAmbushPrevented ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_BLOODCATS_AMBUSH_PREVENTED] ); + + fBloodCatAmbushPrevented = TRUE; + + gubEnemyEncounterCode = NO_ENCOUNTER_CODE; + } + else + { + // Ambush occurs. + gubEnemyEncounterCode = BLOODCAT_AMBUSH_CODE; + } } - return TRUE; + // merc recoeds - get a point to scouts + if ( fBloodCatAmbushPrevented ) + { + for( UINT16 i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) + { + if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) ) + { + if ( MercPtrs[ i ]->sSectorX == pGroup->ubSectorX && MercPtrs[ i ]->sSectorY == pGroup->ubSectorY && MercPtrs[ i ]->bAssignment != ASSIGNMENT_POW && MercPtrs[ i ]->stats.bLife > OKLIFE ) + { + if( HAS_SKILL_TRAIT( MercPtrs[ i ], SCOUTING_NT ) && MercPtrs[ i ]->ubProfile != NO_PROFILE ) + { + gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.usAmbushesExperienced++; + } + } + } + } + } + return( ( gubEnemyEncounterCode == NO_ENCOUNTER_CODE ) ? FALSE : TRUE); + /////////////////////////////////////////////////////////////////////////////////////////// } else { @@ -5088,8 +5184,13 @@ BOOLEAN WildernessSectorWithAllProfiledNPCsNotSpokenWith( INT16 sSectorX, INT16 MERCPROFILESTRUCT * pProfile; BOOLEAN fFoundSomebody = FALSE; - - for ( ubProfile = FIRST_RPC; ubProfile < GASTON; ubProfile++ ) + + //for ( ubProfile = FIRST_RPC; ubProfile < GASTON; ubProfile++ ) + //new profiles by Jazz + for ( ubProfile = 0; ubProfile < NUM_PROFILES; ubProfile++ ) + { + + if ( gProfilesRPC[ubProfile].ProfilId == ubProfile || gProfilesNPC[ubProfile].ProfilId == ubProfile || gProfilesVehicle[ubProfile].ProfilId == ubProfile) { pProfile = &gMercProfiles[ ubProfile ]; @@ -5100,7 +5201,8 @@ BOOLEAN WildernessSectorWithAllProfiledNPCsNotSpokenWith( INT16 sSectorX, INT16 } // skip vehicles - if ( ubProfile >= PROF_HUMMER && ubProfile <= PROF_HELICOPTER ) + //if ( ubProfile >= PROF_HUMMER && ubProfile <= PROF_HELICOPTER ) + if ( gProfilesVehicle[ubProfile].ProfilId == ubProfile ) { continue; } @@ -5122,8 +5224,14 @@ BOOLEAN WildernessSectorWithAllProfiledNPCsNotSpokenWith( INT16 sSectorX, INT16 return( FALSE ); } } + + } + else + { + return( FALSE ); } + } return( fFoundSomebody ); } @@ -5234,13 +5342,20 @@ UINT8 NumberMercsInVehicleGroup( GROUP *pGroup ) return 0; } -#ifdef JA2BETAVERSION -void ValidateGroups( GROUP *pGroup ) + +BOOLEAN ValidateGroups( GROUP *pGroup ) { + BOOLEAN isValid = TRUE; + //Do error checking, and report group - ValidatePlayersAreInOneGroupOnly(); + #ifdef JA2BETAVERSION + ValidatePlayersAreInOneGroupOnly(); + #endif + if( !pGroup->fPlayer && !pGroup->ubGroupSize ) { + isValid = FALSE; + //report error CHAR16 str[ 512 ]; if( pGroup->ubSectorIDOfLastReassignment == 255 ) @@ -5260,7 +5375,34 @@ void ValidateGroups( GROUP *pGroup ) } //correct error - DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL ); + #ifdef JA2BETAVERSION + DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL ); + #endif } + + return isValid; } -#endif + + +// SANDRO - added check if we have a scout in group +BOOLEAN ScoutIsPresentInSquad( INT16 ubSectorNumX, INT16 ubSectorNumY ) +{ + BOOLEAN fScoutPresent = FALSE; + INT32 i; + + for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ ) + { + if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) ) + { + if ( MercPtrs[ i ]->sSectorX == ubSectorNumX && MercPtrs[ i ]->sSectorY == ubSectorNumY && MercPtrs[ i ]->bAssignment != ASSIGNMENT_POW && MercPtrs[ i ]->stats.bLife > OKLIFE ) + { + if( HAS_SKILL_TRAIT( MercPtrs[ i ], SCOUTING_NT )) + { + fScoutPresent = TRUE; + } + } + } + } + + return ( fScoutPresent ); +} \ No newline at end of file diff --git a/Strategic/Strategic Movement.h b/Strategic/Strategic Movement.h index 3e5effd2..2867881e 100644 --- a/Strategic/Strategic Movement.h +++ b/Strategic/Strategic Movement.h @@ -305,4 +305,6 @@ BOOLEAN DoesPlayerExistInPGroup( UINT8 ubGroupID, SOLDIERTYPE *pSoldier ); BOOLEAN GroupHasInTransitDeadOrPOWMercs( GROUP *pGroup ); +BOOLEAN ScoutIsPresentInSquad( INT16 ubSectorNumX, INT16 ubSectorNumY ); // added by SANDRO + #endif diff --git a/Strategic/Strategic Town Loyalty.cpp b/Strategic/Strategic Town Loyalty.cpp index 9440d303..8e4227fa 100644 --- a/Strategic/Strategic Town Loyalty.cpp +++ b/Strategic/Strategic Town Loyalty.cpp @@ -39,6 +39,10 @@ #include "Facilities.h" #endif +#include "Luaglobal.h" +#include "LuaInitNPCs.h" +#include "Interface.h" + // the max loyalty rating for any given town #define MAX_LOYALTY_VALUE 100 @@ -678,6 +682,8 @@ void HandleMurderOfCivilian( SOLDIERTYPE *pSoldier, BOOLEAN fIntentional ) UINT32 uiChanceFalseAccusal = 0; INT8 bKillerTeam = 0; BOOLEAN fIncrement = FALSE; + + UINT16 iCounter2; // ubAttacker CAN be NOBODY... Don't treat is as murder if NOBODY killed us... @@ -702,6 +708,18 @@ void HandleMurderOfCivilian( SOLDIERTYPE *pSoldier, BOOLEAN fIntentional ) } } + // if civilian belongs to a civilian group + if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP ) + { + //New Group by Jazz + for( iCounter2 = REBEL_CIV_GROUP; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if (zCivGroupName[iCounter2].Loyalty == FALSE) + return; + } + } + + /* // if civilian belongs to a civilian group if ( pSoldier->ubCivilianGroup != NON_CIV_GROUP ) { @@ -714,8 +732,17 @@ void HandleMurderOfCivilian( SOLDIERTYPE *pSoldier, BOOLEAN fIntentional ) case WARDEN_CIV_GROUP: return; } + + //New Group by Jazz + for( iCounter2 = UNNAMED_CIV_GROUP_15; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if (pSoldier->ubCivilianGroup == iCounter2) + return; + } + + } - + */ // set killer team bKillerTeam = Menptr[ pSoldier->ubAttackerID ].bTeam; @@ -1605,8 +1632,7 @@ void DecrementTownLoyaltyEverywhere( UINT32 uiLoyaltyDecrease ) } // this applies the change to every town differently, depending on the distance from the event void HandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ) -{ - INT32 iLoyaltyChange; +{ INT8 bTownId = 0; if( bSectorZ == 0 ) @@ -1620,6 +1646,12 @@ void HandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY { return; } + + //move to lua scripts StrategicTownLoyalty.lua +#ifdef LUA_STRATEGY_TOWN_LOYALTY + LuaHandleGlobalLoyaltyEvent( ubEventType, sSectorX, sSectorY, bSectorZ, 0 ); +#else + INT32 iLoyaltyChange; // determine what the base loyalty change of this event type is worth // these are->hundredths<- of loyalty points, so choose appropriate values accordingly! @@ -1677,6 +1709,8 @@ void HandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY } AffectAllTownsLoyaltyByDistanceFrom( iLoyaltyChange, sSectorX, sSectorY, bSectorZ); + +#endif } @@ -1848,6 +1882,12 @@ void CheckIfEntireTownHasBeenLost( INT8 bTownId, INT16 sSectorX, INT16 sSectorY void HandleLoyaltyChangeForNPCAction( UINT8 ubNPCProfileId ) { + //move to lua scripts StrategicTownLoyalty.lua + +#ifdef LUA_STRATEGY_TOWN_LOYALTY + LetHandleLoyaltyChangeForNPCAction( ubNPCProfileId, 0 ); +#else + switch ( ubNPCProfileId ) { case MIGUEL: @@ -1891,6 +1931,7 @@ void HandleLoyaltyChangeForNPCAction( UINT8 ubNPCProfileId ) break; } +#endif } @@ -1973,7 +2014,8 @@ void HandleLoyaltyImplicationsOfMercRetreat( INT8 bRetreatCode, INT16 sSectorX, if ( bRetreatCode == RETREAT_TACTICAL_TRAVERSAL ) { // if not worse than 2:1 odds, then penalize morale - if ( gTacticalStatus.fEnemyInSector && ( PlayerStrength() * 2 >= EnemyStrength() ) ) + // SANDRO - Set the odds based on difficulty level + if ( gTacticalStatus.fEnemyInSector && ( (PlayerStrength() * (2 + gGameOptions.ubDifficultyLevel)) >= EnemyStrength() ) ) { HandleMoraleEvent( NULL, MORALE_RAN_AWAY, sSectorX, sSectorY, (INT8)sSectorZ ); } diff --git a/Strategic/Strategic_VS2005.vcproj b/Strategic/Strategic_VS2005.vcproj new file mode 100644 index 00000000..dbd3caeb --- /dev/null +++ b/Strategic/Strategic_VS2005.vcproj @@ -0,0 +1,767 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Strategic/Strategic_VS2008.vcproj b/Strategic/Strategic_VS2008.vcproj index 5e1a57c6..5c8843d0 100644 --- a/Strategic/Strategic_VS2008.vcproj +++ b/Strategic/Strategic_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -379,6 +379,14 @@ RelativePath="Game Init.h" > + + + + @@ -471,6 +479,10 @@ RelativePath="Strategic Merc Handler.h" > + + @@ -563,6 +575,14 @@ RelativePath="Hourly Update.cpp" > + + + + @@ -651,6 +671,10 @@ RelativePath="Strategic Merc Handler.cpp" > + + diff --git a/Strategic/Strategic_VS2010.vcxproj b/Strategic/Strategic_VS2010.vcxproj new file mode 100644 index 00000000..a5f528a5 --- /dev/null +++ b/Strategic/Strategic_VS2010.vcxproj @@ -0,0 +1,317 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} + Win32Proj + Strategic + Strategic + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Strategic/Strategic_VS2010.vcxproj.filters b/Strategic/Strategic_VS2010.vcxproj.filters new file mode 100644 index 00000000..00b93da1 --- /dev/null +++ b/Strategic/Strategic_VS2010.vcxproj.filters @@ -0,0 +1,327 @@ + + + + + {e965b12d-833b-4ed2-b5fe-b519e2d661e3} + + + {7fc727d5-3708-404e-8267-410283203b63} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Strategic/Town Militia.cpp b/Strategic/Town Militia.cpp index 104fe038..e7b25579 100644 --- a/Strategic/Town Militia.cpp +++ b/Strategic/Town Militia.cpp @@ -328,6 +328,8 @@ void TownMilitiaTrainingCompleted( SOLDIERTYPE *pTrainer, INT16 sMapX, INT16 sMa IncrementTownLoyalty( ubTownId, uiTownLoyaltyBonus ); } + // SANDRO - merc records (num militia trained) + RecordNumMilitiaTrainedForMercs( sMapX, sMapY, pTrainer->bSectorZ, ubMilitiaTrained, FALSE ); } // the trainer announces to player that he's finished his assignment. Make his sector flash! @@ -882,6 +884,11 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia3"); SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR(pSoldier->sSectorX, pSoldier->sSectorY) ] ); BOOLEAN fUnfullSectorFound = FALSE; + // Test to see if not enough Town Militia + // HEADROCK HAM 4: No need for this check anymore. Militia can now be trained separately thanks to being + // able to keep them out of cities. + /* + if ( CountMilitia( pSectorInfo ) < gGameExternalOptions.iMaxMilitiaPerSector ) { fUnfullSectorFound = TRUE; @@ -925,6 +932,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Militia3"); DoContinueMilitiaTrainingMessageBox( sSectorX, sSectorY, sString, MSG_BOX_FLAG_OK, CantTrainMobileMilitiaOkBoxCallback ); return; } + */ ////////////////////////////////////////// // Capacity check in nearby sectors @@ -1162,7 +1170,7 @@ void HandleMilitiaStatusInCurrentMapBeforeLoadingNewMap( void ) } -BOOLEAN CanNearbyMilitiaScoutThisSector( INT16 sSectorX, INT16 sSectorY ) +BOOLEAN CanSomeoneNearbyScoutThisSector( INT16 sSectorX, INT16 sSectorY, BOOLEAN fScoutTraitCheck ) // added argument - SANDRO { INT16 sSectorValue = 0, sSector = 0; INT16 sCounterA = 0, sCounterB = 0; @@ -1184,18 +1192,36 @@ BOOLEAN CanNearbyMilitiaScoutThisSector( INT16 sSectorX, INT16 sSectorY ) sSectorValue = SECTOR( sCounterA, sCounterB ); - // check if any sort of militia here - if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ GREEN_MILITIA ] ) + // SANDRO - STOMP traits - Scouting check + if (fScoutTraitCheck && gGameOptions.fNewTraitSystem && ScoutIsPresentInSquad( sCounterA, sCounterB )) { - return( TRUE ); + // if diagonal sector and not allowed + if (!gSkillTraitValues.fSCDetectionInDiagonalSectors && + ((sCounterA - 1 == sSectorX && sCounterB + 1 == sSectorY) || + (sCounterA - 1 == sSectorX && sCounterB - 1 == sSectorY) || + (sCounterA + 1 == sSectorX && sCounterB + 1 == sSectorY) || + (sCounterA + 1 == sSectorX && sCounterB - 1 == sSectorY))) + { + return( FALSE ); + } + else + return( TRUE ); } - else if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] ) + else { - return( TRUE ); - } - else if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ ELITE_MILITIA ] ) - { - return( TRUE ); + // check if any sort of militia here + if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ GREEN_MILITIA ] ) + { + return( TRUE ); + } + else if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] ) + { + return( TRUE ); + } + else if( SectorInfo[ sSectorValue ].ubNumberOfCivsAtLevel[ ELITE_MILITIA ] ) + { + return( TRUE ); + } } } } @@ -1891,10 +1917,21 @@ UINT8 FindBestMilitiaTrainingLeadershipInSector ( INT16 sMapX, INT16 sMapY, INT8 { usTrainerEffectiveLeadership = EffectiveLeadership(pCheckedTrainer); - // Effective leadership is modified by an INI-based percentage, once for every TEACHING trait level. - if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) + if ( gGameOptions.fNewTraitSystem ) // SANDRO - old/new traits { - for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pCheckedTrainer, TEACHING ); i++ ) + // -10% penalty for untrained mercs + usTrainerEffectiveLeadership = (usTrainerEffectiveLeadership * (100 - gSkillTraitValues.bSpeedModifierTrainingMilitia) / 100); + + if (HAS_SKILL_TRAIT( pCheckedTrainer, TEACHING_NT )) + { + // bonus from Teaching trait + usTrainerEffectiveLeadership = __min(100,(usTrainerEffectiveLeadership * (100 + gSkillTraitValues.ubTGEffectiveLDRToTrainMilitia) / 100 )); + } + } + // Effective leadership is modified by an INI-based percentage, once for every TEACHING trait level. + else if ( gGameExternalOptions.usTeacherTraitEffectOnLeadership > 0 && gGameExternalOptions.usTeacherTraitEffectOnLeadership != 100 ) + { + for (UINT8 i = 0; i < NUM_SKILL_TRAITS( pCheckedTrainer, TEACHING_OT ); i++ ) { // percentage-based. usTrainerEffectiveLeadership = __min(100,((usTrainerEffectiveLeadership * gGameExternalOptions.usTeacherTraitEffectOnLeadership)/100)); @@ -2282,4 +2319,4 @@ UINT32 CalcMilitiaUpkeep( void ) } return (uiTotalPayment); -} +} \ No newline at end of file diff --git a/Strategic/Town Militia.h b/Strategic/Town Militia.h index ac0d1c92..9489508a 100644 --- a/Strategic/Town Militia.h +++ b/Strategic/Town Militia.h @@ -63,7 +63,7 @@ void HandleInterfaceMessageForContinuingTrainingMilitia( SOLDIERTYPE *pSoldier ) void HandleMilitiaStatusInCurrentMapBeforeLoadingNewMap( void ); // is there a town with militia here or nearby? -BOOLEAN CanNearbyMilitiaScoutThisSector( INT16 sSectorX, INT16 sSectorY ); +BOOLEAN CanSomeoneNearbyScoutThisSector( INT16 sSectorX, INT16 sSectorY, BOOLEAN fScoutTraitCheck ); // changed - SANDRO // is the town militia full? BOOLEAN IsTownFullMilitia( INT8 bTownId, INT8 iMilitiaType ); diff --git a/Strategic/UndergroundInit.cpp b/Strategic/UndergroundInit.cpp index 031f2cd5..b45bca95 100644 --- a/Strategic/UndergroundInit.cpp +++ b/Strategic/UndergroundInit.cpp @@ -4,9 +4,9 @@ #include "UndergroundInit.h" #include "Campaign Init.h" -#include "Campaign Types.h" #include "FileMan.h" #include "GameSettings.h" +#include "Game Clock.h" extern "C" { #include "lua.h" @@ -14,107 +14,318 @@ extern "C" { #include "lualib.h" } +#include "lua_state.h" +#include "lua_table.h" +#include "lua_function.h" +#include "connect.h" -extern UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ ); +// externals +UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ ); +extern BOOLEAN gfGettingNameFromSaveLoadScreen; -static int l_addSector(lua_State *L); -static int lh_getIntegerFromTable(lua_State *L, char * fieldname); -static std::string lh_getStringFromTable(lua_State *L, char * fieldname); -static std::wstring lh_getWStringFromTable(lua_State *L, char * fieldname); -static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z); +// helper functions +static std::string XYZtoString(INT16 x, INT16 y, INT16 z); -using namespace std; +// keystroke savers +#define LF vfs::Log::endl +#define ON LuaLogger::ON +#define OFF LuaLogger::OFF + +// global +LuaUnderground g_luaUnderground; -BOOLEAN LetLuaBuildUndergroundSectorInfoList() +template <> +bool LuaTable::getValue(const char * index, UINT8& value) { - char * filename = "scripts\\initunderground.lua"; - UINT32 size, bytesRead; - char* buffer; + int dummy; + bool b = getValue(index, dummy); + if (b) + { + value = static_cast(dummy); + return true; + } + + return false; +} + +// Calls into Lua script to let build underground sector list. +BOOLEAN LuaUnderground::InitializeSectorList() +{ + // WANNE: Skip initialization in a multiplayer game, because some variables are not yet set + // No problem: Underground sectors are not currently used in a multiplayer game + if (!is_networked || gGameOptions.ubDifficultyLevel > 0) + { + LuaState L = GetLuaState(); + + LuaFunction initsectorlist_func(L, "BuildUndergroundSectorList"); + + initsectorlist_func + .TableOpen() + .TParam("difficultyLevel", int(gGameOptions.ubDifficultyLevel)) + .TParam("gameStyle", int(gGameOptions.ubGameStyle)) + .TableClose(); + + SGP_THROW_IFFALSE(initsectorlist_func.Call(1), "call to lua function BuildUndergroundSectorList failed"); + + LuaTable result(L, -1); + if (result.is_valid()) + { + int len = result.length(); + for (int i = 1; i <= result.length(); ++i) + { + LuaTable sectorData(result, i); + if (sectorData.is_valid()) + { + std::string location; + sectorData.getValue("location", location); + + UINT8 x, y, z; + if (locationStringToCoordinates(location, &x, &y, &z)) + { + UNDERGROUND_SECTORINFO* s = NewUndergroundNode(x, y, z); + + sectorData.getValue("numAdmins", s->ubNumAdmins); + sectorData.getValue("numTroops", s->ubNumTroops); + sectorData.getValue("numElites", s->ubNumElites); + + sectorData.getValue("numBloodcats", s->ubNumBloodcats); + sectorData.getValue("numCreatures", s->ubNumCreatures); + sectorData.getValue("creatureHabitat", s->ubCreatureHabitat); + + sectorData.getValue("music", s->ubMusicMode); + if (s->ubMusicMode < CM_COMPAT || CM_ALWAYS < s->ubMusicMode) + s->ubMusicMode = CM_COMPAT; + + // logging only + { + m_log << "adding sector: " << location << LF; + m_log << "\t- Enemy garrison" << LF; + m_log << "\t\tAdmins: " << static_cast(s->ubNumAdmins) << LF; + m_log << "\t\tTroops: " << static_cast(s->ubNumTroops) << LF; + m_log << "\t\tElites: " << static_cast(s->ubNumElites) << LF; + m_log << "\t- Creature population" << LF; + m_log << "\t\tBloodcats: " << static_cast(s->ubNumBloodcats) << LF; + m_log << "\t\tCrepitus: " << static_cast(s->ubNumCreatures) << LF; + m_log << "\t\t- Habitat: " << static_cast(s->ubCreatureHabitat) << LF; + m_log << "\t\t- Music mode: "; + switch (s->ubMusicMode) + { + case CM_COMPAT: m_log << "compat" << LF; break; + case CM_AUTO: m_log << "auto" << LF; break; + case CM_NEVER: m_log << "never" << LF; break; + case CM_ALWAYS: m_log << "always" << LF; break; + } + m_log << LF; + } + } + else + m_log << "WARNING: ignoring invalid location ID: '" << location << "'" << LF; + + m_log.Flush(); + } + + lua_pop(L(), 1); // sectorData + } + } + lua_pop(L(), 1); // result + } + else + { + return FALSE; + } + + return TRUE; +} + + +// Calls into Lua script to get the loadscreen for a given sector. +void LuaUnderground::GetLoadscreen(INT16 x, INT16 y, INT16 z, std::string& loadscreen, std::string& format) +{ + const std::string strSector = XYZtoString(x, y, z); + + LuaState L = GetLuaState(); + LuaFunction getLoadscreen_func(L, "GetLoadscreen"); + + getLoadscreen_func + .Param(strSector) + .Param(int(GetWorldMinutesInDay())); + + SGP_THROW_IFFALSE(getLoadscreen_func.Call(2), "call to lua function GetLoadscreen failed"); + + + { + if (lua_isstring(L(), -1)) + { + format.append(lua_tostring(L(), -1)); + } + else + m_log << "ERROR: GetLoadscreen('" << strSector << "'): return value #2 is not a valid string object" << LF; + lua_pop(L(), 1); + + if (lua_isstring(L(), -1)) + { + loadscreen.append(lua_tostring(L(), -1)); + } + else + m_log << "ERROR: GetLoadscreen('" << strSector << "'): return value #1 is not a valid string object" << LF; + lua_pop(L(), 1); + } + + return; +} + + +// Calls into Lua script in order to request a sector name for a given sector. +// pSector can be null, e.g. when saveloadscreen requests sector names; +// in this case we didn't initialize the sector list nor have we loaded it from savegame yet. +void LuaUnderground::GetSectorName(INT16 x, INT16 y, INT16 z, const UNDERGROUND_SECTORINFO* pSector, STR16 buffer, ::size_t bufSizeInWChar, BOOLEAN fDetailed) +{ + const std::string coords = XYZtoString(x, y, z); + LuaState L = GetLuaState(); + + LuaFunction getSectorName_func(L, "GetSectorName"); + + getSectorName_func + .Param(coords) + .TableOpen() + .TParam("visited", gfGettingNameFromSaveLoadScreen || (pSector && pSector->fVisited)) + .TParam("creaturesPresent", pSector && pSector->ubNumCreatures > 0) + .TParam("detailed", !!fDetailed) // conversion to C++ bool + .TableClose(); + + SGP_THROW_IFFALSE(getSectorName_func.Call(1), "call to lua func GetSectorName failed"); + + + // TODO: check if this still makes a whole lot of sense now + { + memset(buffer, 0, bufSizeInWChar * sizeof(CHAR16)); + + if (lua_isstring(L(), -1)) + { + const char * utf8 = lua_tostring(L(), -1); + int result = MultiByteToWideChar(CP_UTF8, 0, lua_tostring(L(), -1), -1, buffer, bufSizeInWChar-1); + if (result == 0) + { + // Houston, we have a problem... + buffer[bufSizeInWChar-1] = L'\0'; + + DWORD errorcode = GetLastError(); + if (errorcode == ERROR_INSUFFICIENT_BUFFER) + { + // quick note on logging: + // we explicitly turn logging off once we encounter an error + // since this function gets called a lot (every frame or so) + m_log << "'" << utf8 << "': wchar representation too long" << LF << OFF; + } + else + { + m_log << "'" << utf8 << "': illegal unicode data" << LF << OFF;; + } + } + } + else + m_log << "ERROR: requesting sector name for '" << coords << "' failed, no valid string object has been returned" << LF << OFF; + + lua_pop(L(), 1); // return value + } + + return; +} + + +// Parse the scripts, set everything up. +void LuaUnderground::LoadScript(const char * langPrefix) +{ + LuaState L = GetLuaState(); + + // #1: builds strategic underground layout + char * initunderground = "scripts\\initunderground.lua"; + + // #2: provides sector names; this is localized, build actual filename at runtime + char * sectornamesfile = "undergroundsectornames.lua"; + std::string sectornames("scripts\\"); + if (langPrefix != NULL) + sectornames.append(langPrefix); + sectornames.append(sectornamesfile); + + // we don't use L.EvalFile because the lua parser dislikes UTF-8 BOMs (gonna strip them first) + RunScript(L, sectornames.c_str()); + RunScript(L, initunderground); + + // TODO: see if we can make this better + { + lua_getglobal(L(), "logging"); + if (lua_isboolean(L(), -1) && lua_toboolean(L(), -1)) + m_log << ON; + lua_pop(L(), -1); + } + + return; +} + + + +// Loads a Lua script and let the interpreter process it. +// Returns true if successful. +// Throws an exception if file not found. +bool LuaUnderground::RunScript(LuaState& L, const char * szFileName) +{ + using namespace std; + + // stupid file opening functions don't use const parameters... + vector filenamebuffer(strlen(szFileName)+1); + strcpy(&filenamebuffer[0], szFileName); + char * filename = &filenamebuffer[0]; + + + UINT32 size, bytesRead; HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE); if (!file) - return false; + { + string msg("Cannot open file: "); + msg.append(filename); + + m_log << msg << LF; + m_log.Flush(); + + //throw sgp::Exception(msg.c_str(), __LINE__, _FUNCTION_FORMAT_, __FILE__); + SGP_THROW(msg); + } size = FileSize(filename); - buffer = new char[size+1]; - buffer[size] = 0; - FileRead(file, buffer, size, &bytesRead); + vector buffer = vector(size); + FileRead(file, &buffer[0], size, &bytesRead); FileClose(file); - - lua_State *L = lua_open(); - luaL_openlibs(L); - - lua_register(L, "addSector", l_addSector); - - lua_pushinteger(L, gGameOptions.ubDifficultyLevel); - lua_setglobal(L, "difficultyLevel"); - - lua_pushinteger(L, gGameOptions.ubGameStyle); - lua_setglobal(L, "gameStyle"); - - if (luaL_dostring(L, buffer)) + // simple UTF8 BOM check: + // replace with blanks if necessary since Lua HATES byte order marks + const unsigned char bom[] = { 0xEF, 0xBB, 0xBF }; + if (memcmp(&buffer[0], bom, 3) == 0) { - // oh noes, error - // TODO: write to log or something - return false; + buffer[0] = buffer[1] = buffer[2] = ' '; } - lua_close(L); - - delete[] buffer; - - return true; + return L.EvalString(&buffer[0], buffer.size(), szFileName); } -static int l_addSector(lua_State *L) +LuaUnderground::LuaUnderground() + : m_log("initunderground.log", false, true, vfs::Log::FLUSH_BUFFER) { - UNDERGROUND_SECTORINFO* curr = NULL; - - std::string sector_id = lh_getStringFromTable(L, "location"); - - UINT8 x, y, z; - if (locationStringToCoordinates(sector_id, &x, &y, &z)) - { - curr = NewUndergroundNode(x, y, z); - - curr->ubNumAdmins = lh_getIntegerFromTable(L, "numAdmins"); - curr->ubNumTroops = lh_getIntegerFromTable(L, "numTroops"); - curr->ubNumElites = lh_getIntegerFromTable(L, "numElites"); - - curr->ubCreatureHabitat = lh_getIntegerFromTable(L, "creatureHabitat"); - curr->ubNumCreatures = lh_getIntegerFromTable(L, "numCreatures"); - - curr->ubNumBloodcats = lh_getIntegerFromTable(L, "numBloodcats"); - } - - return 0; // number of results } -static int lh_getIntegerFromTable(lua_State *L, char * fieldname) +LuaUnderground::~LuaUnderground() { - lua_getfield(L, -1, fieldname); - int i = lua_tointeger(L, -1); - lua_pop(L, 1); - return i; + // WANNE: Disabled, because it leads to an unhandled exception when shutting down ja2 1.13 + /*m_log.Flush();*/ } - -static std::string lh_getStringFromTable(lua_State *L, char * fieldname) -{ - lua_getfield(L, -1, fieldname); - string s = lua_tostring(L, -1); - lua_pop(L, 1); - return s; -} - - // extract x,y,z from strings like "D13-1" -static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z) +BOOLEAN locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z) { int length = loc.length(); @@ -132,7 +343,7 @@ static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UIN // gather column loc = loc.substr(1); - stringstream ss = stringstream(); + std::stringstream ss; if (loc[0] >= '0' && loc[0] <= '9') { ss << loc[0]; @@ -159,3 +370,14 @@ static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UIN return true; } + +static std::string XYZtoString(INT16 x, INT16 y, INT16 z) +{ + using namespace std; + + stringstream ss; + ss << static_cast(y+'A'-1) << x << '-' << z; + string tmp; + ss >> tmp; + return tmp; +} diff --git a/Strategic/UndergroundInit.h b/Strategic/UndergroundInit.h index b9de6c64..e93ebbbf 100644 --- a/Strategic/UndergroundInit.h +++ b/Strategic/UndergroundInit.h @@ -1,8 +1,62 @@ #ifndef _UNDERGROUNDINIT_H #define _UNDERGROUNDINIT_H +#include "Campaign Types.h" #include "Types.h" +//#include "Strategic Mines LUA.h" -extern BOOLEAN LetLuaBuildUndergroundSectorInfoList(); +#include "lua_state.h" + +//BOOLEAN LetLuaBuildUndergroundSectorInfoList(); +BOOLEAN locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z); + +#include +class LuaLogger +{ + bool m_active; + vfs::Log& m_log; + +public: + enum LoggingState + { + OFF, + ON, + }; + + LuaLogger(const vfs::Path filename, bool enable = true, bool append = false, vfs::Log::EFlushMode flushMode = vfs::Log::FLUSH_ON_ENDL) + : m_log(*vfs::Log::create(filename, append, flushMode)), m_active(enable) {} + ~LuaLogger() { /*Flush();*/ } + void ToggleLogging(bool enable) { m_active = enable; } + void Flush() { m_log.flush(); } + + template LuaLogger& operator<<(const T& message) { if (m_active) m_log << message; return *this; } + template <> LuaLogger& operator<<(const vfs::Log::_endl& endl) { if (m_active) m_log << vfs::Log::endl; return *this; } + template <> LuaLogger& operator<<(const LoggingState& state) { m_active = state == ON; return *this; } + +}; + +class LuaUnderground +{ +public: + void LoadScript(const char * langPrefix); + + BOOLEAN InitializeSectorList(); + void GetLoadscreen(INT16 x, INT16 y, INT16 z, std::string& buffer, std::string& format); + void GetSectorName(INT16 x, INT16 y, INT16 z, const UNDERGROUND_SECTORINFO* pSector, STR16 buffer, size_t bufSizeInWChar, BOOLEAN fDetailed); + + LuaUnderground(); + virtual ~LuaUnderground(); +private: + LuaState GetLuaState() + { + return LuaState::GET(lua::LUA_STATE_STRATEGIC_MINES_AND_UNDERGROUND); + } + void Reset(); + bool RunScript(LuaState& L, const char * filename); + + LuaLogger m_log; +}; + +extern LuaUnderground g_luaUnderground; #endif diff --git a/Strategic/XML_Bloodcats.cpp b/Strategic/XML_Bloodcats.cpp index 3347ae00..d1faa1a7 100644 --- a/Strategic/XML_Bloodcats.cpp +++ b/Strategic/XML_Bloodcats.cpp @@ -197,6 +197,8 @@ BloodcatsEndElementHandle(void *userData, const XML_Char *name) { // Lair sector. There can be only one, and it is affected by the Quest. Bloodcats can regenerate // their numbers here over time. + gubBloodcatLairSectorId = ubSectorId; + gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = 0; gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats; gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = 0; @@ -219,7 +221,7 @@ BloodcatsEndElementHandle(void *userData, const XML_Char *name) pData->sCurSectorX = x; pData->sCurSectorY = y; } - THROWIFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in BloodcatPlacements.XML" ); + SGP_THROW_IFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in BloodcatPlacements.XML" ); } else if(strcmp(name, "ubPlacementType") == 0 ) { diff --git a/Strategic/XML_DynamicRestrictions.cpp b/Strategic/XML_DynamicRestrictions.cpp index f0cd8340..6c9c5b16 100644 --- a/Strategic/XML_DynamicRestrictions.cpp +++ b/Strategic/XML_DynamicRestrictions.cpp @@ -55,7 +55,7 @@ dynamicroamingStartElementHandle(void *userData, const XML_Char *name, const XML // Set all sector IDs to -1 ("unused") for (UINT16 cnt=0; cnt<5001; cnt++) { - gDynamicRestrictions[cnt].bSectorID = -1; + gDynamicRestrictions[cnt].sSectorID = -1; } pData->curElement = ELEMENT_LIST; @@ -119,7 +119,7 @@ dynamicroamingEndElementHandle(void *userData, const XML_Char *name) if (SECTOR(pData->sCurSectorX, pData->sCurSectorY) >= 0 && SECTOR(pData->sCurSectorX, pData->sCurSectorY) < 256) { pData->curIndex++; - gDynamicRestrictions[pData->curIndex].bSectorID = SECTOR(pData->sCurSectorX,pData->sCurSectorY); + gDynamicRestrictions[pData->curIndex].sSectorID = SECTOR(pData->sCurSectorX,pData->sCurSectorY); gDynamicRestrictions[pData->curIndex].uiReqTownFlags |= pData->uiReqTownFlags; } } diff --git a/Strategic/XML_ExtraItems.cpp b/Strategic/XML_ExtraItems.cpp index 1cc23f4a..c7be4a6e 100644 --- a/Strategic/XML_ExtraItems.cpp +++ b/Strategic/XML_ExtraItems.cpp @@ -15,7 +15,8 @@ typedef enum { EXTRAITEMS_ELEMENT_NONE = 0, EXTRAITEMS_ELEMENT_EXTRAITEMS, - EXTRAITEMS_ELEMENT_ITEM + EXTRAITEMS_ELEMENT_ITEM, + EXTRAITEMS_ELEMENT, } EXTRAITEMS_PARSE_STAGE; typedef struct @@ -29,6 +30,7 @@ typedef struct UINT32 quantity; UINT32 condition; UINT32 gridno; + BOOLEAN visible; } ExtraItemsParseData; @@ -56,35 +58,21 @@ ExtraItemsStartElementHandle(void *userData, const XML_Char *name, const XML_Cha pData->curElement = EXTRAITEMS_ELEMENT_ITEM; pData->maxReadDepth++; //we are not skipping this element - // Extract the attributes - // defaults + // set defaults pData->quantity = 1; pData->condition = 100; pData->gridno = 0; - for(unsigned uiAttrIndex = 0;atts[uiAttrIndex] != NULL;uiAttrIndex += 2) - { - if(strcmp(atts[uiAttrIndex], "quantity") == 0) - { - pData->quantity = atol(atts[uiAttrIndex+1]); - if (pData->quantity < 1 || pData->quantity > 100) { - pData->quantity = 1; - } - } - else if(strcmp(atts[uiAttrIndex], "condition") == 0) - { - pData->condition = atol(atts[uiAttrIndex+1]); - if (pData->condition < 1 || pData->condition > 100) { - pData->condition = 100; - } - } - else if(strcmp(atts[uiAttrIndex], "gridno") == 0) - { - pData->gridno = atol(atts[uiAttrIndex+1]); - //if (pData->gridno < ???? || pData->gridno > ????) { - // pData->gridno = 0; - //} - } - } + pData->visible = FALSE; + } + else if(pData->curElement == EXTRAITEMS_ELEMENT_ITEM && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "quantity") == 0 || + strcmp(name, "condition") == 0 || + strcmp(name, "gridno") == 0 || + strcmp(name, "visible") == 0 )) + { + pData->curElement = EXTRAITEMS_ELEMENT; + pData->maxReadDepth++; } pData->szCharData[0] = '\0'; } @@ -111,24 +99,59 @@ ExtraItemsEndElementHandle(void *userData, const XML_Char *name) if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading { - if(strcmp(name, "ExtraItems") == 0 && pData->curElement == EXTRAITEMS_ELEMENT_EXTRAITEMS) + if(pData->curElement == EXTRAITEMS_ELEMENT_EXTRAITEMS && + strcmp(name, "ExtraItems") == 0) { pData->curElement = EXTRAITEMS_ELEMENT_NONE; } - else if(strcmp(name, "Item") == 0 && pData->curElement == EXTRAITEMS_ELEMENT_ITEM) + else if(pData->curElement == EXTRAITEMS_ELEMENT_ITEM && + strcmp(name, "Item") == 0 && + pData->item > 0 && // Make sure not to create 0-index objects! + pData->quantity > 0 && // Quantity should be positive. Not sure what the LIMIT is, if any. + pData->condition > 0 && pData->condition <= 100 ) // Condition between 1 and 100! { - pData->item = atol(pData->szCharData); OBJECTTYPE object; CreateItem(pData->item, pData->condition, &object); for (unsigned cnt=1; cnt <= pData->quantity; ++cnt) { if (gSectorIsLoaded) { - AddItemToPool( pData->gridno, &object, 1, 0, WORLD_ITEM_REACHABLE, 0 ); + AddItemToPool( pData->gridno, &object, pData->visible, 0, WORLD_ITEM_REACHABLE, 0 ); } else { - AddItemsToUnLoadedSector( gX, gY, gZ, pData->gridno, 1, &object, 0, WORLD_ITEM_REACHABLE, 0, 1, 0 ); + AddItemsToUnLoadedSector( gX, gY, gZ, pData->gridno, pData->visible, &object, 0, WORLD_ITEM_REACHABLE, 0, 1, 0 ); } } pData->curElement = EXTRAITEMS_ELEMENT_EXTRAITEMS; } + + else if( pData->curElement == EXTRAITEMS_ELEMENT && + strcmp( name, "uiIndex" ) == 0) + { + pData->item = (UINT32)atol( pData->szCharData ); + pData->curElement = EXTRAITEMS_ELEMENT_ITEM; + } + else if( pData->curElement == EXTRAITEMS_ELEMENT && + strcmp( name, "quantity" ) == 0) + { + pData->quantity = (UINT32)atol( pData->szCharData ); + pData->curElement = EXTRAITEMS_ELEMENT_ITEM; + } + else if( pData->curElement == EXTRAITEMS_ELEMENT && + strcmp( name, "condition" ) == 0) + { + pData->condition = (UINT32)atol( pData->szCharData ); + pData->curElement = EXTRAITEMS_ELEMENT_ITEM; + } + else if( pData->curElement == EXTRAITEMS_ELEMENT && + strcmp( name, "gridno" ) == 0) + { + pData->gridno = (UINT32)atol( pData->szCharData ); + pData->curElement = EXTRAITEMS_ELEMENT_ITEM; + } + else if( pData->curElement == EXTRAITEMS_ELEMENT && + strcmp( name, "visible" ) == 0) + { + pData->visible = (UINT32)atol( pData->szCharData ); + pData->curElement = EXTRAITEMS_ELEMENT_ITEM; + } pData->maxReadDepth--; } pData->currentDepth--; @@ -185,6 +208,8 @@ void AddExtraItems(UINT8 x, UINT8 y, UINT8 z, bool sectorIsLoaded) break; } + strcat(fileName, ".xml"); + // Open extra items file HWFILE hFile; // Try "special" difficulty level file first diff --git a/Strategic/XML_FacilityTypes.cpp b/Strategic/XML_FacilityTypes.cpp index 66270d4a..8717fb35 100644 --- a/Strategic/XML_FacilityTypes.cpp +++ b/Strategic/XML_FacilityTypes.cpp @@ -57,6 +57,7 @@ struct } typedef facilitytypeParseData; +BOOLEAN FacilityTypes_TextOnly; void InitFacilityTypeEntry( facilitytypeParseData *pData ) { @@ -125,7 +126,7 @@ void InitAssignmentDataArray( facilitytypeParseData *pData ) // Set RISK data for (UINT16 cnt = 0; cnt < NUM_RISKS; cnt++) { - pData->curAssignmentData.Risk[cnt].ubChance = 0; + pData->curAssignmentData.Risk[cnt].usChance = 0; pData->curAssignmentData.Risk[cnt].bBaseEffect = 0; pData->curAssignmentData.Risk[cnt].ubRange = 0; } @@ -397,7 +398,7 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) } else { - THROWEXCEPTION(L"FacilityTypes.XML Error: Tag encountered too early! Please make sure to close all opened tags first."); + SGP_THROW(L"FacilityTypes.XML Error: Tag encountered too early! Please make sure to close all opened tags first."); } } else if(strcmp(name, "FACILITYTYPE") == 0) @@ -408,65 +409,77 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) if (pData->curIndex >= 1) { - - // Begin with basic facility data - wcscpy(gFacilityTypes[pData->curIndex].szFacilityName, pData->curFacilityTypeData.szFacilityName); - wcscpy(gFacilityTypes[pData->curIndex].szFacilityShortName, pData->curFacilityTypeData.szFacilityShortName); - gFacilityTypes[pData->curIndex].ubTotalStaffLimit = pData->curFacilityTypeData.ubTotalStaffLimit; - - gFacilityTypes[pData->curIndex].ubMilitiaTrainersAllowed = pData->curFacilityTypeData.ubMilitiaTrainersAllowed; - gFacilityTypes[pData->curIndex].ubMobileMilitiaTrainersAllowed = pData->curFacilityTypeData.ubMobileMilitiaTrainersAllowed; - gFacilityTypes[pData->curIndex].usMilitiaTraining = pData->curFacilityTypeData.usMilitiaTraining; - gFacilityTypes[pData->curIndex].usMilitiaTraining = pData->curFacilityTypeData.usMilitiaTraining; - - // Set assignment-specific data - for (UINT16 cnt = 0; cnt < NUM_FACILITY_ASSIGNMENTS; cnt++) + if (!FacilityTypes_TextOnly) { - // Performance and limits - gFacilityTypes[pData->curIndex].AssignmentData[cnt].usPerformance = pData->curFacilityTypeData.AssignmentData[cnt].usPerformance; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubStaffLimit = pData->curFacilityTypeData.AssignmentData[cnt].ubStaffLimit; - wcscpy(gFacilityTypes[pData->curIndex].AssignmentData[cnt].szTooltipText, pData->curFacilityTypeData.AssignmentData[cnt].szTooltipText); - gFacilityTypes[pData->curIndex].AssignmentData[cnt].sCostPerHour = pData->curFacilityTypeData.AssignmentData[cnt].sCostPerHour; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].usFatigue = pData->curFacilityTypeData.AssignmentData[cnt].usFatigue; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].usKitDegrade = pData->curFacilityTypeData.AssignmentData[cnt].usKitDegrade; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].usSleep = pData->curFacilityTypeData.AssignmentData[cnt].usSleep; + // Begin with basic facility data + wcscpy(gFacilityTypes[pData->curIndex].szFacilityName, pData->curFacilityTypeData.szFacilityName); + wcscpy(gFacilityTypes[pData->curIndex].szFacilityShortName, pData->curFacilityTypeData.szFacilityShortName); + gFacilityTypes[pData->curIndex].ubTotalStaffLimit = pData->curFacilityTypeData.ubTotalStaffLimit; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMaximumBreath = pData->curFacilityTypeData.AssignmentData[cnt].ubMaximumBreath; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMaximumMorale = pData->curFacilityTypeData.AssignmentData[cnt].ubMaximumMorale; + gFacilityTypes[pData->curIndex].ubMilitiaTrainersAllowed = pData->curFacilityTypeData.ubMilitiaTrainersAllowed; + gFacilityTypes[pData->curIndex].ubMobileMilitiaTrainersAllowed = pData->curFacilityTypeData.ubMobileMilitiaTrainersAllowed; + gFacilityTypes[pData->curIndex].usMilitiaTraining = pData->curFacilityTypeData.usMilitiaTraining; + gFacilityTypes[pData->curIndex].usMilitiaTraining = pData->curFacilityTypeData.usMilitiaTraining; - // Detection abilities - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubDetectEnemiesImmediate = pData->curFacilityTypeData.AssignmentData[cnt].ubDetectEnemiesImmediate; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].fDetectEnemiesDynamic = pData->curFacilityTypeData.AssignmentData[cnt].fDetectEnemiesDynamic; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].fDetectEnemiesLongrange = pData->curFacilityTypeData.AssignmentData[cnt].fDetectEnemiesLongrange; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].fDetectEnemiesAnywhere = pData->curFacilityTypeData.AssignmentData[cnt].fDetectEnemiesAnywhere; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].fCountEnemiesInWild = pData->curFacilityTypeData.AssignmentData[cnt].fCountEnemiesInWild; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].fCountEnemiesInCities = pData->curFacilityTypeData.AssignmentData[cnt].fCountEnemiesInCities; - - // Other strategic abilities - gFacilityTypes[pData->curIndex].AssignmentData[cnt].sSkyriderCostModifier = pData->curFacilityTypeData.AssignmentData[cnt].sSkyriderCostModifier; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].usMineIncomeModifier = pData->curFacilityTypeData.AssignmentData[cnt].usMineIncomeModifier; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].fOnlyLocalMineAffected = pData->curFacilityTypeData.AssignmentData[cnt].fOnlyLocalMineAffected; - - // Conditions - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumStrength = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumStrength; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumAgility = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumAgility; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumDexterity = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumDexterity; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumHealth = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumHealth; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumWisdom = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumWisdom; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumMarksmanship = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumMarksmanship; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumLeadership = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumLeadership; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumExplosives = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumExplosives; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumMechanical = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumMechanical; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumMedical = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumMedical; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumLevel = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumLevel; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumLoyaltyHere = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumLoyaltyHere; - - // Set risks associated with this assignment - for (UINT16 cntB = 0; cntB < NUM_RISKS; cntB++) + // Set assignment-specific data + for (UINT16 cnt = 0; cnt < NUM_FACILITY_ASSIGNMENTS; cnt++) { - gFacilityTypes[pData->curIndex].AssignmentData[cnt].Risk[cntB].ubChance = pData->curFacilityTypeData.AssignmentData[cnt].Risk[cntB].ubChance; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].Risk[cntB].bBaseEffect = pData->curFacilityTypeData.AssignmentData[cnt].Risk[cntB].bBaseEffect; - gFacilityTypes[pData->curIndex].AssignmentData[cnt].Risk[cntB].ubRange = pData->curFacilityTypeData.AssignmentData[cnt].Risk[cntB].ubRange; + // Performance and limits + gFacilityTypes[pData->curIndex].AssignmentData[cnt].usPerformance = pData->curFacilityTypeData.AssignmentData[cnt].usPerformance; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubStaffLimit = pData->curFacilityTypeData.AssignmentData[cnt].ubStaffLimit; + wcscpy(gFacilityTypes[pData->curIndex].AssignmentData[cnt].szTooltipText, pData->curFacilityTypeData.AssignmentData[cnt].szTooltipText); + gFacilityTypes[pData->curIndex].AssignmentData[cnt].sCostPerHour = pData->curFacilityTypeData.AssignmentData[cnt].sCostPerHour; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].usFatigue = pData->curFacilityTypeData.AssignmentData[cnt].usFatigue; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].usKitDegrade = pData->curFacilityTypeData.AssignmentData[cnt].usKitDegrade; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].usSleep = pData->curFacilityTypeData.AssignmentData[cnt].usSleep; + + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMaximumBreath = pData->curFacilityTypeData.AssignmentData[cnt].ubMaximumBreath; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMaximumMorale = pData->curFacilityTypeData.AssignmentData[cnt].ubMaximumMorale; + + // Detection abilities + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubDetectEnemiesImmediate = pData->curFacilityTypeData.AssignmentData[cnt].ubDetectEnemiesImmediate; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].fDetectEnemiesDynamic = pData->curFacilityTypeData.AssignmentData[cnt].fDetectEnemiesDynamic; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].fDetectEnemiesLongrange = pData->curFacilityTypeData.AssignmentData[cnt].fDetectEnemiesLongrange; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].fDetectEnemiesAnywhere = pData->curFacilityTypeData.AssignmentData[cnt].fDetectEnemiesAnywhere; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].fCountEnemiesInWild = pData->curFacilityTypeData.AssignmentData[cnt].fCountEnemiesInWild; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].fCountEnemiesInCities = pData->curFacilityTypeData.AssignmentData[cnt].fCountEnemiesInCities; + + // Other strategic abilities + gFacilityTypes[pData->curIndex].AssignmentData[cnt].sSkyriderCostModifier = pData->curFacilityTypeData.AssignmentData[cnt].sSkyriderCostModifier; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].usMineIncomeModifier = pData->curFacilityTypeData.AssignmentData[cnt].usMineIncomeModifier; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].fOnlyLocalMineAffected = pData->curFacilityTypeData.AssignmentData[cnt].fOnlyLocalMineAffected; + + // Conditions + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumStrength = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumStrength; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumAgility = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumAgility; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumDexterity = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumDexterity; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumHealth = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumHealth; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumWisdom = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumWisdom; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumMarksmanship = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumMarksmanship; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumLeadership = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumLeadership; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumExplosives = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumExplosives; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumMechanical = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumMechanical; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumMedical = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumMedical; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumLevel = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumLevel; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].ubMinimumLoyaltyHere = pData->curFacilityTypeData.AssignmentData[cnt].ubMinimumLoyaltyHere; + + // Set risks associated with this assignment + for (UINT16 cntB = 0; cntB < NUM_RISKS; cntB++) + { + gFacilityTypes[pData->curIndex].AssignmentData[cnt].Risk[cntB].usChance = pData->curFacilityTypeData.AssignmentData[cnt].Risk[cntB].usChance; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].Risk[cntB].bBaseEffect = pData->curFacilityTypeData.AssignmentData[cnt].Risk[cntB].bBaseEffect; + gFacilityTypes[pData->curIndex].AssignmentData[cnt].Risk[cntB].ubRange = pData->curFacilityTypeData.AssignmentData[cnt].Risk[cntB].ubRange; + } + } + } + else + { + wcscpy(gFacilityTypes[pData->curIndex].szFacilityName, pData->curFacilityTypeData.szFacilityName); + wcscpy(gFacilityTypes[pData->curIndex].szFacilityShortName, pData->curFacilityTypeData.szFacilityShortName); + + for (UINT16 cnt = 0; cnt < NUM_FACILITY_ASSIGNMENTS; cnt++) + { + wcscpy(gFacilityTypes[pData->curIndex].AssignmentData[cnt].szTooltipText, pData->curFacilityTypeData.AssignmentData[cnt].szTooltipText); } } @@ -476,7 +489,7 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) } else { - THROWEXCEPTION(L"FacilityTypes.XML Error: A tag was encountered too early! Please make sure all tags are closed properly."); + SGP_THROW(L"FacilityTypes.XML Error: A tag was encountered too early! Please make sure all tags are closed properly."); } } @@ -548,64 +561,72 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) { CHAR16 sErrorString[256]; swprintf(sErrorString, L"FacilityTypes.XML Error: Assignment data for facility type %d is missing a tag", pData->curIndex); - THROWEXCEPTION(sErrorString); + SGP_THROW(sErrorString); } - else if (pData->curAssignmentData.ubStaffLimit <= 0 && - pData->curAssignmentType != FAC_AMBIENT ) + else if (pData->curAssignmentData.ubStaffLimit <= 0 && pData->curAssignmentType != FAC_AMBIENT && !FacilityTypes_TextOnly) { CHAR16 sErrorString[256]; swprintf(sErrorString, L"FacilityTypes.XML Error: Assignment data for facility type %d is missing a tag, or the value of the tag is 0.", pData->curIndex); - THROWEXCEPTION(sErrorString); + SGP_THROW(sErrorString); } else { // Set assignment data from memory - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usPerformance = pData->curAssignmentData.usPerformance; - wcscpy(pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].szTooltipText, pData->curAssignmentData.szTooltipText); - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubStaffLimit = pData->curAssignmentData.ubStaffLimit; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].sCostPerHour = pData->curAssignmentData.sCostPerHour; - - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usFatigue = pData->curAssignmentData.usFatigue; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usSleep = pData->curAssignmentData.usSleep; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usKitDegrade = pData->curAssignmentData.usKitDegrade; - - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].sSkyriderCostModifier = pData->curAssignmentData.sSkyriderCostModifier; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usMineIncomeModifier = pData->curAssignmentData.usMineIncomeModifier; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fOnlyLocalMineAffected = pData->curAssignmentData.fOnlyLocalMineAffected; - - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMaximumBreath = pData->curAssignmentData.ubMaximumBreath; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMaximumMorale = pData->curAssignmentData.ubMaximumMorale; - - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fCountEnemiesInCities = pData->curAssignmentData.fCountEnemiesInCities; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fCountEnemiesInWild = pData->curAssignmentData.fCountEnemiesInWild; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fDetectEnemiesAnywhere = pData->curAssignmentData.fDetectEnemiesAnywhere; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fDetectEnemiesDynamic = pData->curAssignmentData.fDetectEnemiesDynamic; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubDetectEnemiesImmediate = pData->curAssignmentData.ubDetectEnemiesImmediate; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fDetectEnemiesLongrange = pData->curAssignmentData.fDetectEnemiesLongrange; - - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumAgility = pData->curAssignmentData.ubMinimumAgility; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumBreath = pData->curAssignmentData.ubMinimumBreath; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumDexterity = pData->curAssignmentData.ubMinimumDexterity; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumExplosives = pData->curAssignmentData.ubMinimumExplosives; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumHealth = pData->curAssignmentData.ubMinimumHealth; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumLeadership = pData->curAssignmentData.ubMinimumLeadership; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumLevel = pData->curAssignmentData.ubMinimumLevel; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumLoyaltyHere = pData->curAssignmentData.ubMinimumLoyaltyHere; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMarksmanship = pData->curAssignmentData.ubMinimumMarksmanship; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMechanical = pData->curAssignmentData.ubMinimumMechanical; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMedical = pData->curAssignmentData.ubMinimumMedical; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMorale = pData->curAssignmentData.ubMinimumMorale; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumStrength = pData->curAssignmentData.ubMinimumStrength; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumWisdom = pData->curAssignmentData.ubMinimumWisdom; - - // Set RISK data - for (UINT16 cnt = 0; cnt < NUM_RISKS; cnt++) + if (!FacilityTypes_TextOnly) { - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].Risk[cnt].ubChance = pData->curAssignmentData.Risk[cnt].ubChance; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].Risk[cnt].bBaseEffect = pData->curAssignmentData.Risk[cnt].bBaseEffect; - pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].Risk[cnt].ubRange = pData->curAssignmentData.Risk[cnt].ubRange; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usPerformance = pData->curAssignmentData.usPerformance; + wcscpy(pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].szTooltipText, pData->curAssignmentData.szTooltipText); + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubStaffLimit = pData->curAssignmentData.ubStaffLimit; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].sCostPerHour = pData->curAssignmentData.sCostPerHour; + + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usFatigue = pData->curAssignmentData.usFatigue; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usSleep = pData->curAssignmentData.usSleep; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usKitDegrade = pData->curAssignmentData.usKitDegrade; + + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].sSkyriderCostModifier = pData->curAssignmentData.sSkyriderCostModifier; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].usMineIncomeModifier = pData->curAssignmentData.usMineIncomeModifier; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fOnlyLocalMineAffected = pData->curAssignmentData.fOnlyLocalMineAffected; + + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMaximumBreath = pData->curAssignmentData.ubMaximumBreath; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMaximumMorale = pData->curAssignmentData.ubMaximumMorale; + + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fCountEnemiesInCities = pData->curAssignmentData.fCountEnemiesInCities; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fCountEnemiesInWild = pData->curAssignmentData.fCountEnemiesInWild; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fDetectEnemiesAnywhere = pData->curAssignmentData.fDetectEnemiesAnywhere; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fDetectEnemiesDynamic = pData->curAssignmentData.fDetectEnemiesDynamic; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubDetectEnemiesImmediate = pData->curAssignmentData.ubDetectEnemiesImmediate; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].fDetectEnemiesLongrange = pData->curAssignmentData.fDetectEnemiesLongrange; + + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumAgility = pData->curAssignmentData.ubMinimumAgility; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumBreath = pData->curAssignmentData.ubMinimumBreath; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumDexterity = pData->curAssignmentData.ubMinimumDexterity; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumExplosives = pData->curAssignmentData.ubMinimumExplosives; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumHealth = pData->curAssignmentData.ubMinimumHealth; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumLeadership = pData->curAssignmentData.ubMinimumLeadership; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumLevel = pData->curAssignmentData.ubMinimumLevel; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumLoyaltyHere = pData->curAssignmentData.ubMinimumLoyaltyHere; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMarksmanship = pData->curAssignmentData.ubMinimumMarksmanship; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMechanical = pData->curAssignmentData.ubMinimumMechanical; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMedical = pData->curAssignmentData.ubMinimumMedical; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumMorale = pData->curAssignmentData.ubMinimumMorale; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumStrength = pData->curAssignmentData.ubMinimumStrength; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].ubMinimumWisdom = pData->curAssignmentData.ubMinimumWisdom; + + // Set RISK data + for (UINT16 cnt = 0; cnt < NUM_RISKS; cnt++) + { + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].Risk[cnt].usChance = pData->curAssignmentData.Risk[cnt].usChance; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].Risk[cnt].bBaseEffect = pData->curAssignmentData.Risk[cnt].bBaseEffect; + pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].Risk[cnt].ubRange = pData->curAssignmentData.Risk[cnt].ubRange; + } } + else + { + wcscpy(pData->curFacilityTypeData.AssignmentData[pData->curAssignmentType].szTooltipText, pData->curAssignmentData.szTooltipText); + } + } + } //////////////////////////////////////////////// @@ -795,7 +816,7 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) { CHAR16 sErrorString[256]; swprintf(sErrorString, L"FacilityTypes.XML Error: Assignment type for facility %d is unrecognized!", pData->curIndex); - THROWEXCEPTION(sErrorString); + SGP_THROW(sErrorString); } } @@ -1029,7 +1050,7 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) else if(strcmp(name, "ubChance") == 0 ) { pData->curElement = FACILITYTYPE_RISK; - pData->curAssignmentData.Risk[pData->curRisk].ubChance = (UINT8) atol(pData->szCharData); + pData->curAssignmentData.Risk[pData->curRisk].usChance = (UINT8) atol(pData->szCharData); } else if(strcmp(name, "bBaseEffect") == 0 ) @@ -1053,7 +1074,7 @@ facilitytypeEndElementHandle(void *userData, const XML_Char *name) -BOOLEAN ReadInFacilityTypes(STR fileName) +BOOLEAN ReadInFacilityTypes(STR fileName, BOOLEAN localizedVersion) { HWFILE hFile; UINT32 uiBytesRead; @@ -1062,13 +1083,15 @@ BOOLEAN ReadInFacilityTypes(STR fileName) XML_Parser parser = XML_ParserCreate(NULL); facilitytypeParseData pData; + + FacilityTypes_TextOnly = localizedVersion; DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading FacilityTypes.xml" ); // Open merges file hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); if ( !hFile ) - return( FALSE ); + return( localizedVersion ); uiFSize = FileGetSize(hFile); lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); diff --git a/Strategic/XML_SectorNames.cpp b/Strategic/XML_SectorNames.cpp index 9ed5863f..bad51e8c 100644 --- a/Strategic/XML_SectorNames.cpp +++ b/Strategic/XML_SectorNames.cpp @@ -19,6 +19,11 @@ // Four different sector names, used at different times. extern CHAR16 gzSectorNames[256][4][MAX_SECTOR_NAME_LENGTH]; +// moved to lua +//extern CHAR16 gzSectorUndergroundNames1[256][4][MAX_SECTOR_NAME_LENGTH]; +//extern CHAR16 gzSectorUndergroundNames2[256][4][MAX_SECTOR_NAME_LENGTH]; +//extern CHAR16 gzSectorUndergroundNames3[256][4][MAX_SECTOR_NAME_LENGTH]; + typedef enum { SECTORNAME_ELEMENT_NONE = 0, @@ -41,6 +46,10 @@ typedef struct UINT32 maxReadDepth; } SectorNameParseData; +BOOLEAN SectorName_TextOnly; + +INT8 Sector_Level; + static void XMLCALL SectorNameStartElementHandle(void *userData, const XML_Char *name, const char **atts) @@ -57,10 +66,38 @@ SectorNameStartElementHandle(void *userData, const XML_Char *name, const char ** // Initiate Array by setting first character to 0. for (UINT16 x = 0; x < 256; x++) { - gzSectorNames[x][0][0]=0; - gzSectorNames[x][1][0]=0; - gzSectorNames[x][2][0]=0; - gzSectorNames[x][3][0]=0; + + if (Sector_Level == 0 ) + { + gzSectorNames[x][0][0]=0; + gzSectorNames[x][1][0]=0; + gzSectorNames[x][2][0]=0; + gzSectorNames[x][3][0]=0; + } + + // moved to lua + //if (Sector_Level == 1 ) + //{ + // gzSectorUndergroundNames1[x][0][0]=0; + // gzSectorUndergroundNames1[x][1][0]=0; + // gzSectorUndergroundNames1[x][2][0]=0; + // gzSectorUndergroundNames1[x][3][0]=0; + //} + // if (Sector_Level == 2 ) + //{ + // gzSectorUndergroundNames2[x][0][0]=0; + // gzSectorUndergroundNames2[x][1][0]=0; + // gzSectorUndergroundNames2[x][2][0]=0; + // gzSectorUndergroundNames2[x][3][0]=0; + //} + //if (Sector_Level == 3 ) + //{ + // gzSectorUndergroundNames3[x][0][0]=0; + // gzSectorUndergroundNames3[x][1][0]=0; + // gzSectorUndergroundNames3[x][2][0]=0; + // gzSectorUndergroundNames3[x][3][0]=0; + //} + } } @@ -119,11 +156,71 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) UINT8 ubSectorId = SECTOR(pData->sCurSectorX, pData->sCurSectorY); if (ubSectorId >= 0 && ubSectorId < 256) { - wcscpy(gzSectorNames[ubSectorId][0], pData->szCurUnexploredName); - wcscpy(gzSectorNames[ubSectorId][1], pData->szCurDetailedUnexploredName); - wcscpy(gzSectorNames[ubSectorId][2], pData->szCurExploredName); - wcscpy(gzSectorNames[ubSectorId][3], pData->szCurDetailedExploredName); - } + if (!SectorName_TextOnly) + { + if (Sector_Level == 0 ) + { + wcscpy(gzSectorNames[ubSectorId][0], pData->szCurUnexploredName); + wcscpy(gzSectorNames[ubSectorId][1], pData->szCurDetailedUnexploredName); + wcscpy(gzSectorNames[ubSectorId][2], pData->szCurExploredName); + wcscpy(gzSectorNames[ubSectorId][3], pData->szCurDetailedExploredName); + } + // moved to lua + //else if (Sector_Level == 1 ) + //{ + // wcscpy(gzSectorUndergroundNames1[ubSectorId][0], pData->szCurUnexploredName); + // wcscpy(gzSectorUndergroundNames1[ubSectorId][1], pData->szCurDetailedUnexploredName); + // wcscpy(gzSectorUndergroundNames1[ubSectorId][2], pData->szCurExploredName); + // wcscpy(gzSectorUndergroundNames1[ubSectorId][3], pData->szCurDetailedExploredName); + //} + //else if (Sector_Level == 2 ) + //{ + // wcscpy(gzSectorUndergroundNames2[ubSectorId][0], pData->szCurUnexploredName); + // wcscpy(gzSectorUndergroundNames2[ubSectorId][1], pData->szCurDetailedUnexploredName); + // wcscpy(gzSectorUndergroundNames2[ubSectorId][2], pData->szCurExploredName); + // wcscpy(gzSectorUndergroundNames2[ubSectorId][3], pData->szCurDetailedExploredName); + //} + //else if (Sector_Level == 3 ) + //{ + // wcscpy(gzSectorUndergroundNames3[ubSectorId][0], pData->szCurUnexploredName); + // wcscpy(gzSectorUndergroundNames3[ubSectorId][1], pData->szCurDetailedUnexploredName); + // wcscpy(gzSectorUndergroundNames3[ubSectorId][2], pData->szCurExploredName); + // wcscpy(gzSectorUndergroundNames3[ubSectorId][3], pData->szCurDetailedExploredName); + //} + } + else + { + if (Sector_Level == 0 ) + { + wcscpy(gzSectorNames[ubSectorId][0], pData->szCurUnexploredName); + wcscpy(gzSectorNames[ubSectorId][1], pData->szCurDetailedUnexploredName); + wcscpy(gzSectorNames[ubSectorId][2], pData->szCurExploredName); + wcscpy(gzSectorNames[ubSectorId][3], pData->szCurDetailedExploredName); + } + // moved to lua + //else if (Sector_Level == 1 ) + //{ + // wcscpy(gzSectorUndergroundNames1[ubSectorId][0], pData->szCurUnexploredName); + // wcscpy(gzSectorUndergroundNames1[ubSectorId][1], pData->szCurDetailedUnexploredName); + // wcscpy(gzSectorUndergroundNames1[ubSectorId][2], pData->szCurExploredName); + // wcscpy(gzSectorUndergroundNames1[ubSectorId][3], pData->szCurDetailedExploredName); + //} + //else if (Sector_Level == 2 ) + //{ + // wcscpy(gzSectorUndergroundNames2[ubSectorId][0], pData->szCurUnexploredName); + // wcscpy(gzSectorUndergroundNames2[ubSectorId][1], pData->szCurDetailedUnexploredName); + // wcscpy(gzSectorUndergroundNames2[ubSectorId][2], pData->szCurExploredName); + // wcscpy(gzSectorUndergroundNames2[ubSectorId][3], pData->szCurDetailedExploredName); + //} + //else if (Sector_Level == 3 ) + //{ + // wcscpy(gzSectorUndergroundNames3[ubSectorId][0], pData->szCurUnexploredName); + // wcscpy(gzSectorUndergroundNames3[ubSectorId][1], pData->szCurDetailedUnexploredName); + // wcscpy(gzSectorUndergroundNames3[ubSectorId][2], pData->szCurExploredName); + // wcscpy(gzSectorUndergroundNames3[ubSectorId][3], pData->szCurDetailedExploredName); + //} + } + } } else if(strcmp(name, "SectorGrid") == 0 ) @@ -178,7 +275,7 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) } -BOOLEAN ReadInSectorNames(STR fileName) +BOOLEAN ReadInSectorNames(STR fileName, BOOLEAN localizedVersion, INT8 Level ) { HWFILE hFile; UINT32 uiBytesRead; @@ -187,10 +284,13 @@ BOOLEAN ReadInSectorNames(STR fileName) XML_Parser parser = XML_ParserCreate(NULL); SectorNameParseData pData; + + Sector_Level = Level; + SectorName_TextOnly = localizedVersion; hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); if ( !hFile ) - return( FALSE ); + return( localizedVersion ); uiFSize = FileGetSize(hFile); lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); diff --git a/Strategic/XML_UniformColors.cpp b/Strategic/XML_UniformColors.cpp index 5544f21c..0b1064db 100644 --- a/Strategic/XML_UniformColors.cpp +++ b/Strategic/XML_UniformColors.cpp @@ -161,7 +161,7 @@ UniformEndElementHandle(void *userData, const XML_Char *name) { CHAR16 sString[256]; swprintf( sString, L"Error in UniformColors.XML: Uniform color for %s not found or not properly defined!", szUniformErrorStrings[ cnt ] ); - THROWEXCEPTION( sString ); + SGP_THROW( sString ); } } diff --git a/Strategic/mapscreen.cpp b/Strategic/mapscreen.cpp index ce0d6946..92c9abd2 100644 --- a/Strategic/mapscreen.cpp +++ b/Strategic/mapscreen.cpp @@ -113,6 +113,8 @@ #include "Animation Control.h" // HEADROCK HAM 3.6: Include facilities for assignment display #include "Facilities.h" + // HEADROCK HAM 4: Include Militia Squads for Manual Militia Restrictions toggle. + #include "MilitiaSquads.h" #endif #include "connect.h" //hayden @@ -714,6 +716,9 @@ extern BOOLEAN fSelectedListOfMercsForMapScreen[ CODE_MAXIMUM_NUMBER_OF_PLAYER_S extern INT32 iDialogueBox; extern INT32 giMapInvDescButton; +// HEADROCK HAM 4: Extern tab buttons for UDB +extern INT32 giInvDescTabButton[3]; + extern UINT32 guiBrownBackgroundForTeamPanel; // the town mine info box @@ -1131,7 +1136,7 @@ void BeginSellAllCallBack( UINT8 bExitValue ) { return; } - for(UINT32 wItem = 0; wItem < guiNumWorldItems; wItem++) + for(UINT32 wItem = 0; wItem < guiNumWorldItems; wItem++) //WS TODO: is "for(UINT32 wItem = 0; wItem < pInventoryPoolList.size(); wItem++)" better? It resolved a bug in the old SVN, but things have changed now. (It was likely only fighting symptons anyway) { if(pInventoryPoolList[wItem].object.exists() == true && (pInventoryPoolList[wItem].usFlags & WORLD_ITEM_REACHABLE)) { @@ -1169,7 +1174,7 @@ void BeginDeleteAllCallBack( UINT8 bExitValue ) { return; } - for(UINT32 wItem = 0; wItem < guiNumWorldItems; wItem++) + for(UINT32 wItem = 0; wItem < guiNumWorldItems; wItem++) //WS TODO: is "for(UINT32 wItem = 0; wItem < pInventoryPoolList.size(); wItem++)" { if(0 == pInventoryPoolList[wItem].object.MoveThisObjectTo(gItemPointer,-1,0,NUM_INV_SLOTS,MAX_OBJECTS_PER_SLOT)) { @@ -2109,7 +2114,8 @@ void GlowItem( void ) if( fOldItemGlow == TRUE ) { - RestoreExternBackgroundRect( 3, 80, ( UINT16 )( 65 - 3 ), ( UINT16 )( 105 - 80 ) ); + // this caused the attachment/burst/grenade star to disappear behind the item image + //RestoreExternBackgroundRect( 3, 80, ( UINT16 )( 65 - 3 ), ( UINT16 )( 105 - 80 ) ); } fOldItemGlow = FALSE; @@ -2424,11 +2430,15 @@ void DrawCharStats( INT16 sCharNum ) SetFontForeground(CHAR_TEXT_FONT_COLOR); SetFontBackground(FONT_BLACK); - // strength swprintf( sString, L"%d", pSoldier->stats.bStrength); - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeStrengthTime)&& ( pSoldier->timeChanges.uiChangeStrengthTime != 0 ) ) + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_STRENGTH] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeStrengthTime)&& ( pSoldier->timeChanges.uiChangeStrengthTime != 0 ) ) { if( pSoldier->usValueGoneUp & STRENGTH_INCREASE ) { @@ -2451,7 +2461,12 @@ void DrawCharStats( INT16 sCharNum ) // dexterity swprintf( sString, L"%d", pSoldier->stats.bDexterity ); - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeDexterityTime ) && ( pSoldier->timeChanges.uiChangeDexterityTime != 0 ) ) + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_DEXTERITY] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeDexterityTime ) && ( pSoldier->timeChanges.uiChangeDexterityTime != 0 ) ) { if( pSoldier->usValueGoneUp & DEX_INCREASE ) { @@ -2473,8 +2488,13 @@ void DrawCharStats( INT16 sCharNum ) // agility swprintf( sString, L"%d", pSoldier->stats.bAgility ); - - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeAgilityTime)&& ( pSoldier->timeChanges.uiChangeAgilityTime != 0 ) ) + + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_AGILITY] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeAgilityTime)&& ( pSoldier->timeChanges.uiChangeAgilityTime != 0 ) ) { if( pSoldier->usValueGoneUp & AGIL_INCREASE ) { @@ -2496,8 +2516,13 @@ void DrawCharStats( INT16 sCharNum ) // wisdom swprintf( sString, L"%d", pSoldier->stats.bWisdom ); - - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeWisdomTime )&&( pSoldier->timeChanges.uiChangeWisdomTime != 0 )) + + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_WISDOM] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeWisdomTime )&&( pSoldier->timeChanges.uiChangeWisdomTime != 0 )) { if( pSoldier->usValueGoneUp & WIS_INCREASE ) { @@ -2519,8 +2544,13 @@ void DrawCharStats( INT16 sCharNum ) // leadership swprintf( sString, L"%d", pSoldier->stats.bLeadership ); - - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeLeadershipTime ) && ( pSoldier->timeChanges.uiChangeLeadershipTime != 0 ) ) + + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_LEADERSHIP] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeLeadershipTime ) && ( pSoldier->timeChanges.uiChangeLeadershipTime != 0 ) ) { if( pSoldier->usValueGoneUp & LDR_INCREASE ) { @@ -2566,7 +2596,12 @@ void DrawCharStats( INT16 sCharNum ) // marksmanship swprintf( sString, L"%d", pSoldier->stats.bMarksmanship ); - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeMarksmanshipTime) && ( pSoldier->timeChanges.uiChangeMarksmanshipTime != 0 ) ) + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_MARKSMANSHIP] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeMarksmanshipTime) && ( pSoldier->timeChanges.uiChangeMarksmanshipTime != 0 ) ) { if( pSoldier->usValueGoneUp & MRK_INCREASE ) { @@ -2588,8 +2623,13 @@ void DrawCharStats( INT16 sCharNum ) // explosives swprintf( sString, L"%d", pSoldier->stats.bExplosive ); - - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeExplosivesTime)&& ( pSoldier->timeChanges.uiChangeExplosivesTime != 0 ) ) + + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_EXPLOSIVES] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeExplosivesTime)&& ( pSoldier->timeChanges.uiChangeExplosivesTime != 0 ) ) { if( pSoldier->usValueGoneUp & EXP_INCREASE ) { @@ -2611,8 +2651,13 @@ void DrawCharStats( INT16 sCharNum ) // mechanical swprintf( sString, L"%d", pSoldier->stats.bMechanical ); - - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeMechanicalTime )&& ( pSoldier->timeChanges.uiChangeMechanicalTime != 0 ) ) + + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_MECHANICAL] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeMechanicalTime )&& ( pSoldier->timeChanges.uiChangeMechanicalTime != 0 ) ) { if( pSoldier->usValueGoneUp & MECH_INCREASE ) { @@ -2635,7 +2680,12 @@ void DrawCharStats( INT16 sCharNum ) // medical swprintf( sString, L"%d", pSoldier->stats.bMedical ); - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeMedicalTime)&& ( pSoldier->timeChanges.uiChangeMedicalTime != 0 ) ) + // SANDRO - if damaged stat we could regain, show in red until repaired + if( gGameOptions.fNewTraitSystem && ( pSoldier->ubCriticalStatDamage[DAMAGED_STAT_MEDICAL] > 0 )) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + pSoldier->timeChanges.uiChangeMedicalTime)&& ( pSoldier->timeChanges.uiChangeMedicalTime != 0 ) ) { if( pSoldier->usValueGoneUp & MED_INCREASE ) { @@ -3165,6 +3215,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sAgilityGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sAgilityGain+1)) / SubpointsPerPoint(AGILAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (AGL_Y-1); ClipRect.iBottom = (AGL_Y-1) + STAT_HEI; ClipRect.iLeft = AGL_X; @@ -3176,6 +3227,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sDexterityGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sDexterityGain+1)) / SubpointsPerPoint(DEXTAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (DEX_Y-1); ClipRect.iBottom = (DEX_Y-1) + STAT_HEI; ClipRect.iLeft = DEX_X; @@ -3187,6 +3239,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sStrengthGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sStrengthGain+1)) / SubpointsPerPoint(STRAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (STR_Y-1); ClipRect.iBottom = (STR_Y-1) + STAT_HEI; ClipRect.iLeft = STR_X; @@ -3198,6 +3251,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sWisdomGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sWisdomGain+1)) / SubpointsPerPoint(WISDOMAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (WIS_Y-1); ClipRect.iBottom = (WIS_Y-1) + STAT_HEI; ClipRect.iLeft = WIS_X; @@ -3209,6 +3263,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain+1)) / SubpointsPerPoint(MARKAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (MRK_Y-1); ClipRect.iBottom = (MRK_Y-1) + STAT_HEI; ClipRect.iLeft = MRK_X; @@ -3220,6 +3275,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain+1)) / SubpointsPerPoint(LDRAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (LDR_Y-1); ClipRect.iBottom = (LDR_Y-1) + STAT_HEI; ClipRect.iLeft = LDR_X; @@ -3231,6 +3287,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sMechanicGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMechanicGain+1)) / SubpointsPerPoint(MECHANAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (MEC_Y-1); ClipRect.iBottom = (MEC_Y-1) + STAT_HEI; ClipRect.iLeft = MEC_X; @@ -3242,6 +3299,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain+1)) / SubpointsPerPoint(EXPLODEAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (EXP_Y-1); ClipRect.iBottom = (EXP_Y-1) + STAT_HEI; ClipRect.iLeft = EXP_X; @@ -3253,6 +3311,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sMedicalGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMedicalGain+1)) / SubpointsPerPoint(MEDICALAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (MED_Y-1); ClipRect.iBottom = (MED_Y-1) + STAT_HEI; ClipRect.iLeft = MED_X; @@ -3264,6 +3323,7 @@ void DisplayCharacterInfo( void ) if (gMercProfiles[ pSoldier->ubProfile ].sExpLevelGain) { ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sExpLevelGain+1)) / SubpointsPerPoint(EXPERAMT, pSoldier->stats.bExpLevel); + ubBarWidth = __max(0, __min(ubBarWidth, STAT_WID)); ClipRect.iTop = (LVL_Y-1); ClipRect.iBottom = (LVL_Y-1) + STAT_HEI; ClipRect.iLeft = LVL_X; @@ -3990,14 +4050,14 @@ void DrawMPPlayerList () //DrawString( (STR16)szPlayerName , usX,usY, MAP_SCREEN_FONT); // WANNE: No team selection in DM or COOP - if (PLAYER_BSIDE == MP_TYPE_DEATHMATCH || PLAYER_BSIDE == MP_TYPE_COOP) + if (cGameType == MP_TYPE_DEATHMATCH || cGameType == MP_TYPE_COOP) wcscpy(szTeam, gszMPTeamNames[4]); else wcscpy(szTeam,gszMPTeamNames[client_teams[i]]); FindFontCenterCoordinates((short)MP_TEAM_X + 1, (short)(MP_ROWSTART_Y+(row*Y_SIZE)), (short)MP_TEAM_W, (short)Y_SIZE, szTeam, (long)MAP_SCREEN_FONT, &usX, &usY); DrawString( szTeam,usX,(short)usY, MAP_SCREEN_FONT); - wcscpy(szCompass,(RANDOM_SPAWN==1 ? L"?" : gszMPEdgesText[client_edges[i]])); + wcscpy(szCompass,(gRandomStartingEdge==1 ? L"?" : gszMPEdgesText[client_edges[i]])); FindFontCenterCoordinates((short)MP_COMPASS_X + 1, (short)(MP_ROWSTART_Y+(row*Y_SIZE)), (short)MP_COMPASS_W, (short)Y_SIZE, szCompass, (long)MAP_SCREEN_FONT, &usX, &usY); DrawString(szCompass , usX,(short)usY, MAP_SCREEN_FONT); @@ -4013,7 +4073,7 @@ void DrawMPPlayerList () // change this text to wrap /*wchar_t szServerName[30]; memset(szServerName,0,30*sizeof(wchar_t)); - mbstowcs( szServerName,SERVER_NAME,30); + mbstowcs( szServerName,cServerName,30); SetFontForeground( FONT_YELLOW ); DrawString( L"Server Name:" , MP_GAMEINFO_X ,MP_ROWSTART_Y, MAP_SCREEN_FONT); @@ -4025,7 +4085,7 @@ void DrawMPPlayerList () DrawString( gszMPMapscreenText[0] , MP_GAMEINFO_X ,MP_ROWSTART_Y, MAP_SCREEN_FONT); SetFontForeground( FONT_WHITE ); - switch(PLAYER_BSIDE) + switch(cGameType) { case MP_TYPE_DEATHMATCH: DrawString( gzMPHScreenText[MPH_DEATHMATCH_TEXT] , MP_GAMEINFO_X ,MP_ROWSTART_Y+(1*Y_SIZE), MAP_SCREEN_FONT); @@ -4044,7 +4104,7 @@ void DrawMPPlayerList () SetFontForeground( FONT_WHITE ); wchar_t szMaxPlayers[10]; - swprintf(szMaxPlayers,L"%i",MAX_CLIENTS); + swprintf(szMaxPlayers,L"%i",cMaxClients); DrawString( szMaxPlayers , MP_GAMEINFO_X + StringPixLength(gszMPMapscreenText[1],MAP_SCREEN_FONT),MP_ROWSTART_Y+(2*Y_SIZE), MAP_SCREEN_FONT); // Number of Mercs @@ -4053,11 +4113,11 @@ void DrawMPPlayerList () SetFontForeground( FONT_WHITE ); wchar_t szSquadSize[10]; - swprintf(szSquadSize,L"%i",MAX_MERCS); + swprintf(szSquadSize,L"%i",cMaxMercs); DrawString( szSquadSize , MP_GAMEINFO_X + StringPixLength(gszMPMapscreenText[2],MAP_SCREEN_FONT),MP_ROWSTART_Y+(3*Y_SIZE), MAP_SCREEN_FONT); row = 4; - if (RANDOM_MERCS) + if (gRandomMercs) { // Random Mercs SetFontForeground( FONT_YELLOW ); @@ -5497,6 +5557,14 @@ UINT32 MapScreenHandle(void) //UnMarkButtonDirty( giCharInfoButton[ 0 ] ); //UnMarkButtonDirty( giCharInfoButton[ 1 ] ); MarkAButtonDirty( giMapInvDescButton ); + // HEADROCK HAM 4: Makes sure the Tab Buttons are always redrawn on top. + for (UINT8 cnt = 0; cnt < 3; cnt++) + { + if (giInvDescTabButton[cnt] != -1) + { + MarkAButtonDirty( giInvDescTabButton[ cnt ] ); + } + } } else { @@ -5866,8 +5934,8 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont) } if ( gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] && - (pSoldier->bAssignment >= TRAIN_SELF || - pSoldier->bAssignment <= TRAIN_BY_OTHER ) && + pSoldier->bAssignment >= TRAIN_SELF && + pSoldier->bAssignment <= TRAIN_BY_OTHER && pSoldier->bAssignment != TRAIN_TEAMMATE ) { // HEADROCK HAM 3.6: Draw militia training progress bar @@ -5888,8 +5956,8 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont) } pDestBuf = LockVideoSurface( uiDestBuffer, &uiDestPitchBYTES ); - UINT8 ubProgress; - UINT16 usMaxProgress; + UINT8 ubProgress = 0; + UINT16 usMaxProgress = 100; UINT8 sMapX = (UINT8)pSoldier->sSectorX; UINT8 sMapY = (UINT8)pSoldier->sSectorY; if ( pSoldier->bAssignment == TRAIN_TOWN ) @@ -5947,6 +6015,7 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont) } ubBarWidth = (ASSIGN_WIDTH * ubProgress) / usMaxProgress; + ubBarWidth = __max(0, __min(ubBarWidth, ASSIGN_WIDTH)); ClipRect.iTop = (usY+(Y_OFFSET*sRowIndex+1))-1; ClipRect.iBottom = ClipRect.iTop + Y_SIZE; ClipRect.iLeft = ASSIGN_X+2; @@ -6903,25 +6972,8 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) StopAnyCurrentlyTalkingSpeech( ); break; - // multiplayer: Roman: Should be changed, because the keys are already bount to another feature case F1: - // WANNE: No more needed - /* - if (is_networked) - { - mp_help(); - break; - } - */ case F2: - // WANNE: No more needed - /* - if (is_networked) - { - mp_help2(); - break; - } - */ case F3: case F4: case F5: @@ -7141,13 +7193,6 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) case '5': case '6': case '7': - // WANNE: Only show the override panel when '7' is pressed - /*if (is_networked && InputEvent.usParam == '7') - { - // haydent - manual_overide(); - break; - }*/ case '8': case '9': if(gGameExternalOptions.fEnableInventoryPoolQ && fShowMapInventoryPool == TRUE)//dnl ch51 081009 @@ -7166,8 +7211,7 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) SwitchToInventoryPoolQ('0'); break; } - SelectAllCharactersInSquad( 9 ); // internal squad #s start at 0 - if(is_networked)test_func2(); + SelectAllCharactersInSquad( 9 ); // internal squad #s start at 0 break; case '!': @@ -7318,67 +7362,99 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) if(bSelectedInfoChar != -1) { SOLDIERTYPE *pSoldier = MercPtrs[ gCharactersList[ bSelectedInfoChar ].usSolID ]; - if(OK_CONTROLLABLE_MERC( pSoldier )) + //CHRISL: Try to update InSector value so we don't have to "activate" a sector + if(pSoldier->sSectorX == sSelMapX && pSoldier->sSectorY == sSelMapY && pSoldier->bSectorZ == iCurrentMapSectorZ && !pSoldier->flags.fBetweenSectors) + pSoldier->bInSector=TRUE; + if(OK_CONTROL_MERC( pSoldier )) { - if(!fShowMapInventoryPool) - { - fShowMapInventoryPool = TRUE; - CreateDestroyMapInventoryPoolButtons( TRUE ); - } - if(!fShowInventoryFlag) - { - fShowInventoryFlag = TRUE; - } - if( fCtrl ) - { - //CHRISL: pickup all items to vehicle - if ( UsingNewInventorySystem() == true && fShowInventoryFlag && fShowMapInventoryPool && !(gTacticalStatus.fEnemyInSector) && gGameExternalOptions.fVehicleInventory && (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE)) + if(!fShowMapInventoryPool) { - for(unsigned int i = 0; iflags.uiStatusFlags & SOLDIER_VEHICLE)) { - if(pInventoryPoolList[i].fExists == TRUE && (pInventoryPoolList[i].usFlags & WORLD_ITEM_REACHABLE)) + for(unsigned int i = 0; iinv[x].exists() == true) + for(int x = 0; xinv[x].usItem != pInventoryPoolList[i].object.usItem) + if(vehicleInv[x] == FALSE) continue; + if(pSoldier->inv[x].exists() == true) + { + if(pSoldier->inv[x].usItem != pInventoryPoolList[i].object.usItem) + continue; + else + pInventoryPoolList[i].object.AddObjectsToStack(pSoldier->inv[x], -1, pSoldier, x); + } else - pInventoryPoolList[i].object.AddObjectsToStack(pSoldier->inv[x], -1, pSoldier, x); - } - else - pInventoryPoolList[i].object.MoveThisObjectTo(pSoldier->inv[x], -1, pSoldier, x); - if(pInventoryPoolList[i].object.ubNumberOfObjects < 0) - { - //RemoveItemFromWorld(i); - break; + pInventoryPoolList[i].object.MoveThisObjectTo(pSoldier->inv[x], -1, pSoldier, x); + if(pInventoryPoolList[i].object.ubNumberOfObjects < 0) + { + //RemoveItemFromWorld(i); + break; + } } } + fTeamPanelDirty = TRUE; + fMapPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; } - fTeamPanelDirty = TRUE; - fMapPanelDirty = TRUE; - fInterfacePanelDirty = DIRTYLEVEL2; } } - } - else - { - //CHRISL: drop all items - if ( bSelectedInfoChar != -1 && fShowInventoryFlag && fShowMapInventoryPool && !(gTacticalStatus.fEnemyInSector) ) + else if ( fAlt ) { - for(int i = BODYPOSFINAL; iinv[i].exists() == true) + for(int i = BIGPOCK4POS; i<=BIGPOCK7POS; i++) { - AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo); - DeleteObj(&pSoldier->inv[i]); + if(pSoldier->inv[i].exists() == true) + { + AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo); + DeleteObj(&pSoldier->inv[i]); + } + fTeamPanelDirty = TRUE; + fMapPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; } - fTeamPanelDirty = TRUE; - fMapPanelDirty = TRUE; - fInterfacePanelDirty = DIRTYLEVEL2; + for(int i = SMALLPOCK23POS; iinv[i].exists() == true) + { + AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo); + DeleteObj(&pSoldier->inv[i]); + } + fTeamPanelDirty = TRUE; + fMapPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; + } + } + } + else + { + //CHRISL: drop all items + if ( bSelectedInfoChar != -1 && fShowInventoryFlag && fShowMapInventoryPool && !(gTacticalStatus.fEnemyInSector) ) + { + for(int i = BODYPOSFINAL; iinv[i].exists() == true) + { + AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo); + DeleteObj(&pSoldier->inv[i]); + } + fTeamPanelDirty = TRUE; + fMapPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; } } } @@ -7410,7 +7486,7 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) //Toggle Frame Rate Display gbFPSDisplay = !gbFPSDisplay; DisableFPSOverlay( (BOOLEAN)!gbFPSDisplay ); - } + } } break; case 'h': @@ -7808,6 +7884,65 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent ) } break; case 'W': + if( fAlt ) + { + if ( CHEATER_CHEAT_LEVEL( ) ) + { + if ( InItemDescriptionBox( ) ) + { + CycleItemDescriptionItem( MAP_ITEMDESC_START_X, MAP_ITEMDESC_START_Y ); + } + } + } + else + { + if(bSelectedInfoChar != -1) + { + SOLDIERTYPE *pSoldier = MercPtrs[ gCharactersList[ bSelectedInfoChar ].usSolID ]; + //CHRISL: Try to update InSector value so we don't have to "activate" a sector + if(pSoldier->sSectorX == sSelMapX && pSoldier->sSectorY == sSelMapY && pSoldier->bSectorZ == iCurrentMapSectorZ && !pSoldier->flags.fBetweenSectors) + pSoldier->bInSector=TRUE; + if(OK_CONTROL_MERC( pSoldier )) + { + if(!fShowMapInventoryPool) + { + fShowMapInventoryPool = TRUE; + CreateDestroyMapInventoryPoolButtons( TRUE ); + } + if(!fShowInventoryFlag) + { + fShowInventoryFlag = TRUE; + } + //tais: borrowed the drop all items code from CHRISL to make it drop EVERYTHING! + if ( bSelectedInfoChar != -1 && fShowInventoryFlag && fShowMapInventoryPool && !(gTacticalStatus.fEnemyInSector) ) + { + for(int i = BODYPOSFINAL; iinv[i].exists() == true) + { + AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo); + DeleteObj(&pSoldier->inv[i]); + } + fTeamPanelDirty = TRUE; + fMapPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; + } + for(int i = HELMETPOS; iinv[i].exists() == true) + { + AutoPlaceObjectInInventoryStash(&pSoldier->inv[i], pSoldier->sGridNo); + DeleteObj(&pSoldier->inv[i]); + } + fTeamPanelDirty = TRUE; + fMapPanelDirty = TRUE; + fInterfacePanelDirty = DIRTYLEVEL2; + } + } + } + } + } + break; case 'w': if( fAlt ) { @@ -8565,7 +8700,27 @@ void PollRightButtonInMapView( UINT32 *puiNewEvent ) } */ - if( ( sSelMapX != sMapX ) || ( sSelMapY != sMapY ) ) + // HEADROCK HAM 4: Toggle Militia Restrictions manually. This occurs when the Mobile Restrictions + // view is turned on. Each click advances the sector's classification by 1. If max is reached, + // loops back to start. + if ( fShowMobileRestrictionsFlag == TRUE ) + { + // Restrict more. + if ( gubManualRestrictMilitia[ SECTOR( sMapX, sMapY ) ] > MANUAL_MOBILE_NO_ENTER ) + { + gubManualRestrictMilitia[ SECTOR( sMapX, sMapY ) ]--; + } + else + { + // Wrap back to highest. + gubManualRestrictMilitia[ SECTOR( sMapX, sMapY ) ] = MANUAL_MOBILE_NO_RESTRICTION; + } + fMapPanelDirty = TRUE; + // Skip the rest of this function. + return; + } + // don't change sectors if we've just done the militia restrictions thing. + else if( ( sSelMapX != sMapX ) || ( sSelMapY != sMapY ) ) { ChangeSelectedMapSector( sMapX, sMapY, ( INT8 )iCurrentMapSectorZ ); } @@ -9890,12 +10045,6 @@ void MPReadyButtonCallback( GUI_BUTTON *btn, INT32 reason ) // warn the user that cannot change once buying has commenced ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, gszMPMapscreenText[4]); } - /* - else if (RANDOM_SPAWN) - { - ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"Cannot change edge, the game is set to random spawn"); - } - */ } else { @@ -9958,7 +10107,7 @@ void MPTeamChangeCallback( MOUSE_REGION * pReason, INT32 iReason) // warn the user that cannot change once buying has commenced ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, gszMPMapscreenText[4]); } - else if (RANDOM_SPAWN) + else if (gRandomStartingEdge) { ScreenMsg( FONT_LTBLUE, MSG_MPSYSTEM, L"Cannot change edge, the game is set to random spawn"); } @@ -11460,7 +11609,7 @@ void HandleShadingOfLinesForContractMenu( void ) } // WANNE - MP: Disable "Dismiss" button when Random merc was selected, because we cannot hire any new merc - if (is_networked && RANDOM_MERCS) + if (is_networked && gRandomMercs) { ShadeStringInBox( ghContractBox, CONTRACT_MENU_TERMINATE ); } @@ -15013,7 +15162,8 @@ void HandleNewDestConfirmation( INT16 sMapX, INT16 sMapY ) if(gGameSettings.fOptions[ TOPTION_SILENT_SKYRIDER ] == FALSE) SkyRiderTalk( CONFIRM_DESTINATION ); } } - else + //CHRISL: If we're allowing Skyrider to drop mercs into a hot LZ, we don't need Skyrider telling us he isn't going to drop the mercs off. + else if(gGameExternalOptions.ubSkyriderHotLZ == 0) { // ok, but... you know there are enemies there... SkyRiderTalk( BELIEVED_ENEMY_SECTOR ); @@ -15950,7 +16100,7 @@ INT32 GetTotalContractExpenses ( void ) { iTotalCost += ( gMercProfiles[ pSoldier->ubProfile ].uiBiWeeklySalary / 14 ); } - if( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_1_WEEK ) + else if( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_1_WEEK ) { iTotalCost += ( gMercProfiles[ pSoldier->ubProfile ].uiWeeklySalary / 7 ); } diff --git a/Strategic/mapscreen.h b/Strategic/mapscreen.h index ddb25e66..16a216a7 100644 --- a/Strategic/mapscreen.h +++ b/Strategic/mapscreen.h @@ -8,6 +8,8 @@ #define MAP_WORLD_X 18 #define MAP_WORLD_Y 18 +extern int MAP_ITEMDESC_START_Y; +extern int MAP_ITEMDESC_START_X; #define MAX_TOWN_NAME_LENGHT 32 #define MAX_SECTOR_NAME_LENGTH 128 @@ -99,4 +101,14 @@ BOOLEAN InitializeInvPanelCoordsVehicle( ); // HEADROCK HAM 3.6: Calculate daily cost for all mercs who have one. INT32 GetTotalContractExpenses ( void ); +// HEADROCK HAM 4: enumarate Manual Militia Restriction states +enum +{ + MANUAL_MOBILE_RESTRICTED, + MANUAL_MOBILE_NO_ENTER, + MANUAL_MOBILE_NO_LEAVE, + MANUAL_MOBILE_NO_RESTRICTION, + NUM_MANUAL_MOBILE_STATES, +}; + #endif \ No newline at end of file diff --git a/Strategic/strategic town reputation.cpp b/Strategic/strategic town reputation.cpp index e6745951..53965f6d 100644 --- a/Strategic/strategic town reputation.cpp +++ b/Strategic/strategic town reputation.cpp @@ -39,8 +39,11 @@ void InitializeProfilesForTownReputation( void ) UINT32 uiProfileId = 0; // initialize the town opinion values in each recruitable merc's profile structure - for( uiProfileId = 0; uiProfileId < FIRST_NPC; uiProfileId++ ) + //for( uiProfileId = 0; uiProfileId < FIRST_NPC; uiProfileId++ ) + //new profiles by Jazz + for( uiProfileId = 0; uiProfileId < NUM_PROFILES; uiProfileId++ ) { + if ( gProfilesIMP[uiProfileId].ProfilId == uiProfileId || gProfilesRPC[uiProfileId].ProfilId == uiProfileId || gProfilesAIM[uiProfileId].ProfilId == uiProfileId || gProfilesMERC[uiProfileId].ProfilId == uiProfileId) memset( &( gMercProfiles[ uiProfileId ].bMercTownReputation ), INITIAL_TOWN_REPUTATION, sizeof( gMercProfiles[ uiProfileId ].bMercTownReputation ) ); } } @@ -62,7 +65,8 @@ void PostEventsForSpreadOfTownOpinion( void ) UINT8 GetTownOpinionOfMerc( UINT8 ubProfileId, UINT8 ubTownId ) { - Assert(ubProfileId < FIRST_NPC); + //new profiles by Jazz + //Assert(ubProfileId < FIRST_NPC); Assert(ubTownId < NUM_TOWNS); // return amount @@ -87,7 +91,8 @@ UINT8 GetTownOpinionOfMercForSoldier( SOLDIERTYPE *pSoldier, UINT8 ubTownId ) void UpdateTownOpinionOfThisMerc( UINT8 ubProfileId, UINT8 ubTownId, INT8 bAmount ) { - Assert(ubProfileId < FIRST_NPC); + //new profiles by Jazz + //Assert(ubProfileId < FIRST_NPC); Assert(ubTownId < NUM_TOWNS); // check if opinion would be affected too greatly @@ -132,8 +137,11 @@ void HandleSpreadOfAllTownsOpinion( void ) ScreenMsg( MSG_FONT_RED, MSG_DEBUG, L"%s - Spreading town opinions about mercs", WORLDTIMESTR ); // run though all player-recruitable profiles and update towns opinion of mercs - for( ubProfileId = 0; ubProfileId < FIRST_NPC; ubProfileId++ ) + //for( ubProfileId = 0; ubProfileId < FIRST_NPC; ubProfileId++ ) + //new profiles by Jazz + for( ubProfileId = 0; ubProfileId < NUM_PROFILES; ubProfileId++ ) { + if ( gProfilesIMP[ubProfileId].ProfilId == ubProfileId || gProfilesAIM[ubProfileId].ProfilId == ubProfileId || gProfilesMERC[ubProfileId].ProfilId == ubProfileId || gProfilesRPC[ubProfileId].ProfilId == ubProfileId) HandleSpreadOfTownOpinionForMerc( ubProfileId ); } } @@ -146,7 +154,7 @@ void HandleSpreadOfTownOpinionForMerc( UINT8 ubProfileId ) INT8 iCounterA, iCounterB; INT8 bOpinionOfTownA, bOpinionOfTownB; - Assert(ubProfileId < FIRST_NPC); + //Assert(ubProfileId < FIRST_NPC); for( iCounterA = FIRST_TOWN; iCounterA < NUM_TOWNS; iCounterA++ ) { diff --git a/Strategic/strategicmap.cpp b/Strategic/strategicmap.cpp index 9e88d07f..7d51463f 100644 --- a/Strategic/strategicmap.cpp +++ b/Strategic/strategicmap.cpp @@ -108,9 +108,11 @@ #include "connect.h" //hayden added alot ""'s to get around client spawing random/different placed AI #include "SaveLoadGame.h" +#include "Strategic Mines.h" +#include "Strategic Mines LUA.h" +#include "UndergroundInit.h" -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" +#include "sgp_logger.h" //forward declarations of common classes to eliminate includes class OBJECTTYPE; @@ -136,7 +138,9 @@ BOOLEAN HandleDefiniteUnloadingOfWorld( UINT8 ubUnloadCode ); extern INT32 gsRobotGridNo; extern BOOLEAN gfUndergroundTacticalTraversal; -extern MINE_LOCATION_TYPE gMineLocation[MAX_NUMBER_OF_MINES]; +//extern MINE_LOCATION_TYPE gMineLocation[MAX_NUMBER_OF_MINES]; +//extern MINE_STATUS_TYPE gMineStatus[MAX_NUMBER_OF_MINES]; + extern void CalculateNonPersistantPBIInfo(); @@ -299,6 +303,11 @@ STR8 pHortStrings[]={ // HEADROCK HAM 3.6: Array to hold user-defined sector names CHAR16 gzSectorNames[256][4][MAX_SECTOR_NAME_LENGTH]; +// moved to lua +//CHAR16 gzSectorUndergroundNames1[256][4][MAX_SECTOR_NAME_LENGTH]; +//CHAR16 gzSectorUndergroundNames2[256][4][MAX_SECTOR_NAME_LENGTH]; +//CHAR16 gzSectorUndergroundNames3[256][4][MAX_SECTOR_NAME_LENGTH]; + BOOLEAN ReadInStrategicMapSectorTownNames(STR fileName, BOOLEAN localizedVersion); void DoneFadeOutAdjacentSector( void ); @@ -623,7 +632,7 @@ samsiteEndElementHandle(void *userData, const XML_Char *name) { pData->curElement = SAMSITE_ELEMENT_SAM; - pData->curSamInfo.samGridNoA = (INT16)atol(pData->szCharData); + pData->curSamInfo.samGridNoA = atol(pData->szCharData); if ( pData->curSamInfo.samGridNoA >= WORLD_MAX ) { pData->curSamInfo.samGridNoA = 0; @@ -633,7 +642,7 @@ samsiteEndElementHandle(void *userData, const XML_Char *name) { pData->curElement = SAMSITE_ELEMENT_SAM; - pData->curSamInfo.samGridNoB = (INT16)atol(pData->szCharData); + pData->curSamInfo.samGridNoB = atol(pData->szCharData); if ( pData->curSamInfo.samGridNoB >= WORLD_MAX ) { pData->curSamInfo.samGridNoB = 1; @@ -1456,40 +1465,43 @@ void EndLoadScreen( ) fclose( fp ); } #else - CLog timeResults(L"TimeResults.txt", true); + sgp::Logger_ID time_log_id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(time_log_id, L"TimeResults.txt", true, sgp::Logger::FLUSH_ON_ENDL); + sgp::Logger::LogInstance timeResults = SGP_LOG(time_log_id); + ScreenMsg( FONT_YELLOW, MSG_TESTVERSION, L"See JA2\\Data\\TimeResults.txt for more detailed timings." ); //Record all of the timings. - timeResults << str << CLog::ENDL; - timeResults << "EnterSector() supersets LoadWorld(). This includes other external sections." << CLog::ENDL; + timeResults << str << sgp::endl; + timeResults << "EnterSector() supersets LoadWorld(). This includes other external sections." << vfs::Log::endl; //FileRead() - timeResults << CLog::ENDL << CLog::ENDL << "VARIOUS FUNCTION TIMINGS (exclusive of actual function timings in second heading)" << CLog::ENDL; + timeResults << sgp::endl << vfs::Log::endl << "VARIOUS FUNCTION TIMINGS (exclusive of actual function timings in second heading)" << sgp::endl; uiSeconds = uiTotalFileReadTime / 1000; uiHundreths = (uiTotalFileReadTime / 10) % 100; //fprintf( fp, "FileRead: %d.%02d (called %d times)\n", uiSeconds, uiHundreths, uiTotalFileReadCalls ); - timeResults << "FileRead: " <fVisited || gfGettingNameFromSaveLoadScreen ) ) + + #if 0 // reading sector names from lua now + //////////////////////////////////// + // Read and verify XML sector names + + INT8 bMineIndex; + ubSectorID = (UINT8)SECTOR( sSectorX, sSectorY ); + AssertGE(ubSectorID, 0); + AssertLT(ubSectorID,256); + pSector = &SectorInfo[ ubSectorID ]; + ubLandType = pSector->ubTraversability[ 4 ]; + swprintf( zString, L"%c%d: ", 'A' + sSectorY - 1, sSectorX ); + + BOOLEAN fSectorHasXMLNames = TRUE; + CHAR16 zUnexploredUnderground[MAX_SECTOR_NAME_LENGTH]; + CHAR16 zDetailedUnexploredUnderground[MAX_SECTOR_NAME_LENGTH]; + CHAR16 zExploredUnderground[MAX_SECTOR_NAME_LENGTH]; + CHAR16 zDetailedExploredUnderground[MAX_SECTOR_NAME_LENGTH]; + + if ( bSectorZ == 1 ) + { + wcscpy( zUnexploredUnderground, gzSectorUndergroundNames1[ ubSectorID ][0] ); + wcscpy( zDetailedUnexploredUnderground, gzSectorUndergroundNames1[ ubSectorID ][1] ); + wcscpy( zExploredUnderground, gzSectorUndergroundNames1[ ubSectorID ][2] ); + wcscpy( zDetailedExploredUnderground, gzSectorUndergroundNames1[ ubSectorID ][3] ); + } + else if ( bSectorZ == 2 ) { - bMineIndex = GetIdOfMineForSector( sSectorX, sSectorY, bSectorZ ); - if( bMineIndex != -1 ) + wcscpy( zUnexploredUnderground, gzSectorUndergroundNames2[ ubSectorID ][0] ); + wcscpy( zDetailedUnexploredUnderground, gzSectorUndergroundNames2[ ubSectorID ][1] ); + wcscpy( zExploredUnderground, gzSectorUndergroundNames2[ ubSectorID ][2] ); + wcscpy( zDetailedExploredUnderground, gzSectorUndergroundNames2[ ubSectorID ][3] ); + } + else if ( bSectorZ == 3 ) + { + wcscpy( zUnexploredUnderground, gzSectorUndergroundNames3[ ubSectorID ][0] ); + wcscpy( zDetailedUnexploredUnderground, gzSectorUndergroundNames3[ ubSectorID ][1] ); + wcscpy( zExploredUnderground, gzSectorUndergroundNames3[ ubSectorID ][2] ); + wcscpy( zDetailedExploredUnderground, gzSectorUndergroundNames3[ ubSectorID ][3] ); + } + + if (zUnexploredUnderground[0] == 0 || zDetailedUnexploredUnderground[0] == 0 || zExploredUnderground[0] == 0 || zDetailedExploredUnderground[0] == 0) + { + fSectorHasXMLNames = FALSE; + } + + if (fSectorHasXMLNames) // UNDERGROUND XML + { + if ( pUnderground ) { - swprintf( zString, L"%c%d: %s %s", 'A' + sSectorY - 1, sSectorX, pTownNames[ GetTownAssociatedWithMine( bMineIndex ) ], pwMineStrings[ 0 ] ); - } - else switch( SECTOR( sSectorX, sSectorY ) ) - { - case SEC_A10: - swprintf( zString, L"A10: %s", pLandTypeStrings[ REBEL_HIDEOUT ] ); - break; - case SEC_J9: - swprintf( zString, L"J9: %s", pLandTypeStrings[ TIXA_DUNGEON ] ); - break; - case SEC_K4: - swprintf( zString, L"K4: %s", pLandTypeStrings[ ORTA_BASEMENT ] ); - break; - case SEC_O3: - swprintf( zString, L"O3: %s", pLandTypeStrings[ TUNNEL ] ); - break; - case SEC_P3: - swprintf( zString, L"P3: %s", pLandTypeStrings[ SHELTER ] ); - break; - default: - if (pUnderground->ubNumCreatures) - swprintf( zString, L"%c%d: %s", 'A' + sSectorY - 1, sSectorX, pLandTypeStrings[ CREATURE_LAIR ] ); + bMineIndex = GetIdOfMineForSector( sSectorX, sSectorY, bSectorZ ); + if( bMineIndex != -1 ) + { + swprintf( zString, L"%c%d: %s %s", 'A' + sSectorY - 1, sSectorX, pTownNames[ GetTownAssociatedWithMine( bMineIndex ) ], pwMineStrings[ 0 ] ); + } + else if ( pUnderground->fVisited ) + { + if (fDetailed) + { + wcscat( zString, zDetailedExploredUnderground ); + } else - swprintf( zString, L"%c%d-%d", 'A' + sSectorY - 1, sSectorX, bSectorZ ); - break; + { + wcscat( zString, zExploredUnderground ); + } + } + else + { + if (fDetailed) + { + wcscat( zString, zDetailedUnexploredUnderground ); + } + else + { + wcscat( zString, zUnexploredUnderground ); + } + } + + if (pUnderground->ubNumCreatures) + swprintf( zString, L"%c%d: %s", 'A' + sSectorY - 1, sSectorX, pLandTypeStrings[ CREATURE_LAIR ] ); + //else + // swprintf( zString, L"%c%d-%d", 'A' + sSectorY - 1, sSectorX, bSectorZ ); + } + } + else // UNDERGROUND HARDCODED + { + pUnderground = FindUnderGroundSector( sSectorX, sSectorY, bSectorZ ); + if( pUnderground && ( pUnderground->fVisited || gfGettingNameFromSaveLoadScreen ) ) + { + bMineIndex = GetIdOfMineForSector( sSectorX, sSectorY, bSectorZ ); + if( bMineIndex != -1 ) + { + swprintf( zString, L"%c%d: %s %s", 'A' + sSectorY - 1, sSectorX, pTownNames[ GetTownAssociatedWithMine( bMineIndex ) ], pwMineStrings[ 0 ] ); + } + else switch( SECTOR( sSectorX, sSectorY ) ) + { + case SEC_A10: + swprintf( zString, L"A10: %s", pLandTypeStrings[ REBEL_HIDEOUT ] ); + break; + case SEC_J9: + swprintf( zString, L"J9: %s", pLandTypeStrings[ TIXA_DUNGEON ] ); + break; + case SEC_K4: + swprintf( zString, L"K4: %s", pLandTypeStrings[ ORTA_BASEMENT ] ); + break; + case SEC_O3: + swprintf( zString, L"O3: %s", pLandTypeStrings[ TUNNEL ] ); + break; + case SEC_P3: + swprintf( zString, L"P3: %s", pLandTypeStrings[ SHELTER ] ); + break; + default: + if (pUnderground->ubNumCreatures) + swprintf( zString, L"%c%d: %s", 'A' + sSectorY - 1, sSectorX, pLandTypeStrings[ CREATURE_LAIR ] ); + else + swprintf( zString, L"%c%d-%d", 'A' + sSectorY - 1, sSectorX, bSectorZ ); + break; + } + } + else + { //Display nothing + wcscpy( zString, L"" ); } } - else - { //Display nothing - wcscpy( zString, L"" ); - } + #else + + // TODO: the code is riddled with (potential) buffer overruns + // this totally needs to be fixed sometime + // anyway, only trying to not create another one here + // found calls to this function with buffers as small as 50 elements + g_luaUnderground.GetSectorName(sSectorX, sSectorY, bSectorZ, pUnderground, zString, 50, fDetailed); + + #endif } - else + else // SECTORS ABOVE GROUND { bTownNameID = StrategicMap[ CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].bNameId; @@ -3076,7 +3200,7 @@ void GetSectorIDString( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , STR16 zS fSectorHasXMLNames = FALSE; } - if (fSectorHasXMLNames) + if (fSectorHasXMLNames) // ABOVE GROUND XML { // HEADROCK HAM 3.6: The program can now read custom names from XML for all above-ground sectors. // In the event that a specific name or set of names is missing, the program generates a default @@ -3121,111 +3245,111 @@ void GetSectorIDString( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , STR16 zS } } } - else + else // ABOVE GROUND HARDCODED { // Default JA2 Name selection - if ( bTownNameID == BLANK_SECTOR ) - { - // OK, build string id like J11 - // are we dealing with the unfound towns? - switch( ubSectorID ) + if ( bTownNameID == BLANK_SECTOR ) { - case SEC_D2: //Chitzena SAM - if( !fSamSiteFound[ SAM_SITE_ONE ] ) - wcscat( zString, pLandTypeStrings[ TROPICS ] ); - else if( fDetailed ) - wcscat( zString, pLandTypeStrings[ TROPICS_SAM_SITE ] ); - else - wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); - break; - case SEC_D15: //Drassen SAM - if( !fSamSiteFound[ SAM_SITE_TWO ] ) - wcscat( zString, pLandTypeStrings[ SPARSE ] ); - else if( fDetailed ) - wcscat( zString, pLandTypeStrings[ SPARSE_SAM_SITE ] ); - else - wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); - break; - case SEC_I8: //Cambria SAM - if( !fSamSiteFound[ SAM_SITE_THREE ] ) - wcscat( zString, pLandTypeStrings[ SAND ] ); - else if( fDetailed ) - wcscat( zString, pLandTypeStrings[ SAND_SAM_SITE ] ); - else - wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); - break; - default: - wcscat( zString, pLandTypeStrings[ ubLandType ] ); - break; - } - } - else - { - switch( ubSectorID ) - { - case SEC_B13: - if( fDetailed ) - wcscat( zString, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] ); - else - wcscat( zString, pTownNames[ DRASSEN ] ); - break; - case SEC_F8: - if( fDetailed ) - wcscat( zString, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] ); - else - wcscat( zString, pTownNames[ CAMBRIA ] ); - break; - case SEC_J9: //Tixa - if( !fFoundTixa ) - wcscat( zString, pLandTypeStrings[ SAND ] ); - else - wcscat( zString, pTownNames[ TIXA ] ); - break; - case SEC_K4: //Orta - if( !fFoundOrta ) - wcscat( zString, pLandTypeStrings[ SWAMP ] ); - else - wcscat( zString, pTownNames[ ORTA ] ); - break; - case SEC_N3: - if( fDetailed ) - wcscat( zString, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] ); - else - wcscat( zString, pTownNames[ MEDUNA ] ); - break; - default: - if( ubSectorID == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] ) - { //Meduna's SAM site - if( fDetailed ) - wcscat( zString, pLandTypeStrings[ MEDUNA_SAM_SITE ] ); + // OK, build string id like J11 + // are we dealing with the unfound towns? + switch( ubSectorID ) + { + case SEC_D2: //Chitzena SAM + if( !fSamSiteFound[ SAM_SITE_ONE ] ) + wcscat( zString, pLandTypeStrings[ TROPICS ] ); + else if( fDetailed ) + wcscat( zString, pLandTypeStrings[ TROPICS_SAM_SITE ] ); else wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); - } - else - { //All other towns that are known since beginning of the game. - wcscat( zString, pTownNames[ bTownNameID ] ); + break; + case SEC_D15: //Drassen SAM + if( !fSamSiteFound[ SAM_SITE_TWO ] ) + wcscat( zString, pLandTypeStrings[ SPARSE ] ); + else if( fDetailed ) + wcscat( zString, pLandTypeStrings[ SPARSE_SAM_SITE ] ); + else + wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); + break; + case SEC_I8: //Cambria SAM + if( !fSamSiteFound[ SAM_SITE_THREE ] ) + wcscat( zString, pLandTypeStrings[ SAND ] ); + else if( fDetailed ) + wcscat( zString, pLandTypeStrings[ SAND_SAM_SITE ] ); + else + wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); + break; + default: + wcscat( zString, pLandTypeStrings[ ubLandType ] ); + break; + } + } + else + { + switch( ubSectorID ) + { + case SEC_B13: if( fDetailed ) - { - switch( ubSectorID ) - { //Append the word, "mine" for town sectors containing a mine. - case SEC_B2: - case SEC_D4: - case SEC_D13: - case SEC_H3: - case SEC_H8: - case SEC_I14: - wcscat( zString, L" " ); //space - wcscat( zString, pwMineStrings[ 0 ] ); //then "Mine" - break; + wcscat( zString, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] ); + else + wcscat( zString, pTownNames[ DRASSEN ] ); + break; + case SEC_F8: + if( fDetailed ) + wcscat( zString, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] ); + else + wcscat( zString, pTownNames[ CAMBRIA ] ); + break; + case SEC_J9: //Tixa + if( !fFoundTixa ) + wcscat( zString, pLandTypeStrings[ SAND ] ); + else + wcscat( zString, pTownNames[ TIXA ] ); + break; + case SEC_K4: //Orta + if( !fFoundOrta ) + wcscat( zString, pLandTypeStrings[ SWAMP ] ); + else + wcscat( zString, pTownNames[ ORTA ] ); + break; + case SEC_N3: + if( fDetailed ) + wcscat( zString, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] ); + else + wcscat( zString, pTownNames[ MEDUNA ] ); + break; + default: + if( ubSectorID == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] ) + { //Meduna's SAM site + if( fDetailed ) + wcscat( zString, pLandTypeStrings[ MEDUNA_SAM_SITE ] ); + else + wcscat( zString, pLandTypeStrings[ SAM_SITE ] ); + } + else + { //All other towns that are known since beginning of the game. + wcscat( zString, pTownNames[ bTownNameID ] ); + if( fDetailed ) + { + switch( ubSectorID ) + { //Append the word, "mine" for town sectors containing a mine. + case SEC_B2: + case SEC_D4: + case SEC_D13: + case SEC_H3: + case SEC_H8: + case SEC_I14: + wcscat( zString, L" " ); //space + wcscat( zString, pwMineStrings[ 0 ] ); //then "Mine" + break; + } } } - } - break; + break; + } } } } } -} UINT8 SetInsertionDataFromAdjacentMoveDirection( SOLDIERTYPE *pSoldier, UINT8 ubTacticalDirection, INT32 sAdditionalData )//dnl ch56 151009 @@ -3653,16 +3777,52 @@ void AllMercsWalkedToExitGrid() { PLAYERGROUP *pPlayer; BOOLEAN fDone; + // SANDRO was here.. made some tweaks, fixed some stuff + BOOLEAN fEnemiesInLoadedSector = FALSE; + if( NumEnemiesInAnySector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) ) + { + fEnemiesInLoadedSector = TRUE; + //////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if enemies are in sector, handle morale hit for fleeing + // Minor bug fix - check certain circumstances and don't reduce the morale if the fight is not over yet + // if all mercs leaving, morale gets hit + // if one merc only leaves, but there are others fighting on, don't reduce the morale + // if sector is about to be loaded and there are enemies in the current, then all mercs are leaving, so the morale gets hit + if( ( gubAdjacentJumpCode == JUMP_ALL_NO_LOAD && gpAdjacentGroup->ubGroupSize >= PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, (UINT8)gbWorldSectorZ )) || + ( gubAdjacentJumpCode == JUMP_SINGLE_NO_LOAD && PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, (UINT8)gbWorldSectorZ ) <= 1 ) || + ( gubAdjacentJumpCode == JUMP_ALL_LOAD_NEW || gubAdjacentJumpCode == JUMP_SINGLE_LOAD_NEW ) ) + { + HandleLoyaltyImplicationsOfMercRetreat( RETREAT_TACTICAL_TRAVERSAL, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + + // End inetrrogation quest if we left the sector, but haven't killed all enemies + if ( gWorldSectorX == 7 && gWorldSectorY == 14 && gbWorldSectorZ == 0 && gubQuest[ QUEST_INTERROGATION ] == QUESTINPROGRESS ) + { + // Finish quest, although not give points here... + InternalEndQuest( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY, FALSE ); + // ... give them manually, but halved + GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 4, NO_PROFILE ); + // Also get us know, we finished the quest + ResetHistoryFact( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY ); + } + } + //////////////////////////////////////////////////////////////////////////////////////// - HandlePotentialMoraleHitForSkimmingSectors( gpAdjacentGroup ); + HandlePotentialMoraleHitForSkimmingSectors( gpAdjacentGroup ); + } if( gubAdjacentJumpCode == JUMP_ALL_NO_LOAD || gubAdjacentJumpCode == JUMP_SINGLE_NO_LOAD ) { Assert( gpAdjacentGroup ); - pPlayer = gpAdjacentGroup->pPlayerList; + //pPlayer = gpAdjacentGroup->pPlayerList; // SANDRO - why was this here twice? pPlayer = gpAdjacentGroup->pPlayerList; while( pPlayer ) { + ///////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - times retreated counter + if( fEnemiesInLoadedSector && pPlayer->pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pPlayer->pSoldier->ubProfile ].records.usBattlesRetreated++; + ///////////////////////////////////////////////////////////////////////////////// + SetInsertionDataFromAdjacentMoveDirection( pPlayer->pSoldier, gubTacticalDirection, gsAdditionalData ); RemoveSoldierFromTacticalSector( pPlayer->pSoldier, TRUE ); @@ -3675,9 +3835,19 @@ void AllMercsWalkedToExitGrid() SetDefaultSquadOnSectorEntry( TRUE ); + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - reset num enemies here if the sector was unloaded + if( gWorldSectorX == 0 && gWorldSectorX == 0 && gbWorldSectorZ == -1 ) + { + memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// } else { + // SANDRO - reset number of enemies here, we are about to load a new sector + memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); + //Because we are actually loading the new map, and we are physically traversing, we don't want //to bring up the prebattle interface when we arrive if there are enemies there. This flag //ignores the initialization of the prebattle interface and clears the flag. @@ -3698,6 +3868,7 @@ void AllMercsWalkedToExitGrid() AddCharacterToUniqueSquad( pPlayer->pSoldier ); break; } + InitSoldierOppList( pPlayer->pSoldier ); pPlayer = pPlayer->next; } if( !pPlayer ) @@ -3711,6 +3882,12 @@ void AllMercsWalkedToExitGrid() pPlayer = gpAdjacentGroup->pPlayerList; while( pPlayer ) { + ///////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - times retreated counter + if( fEnemiesInLoadedSector && pPlayer->pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pPlayer->pSoldier->ubProfile ].records.usBattlesRetreated++; + ///////////////////////////////////////////////////////////////////////////////// + SetInsertionDataFromAdjacentMoveDirection( pPlayer->pSoldier, gubTacticalDirection, gsAdditionalData ); pPlayer = pPlayer->next; @@ -3721,10 +3898,11 @@ void AllMercsWalkedToExitGrid() gFadeOutDoneCallback = DoneFadeOutExitGridSector; FadeOutGameScreen( ); } - if( !PlayerMercsInSector( (UINT8)gsAdjacentSectorX, (UINT8)gsAdjacentSectorY, (UINT8)gbAdjacentSectorZ ) ) - { - HandleLoyaltyImplicationsOfMercRetreat( RETREAT_TACTICAL_TRAVERSAL, gsAdjacentSectorX, gsAdjacentSectorY, gbAdjacentSectorZ ); - } + // SANDRO - This actually never happeneds, moved up + //if( !PlayerMercsInSector( (UINT8)gsAdjacentSectorX, (UINT8)gsAdjacentSectorY, (UINT8)gbAdjacentSectorZ ) ) + //{ + // HandleLoyaltyImplicationsOfMercRetreat( RETREAT_TACTICAL_TRAVERSAL, gsAdjacentSectorX, gsAdjacentSectorY, gbAdjacentSectorZ ); + //} if( gubAdjacentJumpCode == JUMP_ALL_NO_LOAD || gubAdjacentJumpCode == JUMP_SINGLE_NO_LOAD ) { gfTacticalTraversal = FALSE; @@ -3782,10 +3960,32 @@ void AllMercsHaveWalkedOffSector( ) if( NumEnemiesInAnySector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) ) { fEnemiesInLoadedSector = TRUE; + //////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if enemies are in sector, handle morale hit for fleeing + // Minor bug fix - check certain circumstances and don't reduce the morale if the fight is not over yet + // if all mercs leaving, morale gets hit + // if one merc only leaves, but there are others fighting on, don't reduce the morale + // if sector is about to be loaded and there are enemies in the current, then all mercs are leaving alway + if( ( gubAdjacentJumpCode == JUMP_ALL_NO_LOAD && gpAdjacentGroup->ubGroupSize >= PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, (UINT8)gbWorldSectorZ )) || + ( gubAdjacentJumpCode == JUMP_SINGLE_NO_LOAD && PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, (UINT8)gbWorldSectorZ ) <= 1 ) || + ( gubAdjacentJumpCode == JUMP_ALL_LOAD_NEW || gubAdjacentJumpCode == JUMP_SINGLE_LOAD_NEW ) ) + { + HandleLoyaltyImplicationsOfMercRetreat( RETREAT_TACTICAL_TRAVERSAL, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + + // End inetrrogation quest if we left the sector, but haven't killed all enemies + if ( gWorldSectorX == 7 && gWorldSectorY == 14 && gbWorldSectorZ == 0 && gubQuest[ QUEST_INTERROGATION ] == QUESTINPROGRESS ) + { + // Finish quest, although not give points here... + InternalEndQuest( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY, FALSE ); + // ... give them manually, but halved + GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 4, NO_PROFILE ); + // Also get us know, we finished the quest + ResetHistoryFact( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY ); + } + } + //////////////////////////////////////////////////////////////////////////////////////// } - HandleLoyaltyImplicationsOfMercRetreat( RETREAT_TACTICAL_TRAVERSAL, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); - //Setup strategic traversal information if( guiAdjacentTraverseTime <= 5 ) { @@ -3813,15 +4013,41 @@ void AllMercsHaveWalkedOffSector( ) pPlayer = gpAdjacentGroup->pPlayerList; while( pPlayer ) { + ///////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - times retreated counter + if( fEnemiesInLoadedSector && pPlayer->pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pPlayer->pSoldier->ubProfile ].records.usBattlesRetreated++; + ///////////////////////////////////////////////////////////////////////////////// RemoveSoldierFromTacticalSector( pPlayer->pSoldier, TRUE ); pPlayer = pPlayer->next; } SetDefaultSquadOnSectorEntry( TRUE ); + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - reset num enemies here if the sector was unloaded + if( !fEnemiesInLoadedSector || (gWorldSectorX == 0 && gWorldSectorX == 0 && gbWorldSectorZ == -1 ) ) + { + memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// } else { + // SANDRO - reset number of enemies here, we are about to load a new sector + memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); + if( fEnemiesInLoadedSector ) - { //We are retreating from a sector with enemies in it and there are no mercs left so + { + ///////////////////////////////////////////////////////////////////////////////// + // SANDRO - merc records - times retreated counter + pPlayer = gpAdjacentGroup->pPlayerList; + while( pPlayer ) + { + if( fEnemiesInLoadedSector && pPlayer->pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pPlayer->pSoldier->ubProfile ].records.usBattlesRetreated++; + pPlayer = pPlayer->next; + } + ///////////////////////////////////////////////////////////////////////////////// + //We are retreating from a sector with enemies in it and there are no mercs left so //warp the game time by 5 minutes to simulate the actual retreat. This restricts the //player from immediately coming back to the same sector they left to perhaps take advantage //of the tactical placement gui to get into better position. Additionally, if there are any @@ -5438,8 +5664,6 @@ void HandleSlayDailyEvent( void ) } } - - BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY ) { // HEADROCK HAM 3.5: Fix for assertion errors associated with rain checks. @@ -5448,7 +5672,10 @@ BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY ) return( FALSE ); } - if ( SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == SAND ) + // SANDRO - added more terrain types for heat intolerant feature + if ( SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == SAND || + SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == SAND_ROAD || + SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == SAND_SAM_SITE ) { // desert return( TRUE ); @@ -5458,7 +5685,20 @@ BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY ) return( FALSE ); } } - +// SANDRO - added function +BOOLEAN IsSectorTropical( INT16 sSectorX, INT16 sSectorY ) +{ + if (SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == TROPICS || + SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == TROPICS_ROAD || + SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == TROPICS_SAM_SITE ) + { + return ( TRUE ); + } + else + { + return ( FALSE ); + } +} BOOLEAN HandleDefiniteUnloadingOfWorld( UINT8 ubUnloadCode ) @@ -5800,7 +6040,7 @@ void SetupProfileInsertionDataForSoldier( SOLDIERTYPE *pSoldier ) void HandlePotentialMoraleHitForSkimmingSectors( GROUP *pGroup ) { - PLAYERGROUP *pPlayer; + //PLAYERGROUP *pPlayer; if ( !gTacticalStatus.fHasEnteredCombatModeSinceEntering && gTacticalStatus.fEnemyInSector ) { @@ -5810,16 +6050,17 @@ void HandlePotentialMoraleHitForSkimmingSectors( GROUP *pGroup ) //time to setup a good ambush! pGroup->uiFlags |= GROUPFLAG_HIGH_POTENTIAL_FOR_AMBUSH; - pPlayer = pGroup->pPlayerList; + //SANDRO - WTF?!? + //pPlayer = pGroup->pPlayerList; - while( pPlayer ) - { - // Do morale hit... - // CC look here! - // pPlayer->pSoldier + //while( pPlayer ) + //{ + // // Do morale hit... + // // CC look here! + // // pPlayer->pSoldier - pPlayer = pPlayer->next; - } + // pPlayer = pPlayer->next; + //} } } diff --git a/Strategic/strategicmap.h b/Strategic/strategicmap.h index 730d3ae2..087228cd 100644 --- a/Strategic/strategicmap.h +++ b/Strategic/strategicmap.h @@ -160,6 +160,7 @@ INT32 GetNumberOfSAMSitesUnderPlayerControl( void ); BOOLEAN IsThereAFunctionalSAMSiteInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ); BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY ); +BOOLEAN IsSectorTropical( INT16 sSectorX, INT16 sSectorY ); // added by SANDRO // sam site under players control? INT32 SAMSitesUnderPlayerControl( INT16 sX, INT16 sY ); diff --git a/Tactical/Animation Control.cpp b/Tactical/Animation Control.cpp index 363981d5..df989ca3 100644 --- a/Tactical/Animation Control.cpp +++ b/Tactical/Animation Control.cpp @@ -18,6 +18,7 @@ #include "rotting corpses.h" #include "points.h" #include "Debug Control.h" +#include "Random.h" #endif #include "connect.h" @@ -42,6 +43,35 @@ typedef struct static UINT16 CrouchedThrowAnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,460,10,11,12,13,14,442,603,999,0,0,0,0 }; // +///ddd +static UINT16 StoneAnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,402,1,2,3,4,5,6,7,8,402,1,2,3,4,5,6,7,8,601,999,0,0,0,0,0 }; + +static UINT16 CrouchedShootRocketScript[MAX_FRAMES_PER_ANIM] = +{757,1,2,3,4,5,6,7,8,9,10,11,12,470,430,13,14,15,16,477,17,18,19,20,753,499,999,0,0,0,0}; +static UINT16 SwatWithKnifeScript[MAX_FRAMES_PER_ANIM] = +//{1,2,3,4,5,6,7,703,8,9,10,11,704,12,13,14,15,16,17,18,19,501,999,0,0,0,0}; +{5,703,6,7,8,9,10,11,704,12,13,14,15,16,501,999,0,0,0,0};// 2 +static UINT16 SwatBackWithKnifeScript[MAX_FRAMES_PER_ANIM] = +{16,15,14,13,12,704,11,10,9,8,7,6,703,5,501,999,0,0,0,0}; + +static UINT16 SwatBackWithNothingScript[MAX_FRAMES_PER_ANIM] = +{16,15,14,13,12,704,11,10,9,8,7,6,703,5,501,999,0,0,0,0}; + +//, . +static UINT16 ThrowGrenadeStanceAnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,460,11,12,13,14,15,16,17,18,19,442,601,999,0,0,0,0 }; +static UINT16 LobGrenadeStanceAnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,460,11,12,13,14,15,16,17,18,19,442,601,999,0,0,0,0 }; +// +static UINT16 ROLL_L_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,501,999,0,0,0,0 }; +static UINT16 ROLL_R_AnimationScript[MAX_FRAMES_PER_ANIM] = { 14,13,12,11,10,9,8,7,6,5,4,3,2,1,501,999,0,0,0,0 }; + + + + + + + + + ANI_SPEED_DEF gubAnimCrawlSpeeds[ TOTALBODYTYPES ]; //Block for anim file UINT16 gusAnimInst[ MAX_ANIMATIONS ][ MAX_FRAMES_PER_ANIM ]; @@ -929,6 +959,27 @@ ANIMCONTROLTYPE gAnimControl[ NUMANIMATIONSTATES ] = // crouch throwing "THROW ITEM CROUCHED", 0, 80, (FLOAT)0, ANIM_STATIONARY | ANIM_NOMOVE_MARKER | ANIM_NONINTERRUPT | ANIM_MIN_EFFORT | ANIM_ATTACK, ANIM_CROUCH, ANIM_CROUCH, -1, // crouch throwing gubAnimSurfaceIndex[ REGMALE ][ THROW_ITEM_CROUCHED ] = RGMCRTHROW; // + //ddd shoot rocket crouched + gubAnimSurfaceIndex[ REGMALE ][ SHOOT_ROCKET_CROUCHED ] = RGMCRROCKET; + gubAnimSurfaceIndex[ REGMALE ][ SWATTING_WK ] = RGMSWKNIFE; + gubAnimSurfaceIndex[ REGMALE ][ SWAT_BACKWARDS_WK ] = RGMSWKNIFE; + gubAnimSurfaceIndex[ REGMALE ][ SWAT_BACKWARDS_NOTHING ] = RGMNOTHING_SWAT; + // + gubAnimSurfaceIndex[ REGMALE ][ THROW_GRENADE_STANCE ] = RGMSTHRG; + gubAnimSurfaceIndex[ REGMALE ][ LOB_GRENADE_STANCE ] = RGMSLOBG; + // + gubAnimSurfaceIndex[ REGMALE ][ ROLL_PRONE_L ] = RGMROLL_PR; + gubAnimSurfaceIndex[ REGMALE ][ ROLL_PRONE_R ] = RGMROLL_PR; + + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ STANDING][0] = RGMWATER_R_STD; gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ WALKING ][0] = RGMWATER_R_WALK; @@ -1671,6 +1735,19 @@ void InitAnimationSurfacesPerBodytype( ) // crouch throwing gubAnimSurfaceIndex[ BIGMALE ][ THROW_ITEM_CROUCHED ] = BGMCRTHROW; // +//dddd + gubAnimSurfaceIndex[ BIGMALE ][ BIGGUY_STONE ] = BGMWITHSTONE; + gubAnimSurfaceIndex[ BIGMALE ][ SHOOT_ROCKET_CROUCHED ] = BGMCRROCKET; + gubAnimSurfaceIndex[ BIGMALE ][ SWATTING_WK ] = BGMSWKNIFE; + gubAnimSurfaceIndex[ BIGMALE ][ SWAT_BACKWARDS_WK ] = BGMSWKNIFE; + gubAnimSurfaceIndex[ BIGMALE ][ SWAT_BACKWARDS_NOTHING ] = BGMNOTHING_SWAT; + // + gubAnimSurfaceIndex[ BIGMALE ][ THROW_GRENADE_STANCE ] = BGMSTHRG; + gubAnimSurfaceIndex[ BIGMALE ][ LOB_GRENADE_STANCE ] = BGMSLOBG; + // + gubAnimSurfaceIndex[ BIGMALE ][ ROLL_PRONE_L ] = BGMROLL_PR; + gubAnimSurfaceIndex[ BIGMALE ][ ROLL_PRONE_R ] = BGMROLL_PR; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ STANDING ] = BGMPISTOLBREATH; gubAnimSurfaceItemSubIndex[ BIGMALE ][ WALKING ] = BGMNOTHING_WALK; @@ -1793,6 +1870,14 @@ void InitAnimationSurfacesPerBodytype( ) gRandomAnimDefs[ BIGMALE ][ 6 ].ubFlags = RANDOM_ANIM_DRUNK; gRandomAnimDefs[ BIGMALE ][ 6 ].ubAnimHeight = ANIM_STAND; + ///ddd big guy with stone + gRandomAnimDefs[ BIGMALE ][ 7 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; + gRandomAnimDefs[ BIGMALE ][ 7 ].sAnimID = BIGGUY_STONE; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubStartRoll = 20; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubEndRoll = 26; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubFlags = RANDOM_ANIM_CASUAL ; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubAnimHeight = ANIM_STAND; + gubAnimSurfaceCorpseID[ BIGMALE ][ GENERIC_HIT_DEATH ] = MMERC_FWD; gubAnimSurfaceCorpseID[ BIGMALE ][ FALLBACK_HIT_DEATH ] = MMERC_BCK; @@ -1810,8 +1895,8 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceCorpseID[ BIGMALE ][ FALLBACK_HIT_DEATHTWITCHNB ] = MMERC_BCK; gubAnimSurfaceCorpseID[ BIGMALE ][ PRONE_HIT_DEATHTWITCHNB ] = MMERC_PRN; gubAnimSurfaceCorpseID[ BIGMALE ][ PRONE_LAY_FROMHIT ] = MMERC_PRN; - gubAnimSurfaceCorpseID[ REGMALE ][ FALLOFF ] = MMERC_FALLF; - gubAnimSurfaceCorpseID[ REGMALE ][ FALLFORWARD_ROOF ] = MMERC_FALL; + gubAnimSurfaceCorpseID[ BIGMALE ][ FALLOFF ] = MMERC_FALLF; + gubAnimSurfaceCorpseID[ BIGMALE ][ FALLFORWARD_ROOF ] = MMERC_FALL; gubAnimSurfaceCorpseID[ BIGMALE ][ FLYBACKHIT_STOP ] = MMERC_DHD; gubAnimSurfaceCorpseID[ BIGMALE ][ STAND_FALLFORWARD_STOP ] = MMERC_FWD; gubAnimSurfaceCorpseID[ BIGMALE ][ FALLBACKHIT_STOP ] = MMERC_BCK; @@ -2039,6 +2124,18 @@ void InitAnimationSurfacesPerBodytype( ) // crouch throwing gubAnimSurfaceIndex[ STOCKYMALE ][ THROW_ITEM_CROUCHED ] = RGMCRTHROW; // + //dddd + gubAnimSurfaceIndex[ STOCKYMALE ][ SHOOT_ROCKET_CROUCHED ] = RGMCRROCKET; + gubAnimSurfaceIndex[ STOCKYMALE ][ SWATTING_WK ] = RGMSWKNIFE; + gubAnimSurfaceIndex[ STOCKYMALE ][ SWAT_BACKWARDS_WK ] = RGMSWKNIFE; + gubAnimSurfaceIndex[ STOCKYMALE ][ SWAT_BACKWARDS_NOTHING ] = RGMNOTHING_SWAT; + // + gubAnimSurfaceIndex[ STOCKYMALE ][ THROW_GRENADE_STANCE ] = RGMSTHRG; + gubAnimSurfaceIndex[ STOCKYMALE ][ LOB_GRENADE_STANCE ] = RGMSLOBG; + // + gubAnimSurfaceIndex[ STOCKYMALE ][ ROLL_PRONE_L ] = RGMROLL_PR; + gubAnimSurfaceIndex[ STOCKYMALE ][ ROLL_PRONE_R ] = RGMROLL_PR; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ STANDING ] = RGMPISTOLBREATH; gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ WALKING ] = RGMNOTHING_WALK; @@ -2394,6 +2491,19 @@ void InitAnimationSurfacesPerBodytype( ) // crouch throwing gubAnimSurfaceIndex[ REGFEMALE ][ THROW_ITEM_CROUCHED ] = RGFCRTHROW; // + //ddd + gubAnimSurfaceIndex[ REGFEMALE ][ SHOOT_ROCKET_CROUCHED ] = RGFCRROCKET; + gubAnimSurfaceIndex[ REGFEMALE ][ SWAT_BACKWARDS_NOTHING ] = RGFNOTHING_SWAT; + gubAnimSurfaceIndex[ REGFEMALE ][ SWATTING_WK ] = RGFSWKNIFE; + gubAnimSurfaceIndex[ REGFEMALE ][ SWAT_BACKWARDS_WK ] = RGFSWKNIFE; + // + gubAnimSurfaceIndex[ REGFEMALE ][ THROW_GRENADE_STANCE ] = RGFSTHRG; + gubAnimSurfaceIndex[ REGFEMALE ][ LOB_GRENADE_STANCE ] = RGFSLOBG; + // + gubAnimSurfaceIndex[ REGFEMALE ][ ROLL_PRONE_L ] = RGFROLL_PR; + gubAnimSurfaceIndex[ REGFEMALE ][ ROLL_PRONE_R ] = RGFROLL_PR; + + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ STANDING ] = RGFPISTOLBREATH; gubAnimSurfaceItemSubIndex[ REGFEMALE ][ WALKING ] = RGFNOTHING_WALK; @@ -3058,17 +3168,60 @@ BOOLEAN LoadAnimationStateInstructions( ) return( FALSE ); } + //ddd 320 ;( + // , + UINT16 fuckTheBoundz[320][100]; + //Read in block - if ( !FileRead( hFile, gusAnimInst, sizeof( gusAnimInst ), &uiBytesRead ) ) + //if ( !FileRead( hFile, gusAnimInst, sizeof( gusAnimInst ), &uiBytesRead ) ) //commentet by ddd + if ( !FileRead( hFile, fuckTheBoundz, sizeof( fuckTheBoundz ), &uiBytesRead ) ) { return( FALSE ); } FileClose( hFile ); + //memcpy(gusAnimInst, fuckTheBoundz, sizeof(gusAnimInst)); + for(int i=0;i<320;i++) + memcpy(gusAnimInst[i],fuckTheBoundz[i],sizeof(fuckTheBoundz[i])); + //gusAnimInst[i][0] = fuckTheBoundz[i][0]; + + //! 2 +// char gS[22]; +// UINT32 uiNumBytesWritten = 64000; +// int ggg[MAX_ANIMATIONS][MAX_FRAMES_PER_ANIM]; +// sprintf(gS, "%s\\%s", "c:", "zzz"); +// hFile = FileOpen( gS, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); +// +// for(int i=0;i<=MAX_ANIMATIONS;i++) +// { +// FilePrintf(hFile,"\r\n :%02d === \r\n",i); +// for(int ii=0;ii<=MAX_FRAMES_PER_ANIM;ii++) +// FilePrintf(hFile,"%02d ",gusAnimInst[i][ii]); +// +// } +// //ggg[i][ii]=gusAnimInst[i][ii]; +// //FileWrite( hFile, &ggg, sizeof( ggg ), &uiNumBytesWritten ); +//FileClose( hFile ); +//! +//strcpy(NULL, "crash"); + // crouch throwing memcpy(gusAnimInst[ THROW_ITEM_CROUCHED ],CrouchedThrowAnimationScript,sizeof(CrouchedThrowAnimationScript)); // crouch throwing + + //ddd + memcpy(gusAnimInst[ BIGGUY_STONE ],StoneAnimationScript,sizeof(StoneAnimationScript)); + memcpy(gusAnimInst[ SHOOT_ROCKET_CROUCHED ],CrouchedShootRocketScript,sizeof(CrouchedShootRocketScript)); + memcpy(gusAnimInst[ SWATTING_WK ],SwatWithKnifeScript,sizeof(SwatWithKnifeScript)); + memcpy(gusAnimInst[ SWAT_BACKWARDS_WK ],SwatBackWithKnifeScript,sizeof(SwatBackWithKnifeScript)); + memcpy(gusAnimInst[ SWAT_BACKWARDS_NOTHING ],SwatBackWithNothingScript,sizeof(SwatBackWithNothingScript)); + + memcpy(gusAnimInst[ THROW_GRENADE_STANCE ],ThrowGrenadeStanceAnimationScript,sizeof(ThrowGrenadeStanceAnimationScript)); + memcpy(gusAnimInst[ LOB_GRENADE_STANCE ],LobGrenadeStanceAnimationScript,sizeof(LobGrenadeStanceAnimationScript)); + + memcpy(gusAnimInst[ ROLL_PRONE_L ],ROLL_L_AnimationScript,sizeof(ROLL_L_AnimationScript)); + memcpy(gusAnimInst[ ROLL_PRONE_R ],ROLL_R_AnimationScript,sizeof(ROLL_R_AnimationScript)); return( TRUE ); } @@ -3438,7 +3591,7 @@ UINT16 DetermineSoldierAnimationSurface( SOLDIERTYPE *pSoldier, UINT16 usAnimSta // Assume a target gridno is here.... get direction... // ATE: use +2 in gridno because here head is far from body - bDir = (INT8)GetDirectionToGridNoFromGridNo( pSoldier->sGridNo + 2, pSoldier->sTargetGridNo ); + bDir = (INT8)GetDirectionToGridNoFromGridNo( (INT16)( pSoldier->sGridNo + 2 ), pSoldier->sTargetGridNo ); return( gusQueenMonsterSpitAnimPerDir[ bDir ] ); } @@ -3456,6 +3609,8 @@ UINT16 DetermineSoldierAnimationSurface( SOLDIERTYPE *pSoldier, UINT16 usAnimSta if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) { usAnimSurface = BGMSTANDAIM; +// if(Random(2)) usAnimSurface = BGMSTANDAIM; //ddd +// else usAnimSurface = BGMSTANDAIM2; } } @@ -3557,6 +3712,15 @@ UINT16 DetermineSoldierAnimationSurface( SOLDIERTYPE *pSoldier, UINT16 usAnimSta usAltAnimSurface = gubAnimSurfaceItemSubIndex[pSoldier->ubBodyType][usAnimState]; if ( usAltAnimSurface != INVALID_ANIMATION ) { + //ddd{ + /*if ( usAnimSurface == BGMSTANDAIM2 ) + { + + usAnimSurface = BGMFLEX; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"usanimcashe"); + + } + else //}ddd*/ usAnimSurface = usAltAnimSurface; fAdjustedForItem = TRUE; } diff --git a/Tactical/Animation Control.h b/Tactical/Animation Control.h index eaf92b23..8e40ec28 100644 --- a/Tactical/Animation Control.h +++ b/Tactical/Animation Control.h @@ -7,9 +7,9 @@ // Defines // ####################################################### -#define MAX_ANIMATIONS 320 +#define MAX_ANIMATIONS 350 //!!!!!ddd 30 . #define MAX_FRAMES_PER_ANIM 100 -#define MAX_RANDOM_ANIMS_PER_BODYTYPE 7 +#define MAX_RANDOM_ANIMS_PER_BODYTYPE 8 #define RANDOM_ANIM_NOTHINGINHAND 0 #define RANDOM_ANIM_RIFLEINHAND 1 @@ -542,7 +542,18 @@ enum AnimationStates // crouch throwing THROW_ITEM_CROUCHED, // - + ///ddd + BIGGUY_STONE, + SHOOT_ROCKET_CROUCHED, + SWATTING_WK, + SWAT_BACKWARDS_WK, + SWAT_BACKWARDS_NOTHING, + THROW_GRENADE_STANCE, //ddd - + LOB_GRENADE_STANCE, + // + ROLL_PRONE_R, + ROLL_PRONE_L, + NUMANIMATIONSTATES }; diff --git a/Tactical/Animation Data.cpp b/Tactical/Animation Data.cpp index 425b74ce..11767942 100644 --- a/Tactical/Animation Data.cpp +++ b/Tactical/Animation Data.cpp @@ -478,6 +478,31 @@ AnimationSurfaceType gAnimSurfaceDatabase[ NUMANIMATIONSURFACETYPES ] = BGMCRTHROW, "ANIMS\\M_MERC\\M_CR_THR.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGFCRTHROW, "ANIMS\\F_MERC\\F_CR_THR.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, // + //ddd big man with stone + BGMWITHSTONE, "ANIMS\\M_MERC\\M_STEIN.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + //ddd crouched shoot rocket + RGMCRROCKET, "ANIMS\\S_MERC\\S_LAW_CR.sti", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGMCRROCKET, "ANIMS\\M_MERC\\M_LAW_CR.sti", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGFCRROCKET, "ANIMS\\F_MERC\\F_LAW_CR.sti", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + BGMSWKNIFE , "ANIMS\\M_MERC\\M_K_SWAT_K.sti", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGFSWKNIFE , "ANIMS\\F_MERC\\F_K_SWAT_K.sti", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGMSWKNIFE , "ANIMS\\S_MERC\\S_K_SWAT.sti", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + // 2 + BGMSTHRG, "ANIMS\\M_MERC\\M_THROW_G.sti", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + // + RGFSTHRG, "ANIMS\\F_MERC\\F_THROW.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGMSTHRG, "ANIMS\\S_MERC\\S_THROW_G.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + BGMSLOBG, "ANIMS\\M_MERC\\M_THROW_GLOB.sti", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGFSLOBG, "ANIMS\\F_MERC\\F_LOB.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGMSLOBG, "ANIMS\\S_MERC\\S_THROW_GLOB.sti", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + // + RGMROLL_PR, "ANIMS\\S_MERC\\S_ROLL_N.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGMROLL_PR, "ANIMS\\M_MERC\\M_ROLL_N.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGFROLL_PR, "ANIMS\\F_MERC\\F_ROLL_N.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + }; @@ -828,12 +853,6 @@ BOOLEAN LoadAnimationSurface( UINT16 usSoldierID, UINT16 usSurfaceIndex, UINT16 { AuxObjectData *pAuxData; - if (usSurfaceIndex == 251) - { - int a = 10; - a++; - } - // Check for valid surface CHECKF( usSurfaceIndex < NUMANIMATIONSURFACETYPES ); @@ -953,13 +972,6 @@ BOOLEAN LoadAnimationSurface( UINT16 usSoldierID, UINT16 usSurfaceIndex, UINT16 BOOLEAN UnLoadAnimationSurface( UINT16 usSoldierID, UINT16 usSurfaceIndex ) { - - if (usSurfaceIndex == 251) - { - int a = 10; - a++; - } - // Decrement usage flag, only if this soldier has it currently tagged if ( gbAnimUsageHistory[ usSurfaceIndex ][ usSoldierID ] > 0 ) { diff --git a/Tactical/Animation Data.h b/Tactical/Animation Data.h index 5cac37ce..c39c7cff 100644 --- a/Tactical/Animation Data.h +++ b/Tactical/Animation Data.h @@ -508,6 +508,29 @@ typedef enum RGFCRTHROW, // +//***ddd +BGMWITHSTONE, +//for crouched shoot rocket + RGMCRROCKET, + BGMCRROCKET, + RGFCRROCKET, +//swatting with knife + BGMSWKNIFE, + RGFSWKNIFE, + RGMSWKNIFE, +// . + BGMSTHRG, + RGFSTHRG, + RGMSTHRG, +// . + BGMSLOBG, + RGFSLOBG, + RGMSLOBG, +// ! + RGMROLL_PR, + BGMROLL_PR, + RGFROLL_PR, + NUMANIMATIONSURFACETYPES } AnimationSurfaceTypes; diff --git a/Tactical/Arms Dealer Init.cpp b/Tactical/Arms Dealer Init.cpp index 2b447ff1..a5a6d4b3 100644 --- a/Tactical/Arms Dealer Init.cpp +++ b/Tactical/Arms Dealer Init.cpp @@ -16,6 +16,7 @@ #include "Handle Items.h" #include "Quests.h" #include "Scheduling.h" + #include "GameSettings.h" #endif #include @@ -92,6 +93,9 @@ void LimitArmsDealersInventory( UINT8 ubArmsDealer, UINT32 uDealerItemType, UIN void GuaranteeAtLeastOneItemOfType( UINT8 ubArmsDealer, UINT32 uiDealerItemType ); void GuaranteeAtLeastXItemsOfIndex( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany ); +void GuaranteeAtMostNumOfItemsForItem( UINT8 ubArmsDealer, INT16 sItemIndex, UINT8 ubAtMostNumItems ); + + void ArmsDealerGetsFreshStock( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubNumItems ); BOOLEAN ItemContainsLiquid( UINT16 usItemIndex ); UINT8 DetermineDealerItemCondition( UINT8 ubArmsDealer, UINT16 usItemIndex ); @@ -147,7 +151,6 @@ void InitAllArmsDealers() UINT8 ubArmsDealer; ShutDownArmsDealers(); - //Initialize the initial status & inventory for each of the arms dealers for( ubArmsDealer = 0; ubArmsDealer < NUM_ARMS_DEALERS; ubArmsDealer++ ) { @@ -1271,7 +1274,7 @@ BOOLEAN ItemContainsLiquid( UINT16 usItemIndex ) bool ItemIsSpecial(DEALER_SPECIAL_ITEM& item) { for (int x = 0; x < item.object.ubNumberOfObjects; ++x) { - if (item.object[x]->attachments.empty() == false) { + if (item.object[x]->AttachmentListSize() > 0) { //items with attachments are special return true; } @@ -1347,11 +1350,16 @@ void AddObjectToArmsDealerInventory( UINT8 ubArmsDealer, OBJECTTYPE *pObject ) for (attachmentList::iterator iter = seperateObject[0]->attachments.begin(); iter != seperateObject[0]->attachments.end();) { // ARM: Note: this is only used for selling, not repairs, so attachmentes are seperated when sold to a dealer // If the attachment is detachable - if (! (Item[ iter->usItem ].inseparable ) ) + if (! (Item[ iter->usItem ].inseparable ) && iter->exists()) { // add this particular attachment (they can't be imprinted, or themselves have attachments!) AddObjectToArmsDealerInventory( ubArmsDealer, &(*iter) ); - iter = pData->attachments.erase(iter); + + iter = pData->RemoveAttachmentAtIter(iter); + + if(UsingNewAttachmentSystem()==true) + ++iter; + if (iter == pData->attachments.end()) { break; } @@ -1494,7 +1502,7 @@ void AddItemToArmsDealerInventory( UINT8 ubArmsDealer, OBJECTTYPE& object ) { //we can only add items to a stack if the item has no attachments (not even default) //and if it is either perfect or ammo (and same amount of ammo) - if (object[0]->attachments.empty() == true && + if (/*object[0]->attachments.empty() == true*/ object[0]->AttachmentListSize() && (object[0]->data.objectStatus == 100 || Item [ object.usItem ].usItemClass == IC_AMMO)) { //first find existing items with same perfect status, if found add to that, else create new one @@ -1832,7 +1840,7 @@ UINT32 CalculateObjectItemRepairTime( UINT8 ubArmsDealer, OBJECTTYPE *pItemObjec // add time to repair any attachments on it for (attachmentList::iterator iter = (*pItemObject)[x]->attachments.begin(); iter != (*pItemObject)[x]->attachments.end(); ++iter) { // if damaged and repairable - if ( ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) ) + if ( ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) && iter->exists()) { //uiRepairTime += CalculateSimpleItemRepairTime( ubArmsDealer, iter->usItem, (*iter)[x]->data.objectStatus ); uiRepairTime += CalculateObjectItemRepairTime( ubArmsDealer, &(*iter) ); @@ -1890,7 +1898,7 @@ UINT32 CalculateObjectItemRepairCost( UINT8 ubArmsDealer, OBJECTTYPE *pItemObjec // add cost of repairing any attachments on it for (attachmentList::iterator iter = (*pItemObject)[x]->attachments.begin(); iter != (*pItemObject)[x]->attachments.end(); ++iter) { // if damaged and repairable - if ( ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) ) + if ( ( (*iter)[x]->data.objectStatus < 100 ) && CanDealerRepairItem( ubArmsDealer, iter->usItem ) && iter->exists()) { uiRepairCost += CalculateObjectItemRepairCost( ubArmsDealer, &(*iter)); } @@ -2265,3 +2273,25 @@ UINT32 CalculateMinutesClosedBetween( UINT8 ubArmsDealer, UINT32 uiStartTime, UI return ( uiMinutesClosed ); } + +void GuaranteeAtMostNumOfItemsForItem( UINT8 ubArmsDealer, INT16 sItemIndex, UINT8 ubAtMostNumItems ) +{ + + if( gArmsDealerStatus[ ubArmsDealer ].fOutOfBusiness ) + return; + + //ADB, ya, a whole 1 line of extra code! + // not permitted for repair dealers - would take extra code to avoid counting items under repair! + //Assert( !DoesDealerDoRepairs( ubArmsDealer ) ); + int itemsIHave = 0; + for (DealerItemList::iterator iter = gArmsDealersInventory[ ubArmsDealer ].begin(); + iter != gArmsDealersInventory[ ubArmsDealer ].end(); ++iter) { + if (iter->ItemIsInInventory() == true + && iter->object.usItem == sItemIndex + && iter->IsUnderRepair() == false) { + itemsIHave -= iter->object.ubNumberOfObjects; + //if there are any of these in stock + + } + } +} diff --git a/Tactical/Arms Dealer Init.h b/Tactical/Arms Dealer Init.h index 68194476..d711a946 100644 --- a/Tactical/Arms Dealer Init.h +++ b/Tactical/Arms Dealer Init.h @@ -362,6 +362,8 @@ UINT16 CalcValueOfItemToDealer( UINT8 ubArmsDealer, UINT16 usItemIndex, BOOLEAN UINT32 CalculateOvernightRepairDelay( UINT8 ubArmsDealer, UINT32 uiTimeWhenFreeToStartIt, UINT32 uiMinutesToFix ); UINT32 CalculateMinutesClosedBetween( UINT8 ubArmsDealer, UINT32 uiStartTime, UINT32 uiEndTime ); +extern void GuaranteeAtLeastXItemsOfIndex( UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubHowMany ); + #endif \ No newline at end of file diff --git a/Tactical/ArmsDealerInvInit.cpp b/Tactical/ArmsDealerInvInit.cpp index 629f9a3b..d43e1709 100644 --- a/Tactical/ArmsDealerInvInit.cpp +++ b/Tactical/ArmsDealerInvInit.cpp @@ -901,6 +901,7 @@ UINT8 GetCurrentSuitabilityForItem( INT8 bArmsDealer, UINT16 usItemIndex, BOOLEA } // items normally not sold at shops are unsuitable +// if ( Item[ usItemIndex ].fFlags & ITEM_NOT_BUYABLE ) if ( Item[ usItemIndex ].notbuyable ) { return(ITEM_SUITABILITY_NONE); @@ -916,8 +917,21 @@ UINT8 GetCurrentSuitabilityForItem( INT8 bArmsDealer, UINT16 usItemIndex, BOOLEA } // the following staple items are always deemed highly suitable regardless of player's progress: + //switch (usItemIndex) + //{ + // case FIRSTAIDKIT: + // case MEDICKIT: + // case TOOLKIT: + // case LOCKSMITHKIT: + + // case CANTEEN: + // case CROWBAR: + // case JAR: + // case JAR_ELIXIR: + // case JAR_CREATURE_BLOOD: if ( Item[usItemIndex].medical || Item[usItemIndex].canteen || Item[usItemIndex].medicalkit || Item[usItemIndex].locksmithkit || Item[usItemIndex].toolkit || Item[usItemIndex].crowbar || Item[usItemIndex].jar ) return(ITEM_SUITABILITY_ALWAYS); + //} // If it's not BobbyRay, Tony, or Devin @@ -931,11 +945,13 @@ UINT8 GetCurrentSuitabilityForItem( INT8 bArmsDealer, UINT16 usItemIndex, BOOLEA // figure out the appropriate range of coolness based on player's maximum progress so far - if ( bArmsDealer == bobbyRaysID ) + if ( bArmsDealer == bobbyRaysID ) { ubMinCoolness = 1; - else + ubMaxCoolness = HighestPlayerProgressPercentage() / 10 + 1; + } else { ubMinCoolness = HighestPlayerProgressPercentage() * armsDealerInfo[bArmsDealer].coolnessProgressRate / 100; - ubMaxCoolness = ubMinCoolness + 1; + ubMaxCoolness = HighestPlayerProgressPercentage() * armsDealerInfo[bArmsDealer].coolnessProgressRate / 100 + 1; + } //Madd: Bobby Ray's will sell higher coolness stuff if it's used, and may also have a better selection at the start of the game, depending on selection if ( (bArmsDealer == bobbyRaysID || armsDealerInfo[bArmsDealer].useBRSetting) && gGameOptions.ubBobbyRay > BR_GOOD ) diff --git a/Tactical/Boxing.cpp b/Tactical/Boxing.cpp index b897ed8b..8a7d7624 100644 --- a/Tactical/Boxing.cpp +++ b/Tactical/Boxing.cpp @@ -24,6 +24,7 @@ #include "Animation Data.h" #include "Font Control.h" #include "message.h" + #include "GameSettings.h" // added by SANDRO #endif INT32 gsBoxerGridNo[ NUM_BOXERS ] = { 11393, 11233, 11073 }; @@ -386,10 +387,24 @@ BOOLEAN PickABoxer( void ) pBoxer->stats.bDexterity = __min( 100, pBoxer->stats.bDexterity + gubBoxersRests * 5 ); pBoxer->stats.bAgility = __min( 100, pBoxer->stats.bAgility + gubBoxersRests * 5 ); pBoxer->stats.bLifeMax = __min( 100, pBoxer->stats.bLifeMax + gubBoxersRests * 5 ); + // give the 2nd boxer Hand to hand - SANDRO + if ( (uiLoop == NUM_BOXERS - 2) ) + { + if (gGameOptions.fNewTraitSystem) // SANDRO - traits + pBoxer->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT; + else + pBoxer->stats.ubSkillTraits[0] = HANDTOHAND_OT; + } // give the 3rd boxer martial arts if ( (uiLoop == NUM_BOXERS - 1) && pBoxer->ubBodyType == REGMALE ) { - pBoxer->stats.ubSkillTrait1 = MARTIALARTS; + if (gGameOptions.fNewTraitSystem) // SANDRO - traits + { + pBoxer->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT; + pBoxer->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT; + } + else + pBoxer->stats.ubSkillTraits[0] = MARTIALARTS_OT; } return( TRUE ); } diff --git a/Tactical/Campaign.cpp b/Tactical/Campaign.cpp index 15bbbcd1..4179e3a7 100644 --- a/Tactical/Campaign.cpp +++ b/Tactical/Campaign.cpp @@ -300,6 +300,20 @@ void ProcessStatChange(MERCPROFILESTRUCT *pProfile, UINT8 ubStat, UINT16 usNumCh } */ + // SANDRO - penalty for primitive people, they get lesser chance to gain point for certain skills + if ( gGameOptions.fNewTraitSystem && (usChance > 10) && (ubStat != EXPERAMT) && (pProfile->bCharacterTrait == CHAR_TRAIT_PRIMITIVE) ) + { + switch (ubStat) + { + case WISDOMAMT: + case MEDICALAMT: + case EXPLODEAMT: + case MECHANAMT: + case LDRAMT: + usChance = max(1, (usChance - 10)); // -10% chance to gain the point + break; + } + } // maximum possible usChance is 99% @@ -451,6 +465,7 @@ void ChangeStat( MERCPROFILESTRUCT *pProfile, SOLDIERTYPE *pSoldier, UINT8 ubSta UINT8 ubMercMercIdValue = 0; UINT16 usIncreaseValue = 0; UINT16 usSubpointsPerPoint; + INT8 bDamagedStatToRaise = -1; // added by SANDRO usSubpointsPerPoint = SubpointsPerPoint(ubStat, pProfile->bExpLevel ); @@ -529,54 +544,63 @@ void ChangeStat( MERCPROFILESTRUCT *pProfile, SOLDIERTYPE *pSoldier, UINT8 ubSta if (pSoldier != NULL) { // build ptrs to appropriate soldiertype stat fields + // SANDRO - added a variable for stat repair switch( ubStat ) { case HEALTHAMT: pbSoldierStatPtr = &( pSoldier->stats.bLifeMax ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeHealthTime); usIncreaseValue = HEALTH_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_HEALTH; break; case AGILAMT: pbSoldierStatPtr = &( pSoldier->stats.bAgility ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeAgilityTime); usIncreaseValue = AGIL_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_AGILITY; break; case DEXTAMT: pbSoldierStatPtr = &( pSoldier->stats.bDexterity ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeDexterityTime); usIncreaseValue = DEX_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_DEXTERITY; break; case WISDOMAMT: pbSoldierStatPtr = &( pSoldier->stats.bWisdom ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeWisdomTime); usIncreaseValue = WIS_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_WISDOM; break; case MEDICALAMT: pbSoldierStatPtr = &( pSoldier->stats.bMedical ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeMedicalTime); usIncreaseValue = MED_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_MEDICAL; break; case EXPLODEAMT: pbSoldierStatPtr = &( pSoldier->stats.bExplosive ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeExplosivesTime); usIncreaseValue = EXP_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_EXPLOSIVES; break; case MECHANAMT: pbSoldierStatPtr = &( pSoldier->stats.bMechanical ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeMechanicalTime); usIncreaseValue = MECH_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_MECHANICAL; break; case MARKAMT: pbSoldierStatPtr = &( pSoldier->stats.bMarksmanship ); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeMarksmanshipTime); usIncreaseValue = MRK_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_MARKSMANSHIP; break; case EXPERAMT: @@ -589,12 +613,14 @@ void ChangeStat( MERCPROFILESTRUCT *pProfile, SOLDIERTYPE *pSoldier, UINT8 ubSta pbSoldierStatPtr = &(pSoldier->stats.bStrength); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeStrengthTime); usIncreaseValue = STRENGTH_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_STRENGTH; break; case LDRAMT: pbSoldierStatPtr = &( pSoldier->stats.bLeadership); puiStatTimerPtr = &( pSoldier->timeChanges.uiChangeLeadershipTime); usIncreaseValue = LDR_INCREASE; + bDamagedStatToRaise = DAMAGED_STAT_LEADERSHIP; break; } } @@ -633,6 +659,13 @@ void ChangeStat( MERCPROFILESTRUCT *pProfile, SOLDIERTYPE *pSoldier, UINT8 ubSta // transfer over change to soldiertype structure *pbSoldierStatPtr = *pbStatPtr; + // SANDRO - reduce damaged stat if this stat was increased normally + if ( fChangeTypeIncrease && (bDamagedStatToRaise != -1) ) + { + if (pSoldier->ubCriticalStatDamage[ bDamagedStatToRaise ] > 0) + pSoldier->ubCriticalStatDamage[ bDamagedStatToRaise ] = max( 0, (pSoldier->ubCriticalStatDamage[ bDamagedStatToRaise ] - sPtsChanged)); + } + // if it's a level gain, or sometimes for other stats // ( except health; not only will it sound silly, but // also we give points for health on sector traversal and this would @@ -1016,6 +1049,7 @@ void HandleAnyStatChangesAfterAttack( void ) UINT32 CalcNewSalary(UINT32 uiOldSalary, BOOLEAN fIncrease, UINT32 uiMaxLimit) { UINT32 uiNewSalary; + FLOAT SalaryMultiplier = (FLOAT) ((gGameExternalOptions.gMercLevelUpSalaryIncreasePercentage / 100) + 1); // if he was working for free, it's still free! if (uiOldSalary == 0) @@ -1025,11 +1059,11 @@ UINT32 CalcNewSalary(UINT32 uiOldSalary, BOOLEAN fIncrease, UINT32 uiMaxLimit) if (fIncrease) { - uiNewSalary = (UINT32) (uiOldSalary * SALARY_CHANGE_PER_LEVEL); + uiNewSalary = (UINT32) (uiOldSalary * SalaryMultiplier); } else { - uiNewSalary = (UINT32) (uiOldSalary / SALARY_CHANGE_PER_LEVEL); + uiNewSalary = (UINT32) (uiOldSalary / SalaryMultiplier); } // round it off to a reasonable multiple @@ -1247,26 +1281,41 @@ void HandleUnhiredMercDeaths( INT32 iProfileID ) // calculate this merc's (small) chance to get killed today (out of 1000) sChance = 10 - pProfile->bExpLevel; - switch (pProfile->bPersonalityTrait) - { - case FORGETFUL: - case NERVOUS: - case PSYCHO: - // these guys are somewhat more likely to get killed (they have "problems") - sChance += 2; - break; + // SANDRO - certain traits makes us less likely to get killed + if ( gGameOptions.fNewTraitSystem ) + { + if (pProfile->bDisability != NO_DISABILITY) + { + sChance += 1; + } + if ( ProfileHasSkillTrait( iProfileID, SQUADLEADER_NT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, SQUADLEADER_NT ); + if ( ProfileHasSkillTrait( iProfileID, TECHNICIAN_NT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, TECHNICIAN_NT ); + if ( ProfileHasSkillTrait( iProfileID, DOCTOR_NT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, DOCTOR_NT ); + if ( ProfileHasSkillTrait( iProfileID, STEALTHY_NT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, STEALTHY_NT ); + if ( ProfileHasSkillTrait( iProfileID, BODYBUILDING_NT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, BODYBUILDING_NT ); + if ( ProfileHasSkillTrait( iProfileID, SCOUTING_NT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, SCOUTING_NT ); } - - // stealthy guys are slightly less likely to get killed (they're careful) - if (pProfile->bSkillTrait == STEALTHY) - { - sChance -= 1; + else + { + switch (pProfile->bDisability) + { + case FORGETFUL: + case NERVOUS: + case PSYCHO: + // these guys are somewhat more likely to get killed (they have "problems") + sChance += 2; + break; + } + // stealthy guys are slightly less likely to get killed (they're careful) + if ( ProfileHasSkillTrait( iProfileID, STEALTHY_OT ) > 0 ) + sChance -= ProfileHasSkillTrait( iProfileID, STEALTHY_OT ); } - if (pProfile->bSkillTrait2 == STEALTHY) - { - sChance -= 1; - } - if ((INT16) PreRandom(1000) < sChance) { @@ -1278,7 +1327,8 @@ void HandleUnhiredMercDeaths( INT32 iProfileID ) gStrategicStatus.ubUnhiredMercDeaths++; //send an email as long as the merc is from aim - if( iProfileID < BIFF ) + // if( iProfileID < BIFF ) + if ( gProfilesAIM[ iProfileID ].ProfilId == iProfileID ) //new profiles by Jazz { //send an email to the player telling the player that a merc died AddEmailWithSpecialData(MERC_DIED_ON_OTHER_ASSIGNMENT, MERC_DIED_ON_OTHER_ASSIGNMENT_LENGTH, AIM_SITE, GetWorldTotalMin(), 0, iProfileID ); @@ -1340,7 +1390,7 @@ UINT8 CurrentPlayerProgressPercentage(void) // figure out the player's current mine income - uiCurrentIncome = PredictIncomeFromPlayerMines(); + uiCurrentIncome = PredictIncomeFromPlayerMines(FALSE); // figure out the player's potential mine income uiPossibleIncome = CalcMaxPlayerIncomeFromMines(); @@ -1453,8 +1503,11 @@ UINT8 CurrentPlayerProgressPercentage(void) // And failsafes here. I'm not 100% sure about these though: I've never personally seen progress // values go over 100, and I don't think they SHOULD... Can the game handle values > 100? Should it? usCurrentProgress = __min(100, usCurrentProgress); + usCurrentProgress = __max(0, usCurrentProgress); // No less than 0, or the minimum set in the INI file. - usCurrentProgress = __max(gGameExternalOptions.ubGameProgressMinimum, __max(0, usCurrentProgress)); + UINT32 uiMinProgress = __max(gGameExternalOptions.ubGameProgressMinimum, 0); + usCurrentProgress = __max(uiMinProgress, usCurrentProgress); + return((UINT8)usCurrentProgress); } diff --git a/Tactical/Campaign.h b/Tactical/Campaign.h index 7caaa1c5..b45cb84f 100644 --- a/Tactical/Campaign.h +++ b/Tactical/Campaign.h @@ -36,7 +36,8 @@ extern UINT16 LEVEL_SUBPOINTS_TO_IMPROVE; #define WORKIMPROVERATE 2 // increase to make working mercs improve more #define TRAINIMPROVERATE 2 // increase to make training mercs improve more -#define SALARY_CHANGE_PER_LEVEL 1.25 // Mercs salary is multiplied by this +//tais: externalized the salary multiplier to gGameExternalOptions.gMercLevelUpSalaryIncreasePercentage +//#define SALARY_CHANGE_PER_LEVEL 1.25 // Mercs salary is multiplied by this #define MAX_DAILY_SALARY 30000 // must fit into an INT16 (32k) #define MAX_LARGE_SALARY 500000 // no limit, really diff --git a/Tactical/Civ Quotes.cpp b/Tactical/Civ Quotes.cpp index 748cef8d..12a45b9b 100644 --- a/Tactical/Civ Quotes.cpp +++ b/Tactical/Civ Quotes.cpp @@ -40,21 +40,22 @@ #define HIGH_TOWN_LOYALTY 80 #define CIV_QUOTE_HINT 99 - -typedef struct -{ - UINT8 ubNumEntries; - UINT8 ubUnusedCurrentEntry; - -} CIV_QUOTE; - extern void CaptureTimerCallback( void ); BOOLEAN gfSurrendered = FALSE; -CIV_QUOTE gCivQuotes[ NUM_CIV_QUOTES ]; +//-------------------------------------------------------------- +//Not used +typedef struct +{ + UINT16 ubNumEntries; + UINT16 ubUnusedCurrentEntry; //Unused -UINT8 gubNumEntries[ NUM_CIV_QUOTES ] = +} CIV_QUOTE; + +CIV_QUOTE gCivQuotes[ NUM_CIV_QUOTES]; //Not used + +UINT16 gubNumEntries[ NUM_CIV_QUOTES ] = // Not used { 15, 15, @@ -111,7 +112,7 @@ UINT8 gubNumEntries[ NUM_CIV_QUOTES ] = 3, 3 }; - +//-------------------------------------------------------------- typedef struct { @@ -131,20 +132,24 @@ CHAR16 gzCivQuote[ 320 ]; UINT16 gusCivQuoteBoxWidth; UINT16 gusCivQuoteBoxHeight; - -void CopyNumEntriesIntoQuoteStruct( ) +//-------------------------------------------------------------- +void CopyNumEntriesIntoQuoteStruct( ) // Not used { INT32 cnt; for ( cnt = 0; cnt < NUM_CIV_QUOTES; cnt++ ) - { - gCivQuotes[ cnt ].ubNumEntries = gubNumEntries[ cnt ]; + { + + if (cnt <= 50) + gCivQuotes[ cnt ].ubNumEntries = gubNumEntries[ cnt ]; + else + gCivQuotes[ cnt ].ubNumEntries = 15; } } +//-------------------------------------------------------------- - -BOOLEAN GetCivQuoteText( UINT8 ubCivQuoteID, UINT8 ubEntryID, STR16 zQuote ) +BOOLEAN GetCivQuoteText(UINT16 ubCivQuoteID, UINT16 ubEntryID, STR16 zQuote ) { CHAR8 zFileName[164]; @@ -163,7 +168,10 @@ BOOLEAN GetCivQuoteText( UINT8 ubCivQuoteID, UINT8 ubEntryID, STR16 zQuote ) } else { - sprintf( zFileName,"NPCDATA\\CIV%02d.edt",ubCivQuoteID ); + if (ubCivQuoteID <= 9) + sprintf( zFileName,"NPCDATA\\CIV%02d.edt",ubCivQuoteID ); + else + sprintf( zFileName,"NPCDATA\\CIV%d.edt",ubCivQuoteID ); } CHECKF( FileExists( zFileName ) ); @@ -370,18 +378,18 @@ void QuoteOverlayClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) } -void BeginCivQuote( SOLDIERTYPE *pCiv, UINT8 ubCivQuoteID, UINT8 ubEntryID, INT16 sX, INT16 sY ) +void BeginCivQuote( SOLDIERTYPE *pCiv, UINT16 ubCivQuoteID, UINT16 ubEntryID, INT16 sX, INT16 sY ) { VIDEO_OVERLAY_DESC VideoOverlayDesc; - CHAR16 zQuote[ 320 ]; - + CHAR16 zQuote[ 320 ]; + // OK, do we have another on? if ( gCivQuoteData.bActive ) { // Delete? ShutDownQuoteBox( TRUE ); } - + // get text if ( !GetCivQuoteText( ubCivQuoteID, ubEntryID, zQuote ) ) { @@ -469,7 +477,7 @@ void BeginCivQuote( SOLDIERTYPE *pCiv, UINT8 ubCivQuoteID, UINT8 ubEntryID, INT1 } -UINT8 DetermineCivQuoteEntry( SOLDIERTYPE *pCiv, UINT8 *pubCivHintToUse, BOOLEAN fCanUseHints ) +UINT16 DetermineCivQuoteEntry( SOLDIERTYPE *pCiv, UINT16 *pubCivHintToUse, BOOLEAN fCanUseHints ) { UINT8 ubCivType; INT8 bTownId; @@ -478,11 +486,29 @@ UINT8 DetermineCivQuoteEntry( SOLDIERTYPE *pCiv, UINT8 *pubCivHintToUse, BOOLEAN INT8 bCivHint; INT8 bMineId; BOOLEAN bMiners = FALSE; - + UINT16 iCounter2; + UINT16 FileEDTQUoteID; + (*pubCivHintToUse) = 0; ubCivType = GetCivType( pCiv ); - + + + for( iCounter2 = NON_CIV_GROUP; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if (pCiv->ubCivilianGroup > QUEENS_CIV_GROUP && pCiv->ubCivilianGroup == iCounter2) + { + if ( pCiv->aiData.bNeutral ) + { + return( FileEDTQUoteID = iCounter2*2 +10); + } + else + { + return( FileEDTQUoteID = iCounter2*2 + 11); + } + } + } + if ( ubCivType == CIV_TYPE_ENEMY ) { // Determine what type of quote to say... @@ -778,19 +804,23 @@ void HandleCivQuote( ) void StartCivQuote( SOLDIERTYPE *pCiv ) { - UINT8 ubCivQuoteID; + UINT16 ubCivQuoteID; INT16 sX, sY; - UINT8 ubEntryID = 0; + UINT16 ubEntryID = 0; INT16 sScreenX, sScreenY; - UINT8 ubCivHintToUse; - + UINT16 ubCivHintToUse; + UINT16 CivQuoteDelta = 0; + + UINT16 ubCivQuoteID2; + UINT16 RandomVal; + // ATE: Check for old quote..... // This could have been stored on last attempt... if ( pCiv->bCurrentCivQuote == CIV_QUOTE_HINT ) { // Determine which quote to say..... - // CAN'T USE HINTS, since we just did one... - pCiv->bCurrentCivQuote = -1; + // CAN'T USE HINTS, since we just did one... + pCiv->bCurrentCivQuote = -1; pCiv->bCurrentCivQuoteDelta = 0; ubCivQuoteID = DetermineCivQuoteEntry( pCiv, &ubCivHintToUse, FALSE ); } @@ -799,7 +829,23 @@ void StartCivQuote( SOLDIERTYPE *pCiv ) // Determine which quote to say..... ubCivQuoteID = DetermineCivQuoteEntry( pCiv, &ubCivHintToUse, TRUE ); } - + + if (ubCivQuoteID == CIV_QUOTE_ADULTS_REBELS || ubCivQuoteID == CIV_QUOTE_KIDS_REBELS || ubCivQuoteID == CIV_QUOTE_ENEMY_OFFER_SURRENDER ) + { + RandomVal = 5; + } + else if (ubCivQuoteID == CIV_QUOTE_PC_MARRIED) + { + RandomVal = 2; + } + else if (ubCivQuoteID == CIV_QUOTE_HICKS_SEE_US_AT_NIGHT) + { + RandomVal = 3; + } + else + RandomVal = 15; + + // Determine entry id // ATE: Try and get entry from soldier pointer.... if ( ubCivQuoteID != CIV_QUOTE_HINT ) @@ -807,19 +853,23 @@ void StartCivQuote( SOLDIERTYPE *pCiv ) if ( pCiv->bCurrentCivQuote == -1 ) { // Pick random one - pCiv->bCurrentCivQuote = (INT8)Random( gCivQuotes[ ubCivQuoteID ].ubNumEntries - 2 ); + //pCiv->bCurrentCivQuote = (INT8)Random( gCivQuotes[ ubCivQuoteID ].ubNumEntries - 2 ); + ubCivQuoteID2 = Random(RandomVal-2); pCiv->bCurrentCivQuoteDelta = 0; } - ubEntryID = pCiv->bCurrentCivQuote + pCiv->bCurrentCivQuoteDelta; + //ubEntryID = pCiv->bCurrentCivQuote + pCiv->bCurrentCivQuoteDelta; + ubEntryID = ubCivQuoteID2 + pCiv->bCurrentCivQuoteDelta; } else { - ubEntryID = ubCivHintToUse; + ubEntryID =ubCivHintToUse; // ATE: set value for quote ID..... - pCiv->bCurrentCivQuote = ubCivQuoteID; - pCiv->bCurrentCivQuoteDelta = ubEntryID; + //pCiv->bCurrentCivQuote = ubCivQuoteID; + ubCivQuoteID2 = ubCivQuoteID; + CivQuoteDelta = ubEntryID; + //pCiv->bCurrentCivQuoteDelta = ubEntryID; } @@ -835,20 +885,26 @@ void StartCivQuote( SOLDIERTYPE *pCiv ) // Increment use if ( ubCivQuoteID != CIV_QUOTE_HINT ) { - pCiv->bCurrentCivQuoteDelta++; - + //pCiv->bCurrentCivQuoteDelta++; + CivQuoteDelta++; + /* if ( pCiv->bCurrentCivQuoteDelta == 2 ) { pCiv->bCurrentCivQuoteDelta = 0; } + */ + if ( CivQuoteDelta == 2 ) + { + CivQuoteDelta = 0; + } + + } } - void InitCivQuoteSystem( ) { - memset( &gCivQuotes, 0, sizeof( gCivQuotes ) ); - CopyNumEntriesIntoQuoteStruct( ); + memset( &gCivQuotes, 0, sizeof( gCivQuotes ) ); //Not used memset( &gCivQuoteData, 0, sizeof( gCivQuoteData ) ); gCivQuoteData.bActive = FALSE; @@ -856,12 +912,13 @@ void InitCivQuoteSystem( ) gCivQuoteData.iDialogueBox = -1; } - +//-------------------------------------------------------------- +//is allowed remove. Not used and remove from SaveLoadGame.cpp. BOOLEAN SaveCivQuotesToSaveGameFile( HWFILE hFile ) { UINT32 uiNumBytesWritten; - FileWrite( hFile, &gCivQuotes, sizeof( gCivQuotes ), &uiNumBytesWritten ); + FileWrite( hFile, &gCivQuotes, sizeof( gCivQuotes), &uiNumBytesWritten ); if( uiNumBytesWritten != sizeof( gCivQuotes ) ) { return( FALSE ); @@ -870,7 +927,7 @@ BOOLEAN SaveCivQuotesToSaveGameFile( HWFILE hFile ) return( TRUE ); } - +//is allowed remove. Not used and remove from SaveLoadGame.cpp. BOOLEAN LoadCivQuotesFromLoadGameFile( HWFILE hFile ) { UINT32 uiNumBytesRead; @@ -881,7 +938,140 @@ BOOLEAN LoadCivQuotesFromLoadGameFile( HWFILE hFile ) return( FALSE ); } - CopyNumEntriesIntoQuoteStruct( ); + CopyNumEntriesIntoQuoteStruct( ); //Not used return( TRUE ); } +//-------------------------------------------------------------- + +// SANDRO - soldier taunts +void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ) +{ + INT16 sX, sY; + UINT8 ubEntryID = 0; + INT16 sScreenX, sScreenY; + UINT16 iTauntNumber; + STR16 sTauntText; + VIDEO_OVERLAY_DESC VideoOverlayDesc; + CHAR16 gzTauntQuote[ 320 ]; + + // if we have a different quote on, return, this one is not important + if ( gCivQuoteData.bActive ) + { + return; + } + + switch(iTauntType) + { + case TAUNT_FIRE_GUN: + iTauntNumber = Random(15); + sTauntText = sEnemyTauntsFireGun[iTauntNumber]; + break; + case TAUNT_FIRE_LAUNCHER: + iTauntNumber = Random(4); + sTauntText = sEnemyTauntsFireLauncher[iTauntNumber]; + break; + case TAUNT_THROW: + iTauntNumber = Random(7); + sTauntText = sEnemyTauntsThrow[iTauntNumber]; + break; + case TAUNT_CHARGE_KNIFE: + iTauntNumber = Random(5); + sTauntText = sEnemyTauntsChargeKnife[iTauntNumber]; + break; + case TAUNT_RUN_AWAY: + iTauntNumber = Random(7); + sTauntText = sEnemyTauntsRunAway[iTauntNumber]; + break; + case TAUNT_SEEK_NOISE: + iTauntNumber = Random(4); + sTauntText = sEnemyTauntsSeekNoise[iTauntNumber]; + break; + case TAUNT_ALERT: + iTauntNumber = Random(3); + sTauntText = sEnemyTauntsAlert[iTauntNumber]; + break; + case TAUNT_GOT_HIT: + iTauntNumber = Random(7); + sTauntText = sEnemyTauntsGotHit[iTauntNumber]; + break; + default: + return; + break; + } + + // Determine location... + // Get location of civ on screen..... + GetSoldierScreenPos( pCiv, &sScreenX, &sScreenY ); + sX = sScreenX; + sY = sScreenY; + +#ifdef TAIWANESE + swprintf( gzTauntQuote, L"%s", sTauntText ); +#else + swprintf( gzTauntQuote, L"\"%s\"", sTauntText ); +#endif + + // Create video oeverlay.... + memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) ); + + // Prepare text box + gCivQuoteData.iDialogueBox = PrepareMercPopupBox( gCivQuoteData.iDialogueBox , BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gzTauntQuote, DIALOGUE_DEFAULT_WIDTH, 0, 0, 0, &gusCivQuoteBoxWidth, &gusCivQuoteBoxHeight ); + + // OK, find center for box...... + sX = sX - ( gusCivQuoteBoxWidth / 2 ); + sY = sY - ( gusCivQuoteBoxHeight / 2 ); + + // OK, limit to screen...... + { + if ( sX < 0 ) + { + sX = 0; + } + + // CHECK FOR LEFT/RIGHT + if ( ( sX + gusCivQuoteBoxWidth ) > SCREEN_WIDTH ) + { + sX = SCREEN_WIDTH - gusCivQuoteBoxWidth; + } + + // Now check for top + if ( sY < gsVIEWPORT_WINDOW_START_Y ) + { + sY = gsVIEWPORT_WINDOW_START_Y; + } + + // Check for bottom + if ( ( sY + gusCivQuoteBoxHeight ) > (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT)) + { + sY = (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT) - gusCivQuoteBoxHeight; + } + } + + VideoOverlayDesc.sLeft = sX; + VideoOverlayDesc.sTop = sY; + VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + gusCivQuoteBoxWidth; + VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + gusCivQuoteBoxHeight; + VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; + VideoOverlayDesc.sY = VideoOverlayDesc.sTop; + VideoOverlayDesc.BltCallback = RenderCivQuoteBoxOverlay; + + gCivQuoteData.iVideoOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); + + + //Define main region + MSYS_DefineRegion( &(gCivQuoteData.MouseRegion), VideoOverlayDesc.sLeft, VideoOverlayDesc.sTop, VideoOverlayDesc.sRight, VideoOverlayDesc.sBottom, MSYS_PRIORITY_HIGHEST, + CURSOR_NORMAL, MSYS_NO_CALLBACK, QuoteOverlayClickCallback ); + // Add region + MSYS_AddRegion( &(gCivQuoteData.MouseRegion) ); + + + gCivQuoteData.bActive = TRUE; + + gCivQuoteData.uiTimeOfCreation = GetJA2Clock( ); + + gCivQuoteData.uiDelayTime = FindDelayForString( gzCivQuote ) + 1500; + + gCivQuoteData.pCiv = pCiv; + +} \ No newline at end of file diff --git a/Tactical/Civ Quotes.h b/Tactical/Civ Quotes.h index 2847b0ae..9afe8641 100644 --- a/Tactical/Civ Quotes.h +++ b/Tactical/Civ Quotes.h @@ -11,8 +11,8 @@ enum { - CIV_QUOTE_ADULTS_BEGGING, - CIV_QUOTE_KIDS_BEGGING, + CIV_QUOTE_ADULTS_BEGGING, //CIV00.EDT + CIV_QUOTE_KIDS_BEGGING, CIV_QUOTE_ADULTS_RECENT_BUG_ATTACK, CIV_QUOTE_KIDS_RECENT_BUG_ATTACK, CIV_QUOTE_ADULTS_BUG_EXTERMINATED_X_TIME, @@ -22,7 +22,7 @@ enum CIV_QUOTE_ADULTS_HIGH_LOYALTY, CIV_QUOTE_KIDS_HIGH_LOYALTY, - CIV_QUOTE_ADULTS_ALL_PURPOSE, + CIV_QUOTE_ADULTS_ALL_PURPOSE, //CIV10.EDT CIV_QUOTE_KIDS_ALL_PURPOSE, CIV_QUOTE_ADULTS_LIBREATED_FIRST_TIME, CIV_QUOTE_KIDS_LIBREATED_FIRST_TIME, @@ -33,7 +33,7 @@ enum CIV_QUOTE_GOONS_FRIENDLY, CIV_QUOTE_GOONS_ENEMIES, - CIV_QUOTE_ADULTS_REBELS, + CIV_QUOTE_ADULTS_REBELS, //CIV20.EDT CIV_QUOTE_KIDS_REBELS, CIV_QUOTE_GREEN_MILITIA, CIV_QUOTE_MEDIUM_MILITIA, @@ -44,7 +44,7 @@ enum CIV_QUOTE_ENEMY_THREAT, CIV_QUOTE_ENEMY_ELITE, - CIV_QUOTE_ADULTS_COWER, + CIV_QUOTE_ADULTS_COWER, //CIV30.EDT CIV_QUOTE_KIDS_COWER, CIV_QUOTE_PC_MARRIED, CIV_QUOTE_KID_SLAVES, @@ -54,22 +54,25 @@ enum CIV_QUOTE_ENEMY_OFFER_SURRENDER, CIV_QUOTE_HICKS_SEE_US_AT_NIGHT, CIV_QUOTE_DEIDRANNA_DEAD, - - CIV_QUOTE_40, - CIV_QUOTE_41, - CIV_QUOTE_42, - CIV_QUOTE_43, - CIV_QUOTE_44, - CIV_QUOTE_45, - CIV_QUOTE_46, - CIV_QUOTE_47, - CIV_QUOTE_48, - CIV_QUOTE_49, - + + CIV_QUOTE_NEW = CIV_QUOTE_DEIDRANNA_DEAD + 1000, // 500 reserved + NUM_CIV_QUOTES }; +enum //enemy taunts - SANDRO +{ + TAUNT_FIRE_GUN, + TAUNT_FIRE_LAUNCHER, + TAUNT_THROW, + TAUNT_CHARGE_KNIFE, + TAUNT_RUN_AWAY, + TAUNT_SEEK_NOISE, + TAUNT_ALERT, + TAUNT_GOT_HIT +}; +void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ); //enemy taunts - SANDRO void InitCivQuoteSystem( ); @@ -84,6 +87,6 @@ BOOLEAN LoadCivQuotesFromLoadGameFile( HWFILE hFile ); BOOLEAN ShutDownQuoteBoxIfActive( ); -void BeginCivQuote( SOLDIERTYPE *pCiv, UINT8 ubCivQuoteID, UINT8 ubEntryID, INT16 sX, INT16 sY ); +void BeginCivQuote( SOLDIERTYPE *pCiv, UINT16 ubCivQuoteID, UINT16 ubEntryID, INT16 sX, INT16 sY ); #endif \ No newline at end of file diff --git a/Tactical/Dialogue Control.cpp b/Tactical/Dialogue Control.cpp index a7499597..2c500356 100644 --- a/Tactical/Dialogue Control.cpp +++ b/Tactical/Dialogue Control.cpp @@ -55,6 +55,7 @@ #include "end game.h" #include "los.h" #include "qarray.h" + #include "Soldier Profile.h" #endif #include #include "Auto Resolve.h" @@ -83,7 +84,7 @@ class SOLDIERTYPE; #define DIALOGUE_DEFAULT_SUBTITLE_WIDTH 200 #define TEXT_DELAY_MODIFIER 60 - +SOUND_PROFILE_VALUES gSoundProfileValue[NUM_PROFILES]; typedef struct { @@ -114,16 +115,19 @@ extern BOOLEAN gfWaitingForTriggerTimer; BOOLEAN fExternFacesLoaded = FALSE; -UINT32 uiExternalStaticNPCFaces[ NUMBER_OF_EXTERNAL_NPC_FACES ]; -UINT32 uiExternalFaceProfileIds[ NUMBER_OF_EXTERNAL_NPC_FACES ]= -{ - 97, - 106, - 148, - 156, - 157, - 158, -}; + +// head miners' external profile ids have been moved to lua script +std::vector uiExternalStaticNPCFaces; +//UINT32 uiExternalStaticNPCFaces[ NUMBER_OF_EXTERNAL_NPC_FACES ]; +//UINT32 uiExternalFaceProfileIds[ NUMBER_OF_EXTERNAL_NPC_FACES ]= +//{ +// 97, +// 106, +// 148, +// 156, +// 157, +// 158, +//}; UINT8 gubMercValidPrecedentQuoteID[ NUMBER_VALID_MERC_PRECEDENT_QUOTES ] = { 80, 81, 82, 83, 86, 87, 88, 95, 97, 99, 100, 101, 102 }; @@ -302,10 +306,16 @@ void InitalizeStaticExternalNPCFaces( void ) fExternFacesLoaded = TRUE; - for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) - { - uiExternalStaticNPCFaces[ iCounter ] = ( UINT32 )InitFace( ( UINT8 )( uiExternalFaceProfileIds[ iCounter ] ), NOBODY, FACE_FORCE_SMALL ); - } + + // + // Code for loading miners' faces has been moved to LuaMines::InitMinerFaces ... + // + //for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) + //{ + // uiExternalStaticNPCFaces[ iCounter ] = ( UINT32 )InitFace( ( UINT8 )( uiExternalFaceProfileIds[ iCounter ] ), NOBODY, FACE_FORCE_SMALL ); + //} + // ... put Skyrider's face at index 0 + uiExternalStaticNPCFaces.push_back(( UINT32 )InitFace( ( UINT8 )( SKYRIDER ), NOBODY, FACE_FORCE_SMALL )); return; } @@ -322,10 +332,16 @@ void ShutdownStaticExternalNPCFaces( void ) fExternFacesLoaded = FALSE; // remove all external npc faces - for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) + //for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_NPC_FACES; iCounter++ ) + //{ + // DeleteFace( uiExternalStaticNPCFaces[ iCounter ] ); + //} + for (std::vector::iterator face = uiExternalStaticNPCFaces.begin(); + face != uiExternalStaticNPCFaces.end(); ++face) { - DeleteFace( uiExternalStaticNPCFaces[ iCounter ] ); + DeleteFace(*face); } + uiExternalStaticNPCFaces.clear(); } @@ -1599,11 +1615,11 @@ BOOLEAN ExecuteCharacterDialogue( UINT8 ubCharacterNum, UINT16 usQuoteNum, INT32 // now being used in a different way... /* if ( ( (usQuoteNum == QUOTE_PERSONALITY_TRAIT && - (gMercProfiles[ubCharacterNum].bPersonalityTrait == FORGETFUL || - gMercProfiles[ubCharacterNum].bPersonalityTrait == CLAUSTROPHOBIC || - gMercProfiles[ubCharacterNum].bPersonalityTrait == NERVOUS || - gMercProfiles[ubCharacterNum].bPersonalityTrait == NONSWIMMER || - gMercProfiles[ubCharacterNum].bPersonalityTrait == FEAR_OF_INSECTS)) + (gMercProfiles[ubCharacterNum].bDisability == FORGETFUL || + gMercProfiles[ubCharacterNum].bDisability == CLAUSTROPHOBIC || + gMercProfiles[ubCharacterNum].bDisability == NERVOUS || + gMercProfiles[ubCharacterNum].bDisability == NONSWIMMER || + gMercProfiles[ubCharacterNum].bDisability == FEAR_OF_INSECTS)) //usQuoteNum == QUOTE_STARTING_TO_WHINE || #ifdef JA2BETAVERSION || usQuoteNum == QUOTE_WHINE_EQUIPMENT) && (guiCurrentScreen != QUEST_DEBUG_SCREEN) ) @@ -1750,11 +1766,14 @@ CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN // sprintf( zFileName,"NPC_SPEECH\\g_%03d_%03d.wav",ubCharacterNum,usQuoteNum ); // } // #else + if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) + { sprintf( zFileName,"NPC_SPEECH\\d_%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"NPC_SPEECH\\d_%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } + } // #endif } else @@ -1763,7 +1782,9 @@ CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN sprintf( zFileName,"NPCDATA\\d_%03d.EDT", ubCharacterNum ); } } - else if ( ubCharacterNum >= FIRST_RPC && ubCharacterNum < GASTON && + //else if ( ubCharacterNum >= FIRST_RPC && ubCharacterNum < GASTON && + //new profiles by Jazz + else if ( ( gProfilesRPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesNPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesVehicle[ubCharacterNum].ProfilId == ubCharacterNum ) && ( !( gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) || ProfileCurrentlyTalkingInDialoguePanel( ubCharacterNum ) || (gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_FORCENPCQUOTE) ) @@ -1786,11 +1807,14 @@ CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN if ( fWavFile ) { - // Lesh: patch to allow playback ogg speech files - sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.ogg",ubFileNumID,usQuoteNum ); - if ( !FileExists( zFileName ) ) + if ( gSoundProfileValue[ubFileNumID].EnabledSound == TRUE ) { - sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.wav",ubFileNumID,usQuoteNum ); + // Lesh: patch to allow playback ogg speech files + sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.ogg",ubFileNumID,usQuoteNum ); + if ( !FileExists( zFileName ) ) + { + sprintf( zFileName,"NPC_SPEECH\\%03d_%03d.wav",ubFileNumID,usQuoteNum ); + } } } else @@ -1804,8 +1828,12 @@ CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN if ( fWavFile ) { #ifdef RUSSIAN - if( ubCharacterNum >= FIRST_RPC && ubCharacterNum < GASTON && gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) + // if( ubCharacterNum >= FIRST_RPC && ubCharacterNum < GASTON && gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) + //new profiles by Jazz + if ( ( gProfilesRPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesNPC[ubCharacterNum].ProfilId == ubCharacterNum || gProfilesVehicle[ubCharacterNum].ProfilId == ubCharacterNum ) && gMercProfiles[ ubCharacterNum ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) { + if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) + { sprintf( zFileName,"SPEECH\\r_%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { @@ -1821,15 +1849,20 @@ CHAR8 *GetDialogueDataFilename( UINT8 ubCharacterNum, UINT16 usQuoteNum, BOOLEAN } // } + } } else #endif - { // build name of wav file (characternum + quotenum) + { + if ( gSoundProfileValue[ubCharacterNum].EnabledSound == TRUE ) + { + // build name of wav file (characternum + quotenum) sprintf( zFileName,"SPEECH\\%03d_%03d.ogg",ubCharacterNum,usQuoteNum ); if ( !FileExists( zFileName ) ) { sprintf( zFileName,"SPEECH\\%03d_%03d.wav",ubCharacterNum,usQuoteNum ); } + } } } else @@ -2636,12 +2669,12 @@ void SayQuote58FromNearbyMercInSector( INT32 sGridNo, INT8 bDistance, UINT16 usQ SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, 0, 0, TRUE ) ) { // ATE: This is to check gedner for this quote... - if ( QuoteExp_GenderCode[ pTeamSoldier->ubProfile ] == 0 && bSex == FEMALE ) + if ( QuoteExp[ pTeamSoldier->ubProfile ].QuoteExpGenderCode == 0 && bSex == FEMALE ) { continue; } - if ( QuoteExp_GenderCode[ pTeamSoldier->ubProfile ] == 1 && bSex == MALE ) + if ( QuoteExp[ pTeamSoldier->ubProfile ].QuoteExpGenderCode == 1 && bSex == MALE ) { continue; } diff --git a/Tactical/Dialogue Control.h b/Tactical/Dialogue Control.h index 0c704032..9039cb78 100644 --- a/Tactical/Dialogue Control.h +++ b/Tactical/Dialogue Control.h @@ -3,6 +3,17 @@ #include "faces.h" #include "gamescreen.h" +#include "soldier profile type.h" +#include + +typedef struct +{ + UINT16 uiIndex; // add + BOOLEAN EnabledSound; + +} SOUND_PROFILE_VALUES; + +extern SOUND_PROFILE_VALUES gSoundProfileValue[NUM_PROFILES]; // An enumeration for dialog quotes enum DialogQuoteIDs @@ -209,12 +220,12 @@ enum DialogQuoteIDs enum{ SKYRIDER_EXTERNAL_FACE =0, - MINER_FRED_EXTERNAL_FACE, - MINER_MATT_EXTERNAL_FACE, - MINER_OSWALD_EXTERNAL_FACE, - MINER_CALVIN_EXTERNAL_FACE, - MINER_CARL_EXTERNAL_FACE, - NUMBER_OF_EXTERNAL_NPC_FACES, + //MINER_FRED_EXTERNAL_FACE, + //MINER_MATT_EXTERNAL_FACE, + //MINER_OSWALD_EXTERNAL_FACE, + //MINER_CALVIN_EXTERNAL_FACE, + //MINER_CARL_EXTERNAL_FACE, + //NUMBER_OF_EXTERNAL_NPC_FACES, }; @@ -225,8 +236,9 @@ enum{ UPDATE_BOX_REASON_SHOW_BOX, }; -extern UINT32 uiExternalStaticNPCFaces[ ]; -extern UINT32 uiExternalFaceProfileIds[ ]; +//extern UINT32 uiExternalStaticNPCFaces[ ]; +extern std::vector uiExternalStaticNPCFaces; +//extern UINT32 uiExternalFaceProfileIds[ ]; // Functions for handling dialogue Q BOOLEAN InitalizeDialogueControl(); diff --git a/Tactical/DisplayCover.cpp b/Tactical/DisplayCover.cpp index 7734241d..72038389 100644 --- a/Tactical/DisplayCover.cpp +++ b/Tactical/DisplayCover.cpp @@ -40,21 +40,22 @@ class SOLDIERTYPE; //******* Local Defines ************************************************** +enum COVER_VALUES +{ + INVALID_COVER=-1, + NO_COVER=0, + MIN_COVER=1, + MED_COVER=2, + MAX_COVER=3 +}; + struct CoverCell { INT32 sGridNo; INT8 bCover; BOOLEAN fInverseColor; - CoverCell() : sGridNo(NOWHERE), bCover(-1), fInverseColor(FALSE) {} -}; - -enum COVER_VALUES -{ - NO_COVER=0, - MIN_COVER=1, - MED_COVER=2, - MAX_COVER=3 + CoverCell() : sGridNo(NOWHERE), bCover(INVALID_COVER), fInverseColor(FALSE) {} }; enum COVER_DRAW_MODE { @@ -63,35 +64,28 @@ enum COVER_DRAW_MODE { COVER_DRAW_ENEMY_VIEW }; -COVER_DRAW_MODE gubDrawMode = COVER_DRAW_OFF; - const UINT8 animArr[3] = { ANIM_PRONE, ANIM_CROUCH, ANIM_STAND }; -//****** Global Variables ***************************************** - -// yea way too big... but some bytes more memory is cheap, as well as some extra loops -// PS: brainscells arn't cheap ;) -#define COVER_X_CELLS WORLD_COLS -#define COVER_Y_CELLS WORLD_ROWS +// yea way too big... but some bytes more memory is cheap +#define COVER_X_CELLS WORLD_COLS_MAX +#define COVER_Y_CELLS WORLD_ROWS_MAX #define COVER_Z_CELLS 2 // roof or no roof +//****** Local Variables ********************************************* + INT16 gsMinCellX, gsMinCellY, gsMaxCellX, gsMaxCellY = -1; -// WANNE - BMP: COVER_X_CELLS, COVER_Y_CELLS, have to be constants, -// so I set them to 2000 (for rows and cols). In normal map it is 160 - -//CoverCell gCoverViewArea[ COVER_X_CELLS ][ COVER_Y_CELLS ][ COVER_Z_CELLS ]; -CoverCell gCoverViewArea[ 2000 ][ 2000 ][ COVER_Z_CELLS ]; +CoverCell gCoverViewArea[ COVER_X_CELLS ][ COVER_Y_CELLS ][ COVER_Z_CELLS ]; DWORD guiCoverNextUpdateTime = 0; -//******* Function Prototypes *************************************** +COVER_DRAW_MODE gubDrawMode = COVER_DRAW_OFF; -void SwitchCoverDrawMode(); +//******* Local Function Prototypes *********************************** CHAR16* GetTerrainName( const UINT8& ubTerrainType ); @@ -116,30 +110,71 @@ BOOLEAN HasAdjTile( const INT32& ubX, const INT32& ubY ); //******* Functions ************************************************** -// TODO: internationalize +///BEGIN key binding functions +void SwitchToMercView() +{ + if (gubDrawMode == COVER_DRAW_MERC_VIEW) + return; + + gubDrawMode = COVER_DRAW_MERC_VIEW; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzDisplayCoverText[DC_MSG__COVER_DRAW_MERC_VIEW]); + DisplayCover(TRUE); +} + +void SwitchToEnemyView() +{ + if (gubDrawMode == COVER_DRAW_ENEMY_VIEW) + return; + + gubDrawMode = COVER_DRAW_ENEMY_VIEW; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzDisplayCoverText[DC_MSG__COVER_DRAW_ENEMY_VIEW]); + DisplayCover(TRUE); +} + +void SwitchViewOff() +{ + if (gubDrawMode == COVER_DRAW_OFF) + return; + + gubDrawMode = COVER_DRAW_OFF; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzDisplayCoverText[DC_MSG__COVER_DRAW_OFF]); + DisplayCover(TRUE); +} + +void ToggleEnemyView() +{ + if (gubDrawMode == COVER_DRAW_ENEMY_VIEW) { + SwitchViewOff(); + } else { + SwitchToEnemyView(); + } +} + +void ToggleMercView() +{ + if (gubDrawMode == COVER_DRAW_MERC_VIEW) { + SwitchViewOff(); + } else { + SwitchToMercView(); + } +} + void SwitchCoverDrawMode() { - CHAR16 zDebugString[512]; - switch(gubDrawMode) { case COVER_DRAW_OFF: - swprintf( zDebugString, gzDisplayCoverText[DC_MSG__COVER_DRAW_MERC_VIEW] ); - gubDrawMode = COVER_DRAW_MERC_VIEW; + SwitchToMercView(); break; case COVER_DRAW_MERC_VIEW: - swprintf( zDebugString, gzDisplayCoverText[DC_MSG__COVER_DRAW_ENEMY_VIEW] ); - gubDrawMode = COVER_DRAW_ENEMY_VIEW; + SwitchToEnemyView(); break; default: - swprintf( zDebugString, gzDisplayCoverText[DC_MSG__COVER_DRAW_OFF] ); - gubDrawMode = COVER_DRAW_OFF; + SwitchViewOff(); break; } - - DisplayCover(TRUE); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, zDebugString ); } +///END key binding functions void GetGridNoForViewPort( const INT32& ubX, const INT32& ubY, INT32& sGridNo ) { @@ -472,10 +507,7 @@ void CalculateCoverForSoldier( SOLDIERTYPE* pSoldier, const INT32& sTargetGridNo pbPublOL = gbPublicOpplist[ OUR_TEAM ] + pOpponent->ubID; // if this opponent is unknown personally and publicly - if( *pbPersOL != SEEN_CURRENTLY && - *pbPersOL != SEEN_THIS_TURN && - *pbPublOL != SEEN_CURRENTLY && - *pbPublOL != SEEN_THIS_TURN ) + if( *pbPersOL != SEEN_CURRENTLY && *pbPublOL != SEEN_CURRENTLY ) { continue; // next merc } @@ -503,7 +535,7 @@ void CalculateCoverFromSoldier( SOLDIERTYPE* pFromSoldier, const INT32& sTargetG if (pToSoldier == NULL) { usAdjustedSight = usSightLimit; } else { - usAdjustedSight = usSightLimit + usSightLimit * GetSightAdjustment( pToSoldier, sTargetGridNo, ubStance ) /100; + usAdjustedSight = usSightLimit + usSightLimit * GetSightAdjustment( pToSoldier, sTargetGridNo, (INT8) fRoof, ubStance ) /100; } if ( SoldierToVirtualSoldierLineOfSightTest( pFromSoldier, sTargetGridNo, (INT8) fRoof, ubStance, FALSE, usAdjustedSight ) != 0 ) @@ -526,17 +558,20 @@ void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) { UINT8 ubLightLevel = LightTrueLevel(sTargetGridNo, gsInterfaceLevel); - UINT8 ubBrightness = 100 * (SHADE_MIN - ubLightLevel)/SHADE_MIN; // percentage + UINT8 ubBrightness = 100 - 100 * (ubLightLevel-SHADE_MAX)/(SHADE_MIN-SHADE_MAX); // percentage + INT8 ubTerrainType = GetTerrainTypeForGrid(sTargetGridNo, gsInterfaceLevel); - INT8 ubTerrainType = GetTerrainTypeForGrid(sTargetGridNo); - - INT8 ubCover = - GetSightAdjustment(pSoldier, sTargetGridNo); + INT8 ubCover = - GetSightAdjustment(pSoldier, sTargetGridNo, gsInterfaceLevel); //display a string with cover value of current selected merc and brightness - swprintf( zOutputString, gzDisplayCoverText[DC_MSG__COVER_INFORMATION], ubCover, GetTerrainName(ubTerrainType), ubBrightness ); + //swprintf( zOutputString, gzDisplayCoverText[DC_MSG__COVER_INFORMATION], ubCover, GetTerrainName(ubTerrainType), ubBrightness ); //Display the msg - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, zOutputString ); + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, zOutputString ); + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, + gzDisplayCoverText[DC_MSG__COVER_INFORMATION], + ubCover, GetTerrainName(ubTerrainType), ubBrightness ); } //Get the range to the target location @@ -558,7 +593,7 @@ void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) pSoldier->bTargetLevel = bTempTargetLevel; // HEADROCK HAM 3.6: Calculate Gun Range using formula. - UINT16 usGunRange = GunRange(&pSoldier->inv[HANDPOS]); + UINT16 usGunRange = GunRange(&pSoldier->inv[HANDPOS], pSoldier ); // SANDRO - added argument swprintf( zOutputString, gzDisplayCoverText[DC_MSG__GUN_RANGE_INFORMATION], usRange / 10, usGunRange / 10, uiHitChance ); //Display the msg diff --git a/Tactical/DisplayCover.h b/Tactical/DisplayCover.h index c5bc22de..91345c2b 100644 --- a/Tactical/DisplayCover.h +++ b/Tactical/DisplayCover.h @@ -1,8 +1,38 @@ #ifndef _DISPLAY_COVER__H_ #define _DISPLAY_COVER__H_ +void DisplayCoverOfSelectedGridNo( ); +void RemoveCoverOfSelectedGridNo(); + void DisplayRangeToTarget( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ); void DisplayCover(const BOOLEAN& forceUpdate = FALSE); + +void SwitchToMercView(); +void SwitchToEnemyView(); +void SwitchViewOff(); + +void ToggleMercView(); +void ToggleEnemyView(); + void SwitchCoverDrawMode(); +void RemoveVisibleGridNoAtSelectedGridNo(); +void DisplayGridNoVisibleToSoldierGrid( ); + + +#define DC_MAX_COVER_RANGE 43 //31 +#define DC__SOLDIER_VISIBLE_RANGE 43 //31 +#define DC__MIN_SIZE 4 +#define DC__MAX_SIZE 21 //11 + +#ifdef JA2TESTVERSION + void DisplayLosAndDisplayCoverUsageScreenMsg(); +#endif + +void ChangeSizeOfDisplayCover( INT32 iNewSize ); + +void ChangeSizeOfLOS( INT32 iNewSize ); +//ddd for optimize oppponent turn +INT8 CalcCoverForGridNoBasedOnTeamKnownEnemies( SOLDIERTYPE *pSoldier, INT16 sTargetGridNo, INT8 bStance ); +//ddd for optimize oppponent turn #endif diff --git a/Tactical/Drugs And Alcohol.cpp b/Tactical/Drugs And Alcohol.cpp index d64518a7..f4f8d13e 100644 --- a/Tactical/Drugs And Alcohol.cpp +++ b/Tactical/Drugs And Alcohol.cpp @@ -10,6 +10,7 @@ #include "morale.h" #include "points.h" #include "message.h" + #include "GameSettings.h" // SANDRO - had to add this, dammit! #include "Random.h" #include "Text.h" #include "Interface.h" @@ -151,30 +152,84 @@ BOOLEAN ApplyDrugs( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObject ) // Keel over... DeductPoints( pSoldier, 0, 10000 ); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - if our stat is damaged through facility event, make it healable // Permanently lower certain stats... - pSoldier->stats.bWisdom -= 5; - pSoldier->stats.bDexterity -= 5; - pSoldier->stats.bStrength -= 5; + if ( gGameOptions.fNewTraitSystem ) + { + // WISDOM decrease + if ( pSoldier->stats.bWisdom > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] += 5; + pSoldier->stats.bWisdom -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] += (pSoldier->stats.bWisdom - 1); + pSoldier->stats.bWisdom = 1; + } + // DEXTERITY decrease + if ( pSoldier->stats.bDexterity > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] += 5; + pSoldier->stats.bDexterity -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] += (pSoldier->stats.bDexterity - 1); + pSoldier->stats.bDexterity = 1; + } + // STRENGTH decrease + if ( pSoldier->stats.bStrength > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] += 5; + pSoldier->stats.bStrength -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] += (pSoldier->stats.bStrength - 1); + pSoldier->stats.bStrength = 1; + } + // AGILITY decrease + if ( pSoldier->stats.bAgility > 5 ) + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] += 5; + pSoldier->stats.bAgility -= 5; + } + else + { + pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] += (pSoldier->stats.bAgility - 1); + pSoldier->stats.bAgility = 1; + } + } + else // old system + { + pSoldier->stats.bAgility = __max(1, pSoldier->stats.bWisdom-5); + pSoldier->stats.bDexterity = __max(1, pSoldier->stats.bDexterity-5); + pSoldier->stats.bStrength = __max(1, pSoldier->stats.bStrength-5); + pSoldier->stats.bAgility = __max(1, pSoldier->stats.bAgility-5); - if (pSoldier->stats.bWisdom < 1) - pSoldier->stats.bWisdom = 1; - if (pSoldier->stats.bDexterity < 1) - pSoldier->stats.bDexterity = 1; - if (pSoldier->stats.bStrength < 1) - pSoldier->stats.bStrength = 1; + // make those stats RED for a while... + // SANDRO - we don't need to do this with new system, as we simply show all damaged stats in red until healed + pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); + pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); + pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( AGIL_INCREASE ); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // export stat changes to profile gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom; gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity; gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength; + gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility; - // make those stats RED for a while... - pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); - pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); - pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); - pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + // SANDRO - merc records - stat damaged + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; } } } @@ -308,9 +363,16 @@ void HandleEndTurnDrugAdjustments( SOLDIERTYPE *pSoldier ) // increase life pSoldier->stats.bLife = __min( pSoldier->stats.bLife + LIFE_GAIN_PER_REGEN_POINT, pSoldier->stats.bLifeMax ); + //SANDRO - Insta-healable injury reduction + if( pSoldier->iHealableInjury > 0 ) + { + pSoldier->iHealableInjury = max(0, (pSoldier->iHealableInjury - (100 * LIFE_GAIN_PER_REGEN_POINT))); + } + if ( pSoldier->stats.bLife == pSoldier->stats.bLifeMax ) { pSoldier->bBleeding = 0; + pSoldier->iHealableInjury = 0; } else if ( pSoldier->bBleeding + pSoldier->stats.bLife > pSoldier->stats.bLifeMax ) { diff --git a/Tactical/End Game.cpp b/Tactical/End Game.cpp index c13efeb9..edb0ad2f 100644 --- a/Tactical/End Game.cpp +++ b/Tactical/End Game.cpp @@ -116,7 +116,7 @@ void ChangeO3SectorStatue( BOOLEAN fFromExplosion ) ExitGrid.ubGotoSectorX = 3; ExitGrid.ubGotoSectorY = MAP_ROW_O; ExitGrid.ubGotoSectorZ = 1; - ExitGrid.usGridNo = 13037; + ExitGrid.usGridNo = 13037; //dnl!!! AddExitGridToWorld( 13669, &ExitGrid ); gpWorldLevelData[ 13669 ].uiFlags |= MAPELEMENT_REVEALED; @@ -187,7 +187,7 @@ void HandleDeidrannaDeath( SOLDIERTYPE *pKillerSoldier, INT32 sGridNo, INT8 bLev { if ( OK_INSECTOR_MERC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !AM_AN_EPC( pTeamSoldier ) ) { - if ( QuoteExp_WitnessDeidrannaDeath[ pTeamSoldier->ubProfile ] ) + if ( QuoteExp[ pTeamSoldier->ubProfile ].QuoteExpWitnessDeidrannaDeath ) { if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) ) { @@ -475,7 +475,7 @@ void HandleQueenBitchDeath( SOLDIERTYPE *pKillerSoldier, INT32 sGridNo, INT8 bLe { if ( OK_INSECTOR_MERC( pTeamSoldier ) && !( pTeamSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) && !AM_AN_EPC( pTeamSoldier ) ) { - if ( QuoteExp_WitnessQueenBugDeath[ pTeamSoldier->ubProfile ] ) + if ( QuoteExp[ pTeamSoldier->ubProfile ].QuoteExpWitnessQueenBugDeath ) { if ( SoldierTo3DLocationLineOfSightTest( pTeamSoldier, sGridNo, bLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) ) { diff --git a/Tactical/Faces.cpp b/Tactical/Faces.cpp index f6e9397b..1d698788 100644 --- a/Tactical/Faces.cpp +++ b/Tactical/Faces.cpp @@ -61,90 +61,10 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE extern BOOLEAN gfInItemPickupMenu; +RPC_SMALL_FACE_VALUES gRPCSmallFaceValues[200]; +UINT8 ubRPCNumSmallFaceValues = 200; - -typedef struct -{ - INT8 bEyesX; - INT8 bEyesY; - INT8 bMouthX; - INT8 bMouthY; - -} RPC_SMALL_FACE_VALUES; - - -RPC_SMALL_FACE_VALUES gRPCSmallFaceValues[ ] = -{ - 9, 8, 8, 24, // MIGUEL ( 57 ) - 8, 8, 7, 24, // CARLOS ( 58 ) - 10, 8, 8, 26, // IRA ( 59 ) - 7, 8, 7, 26, // DIMITRI ( 60 ) - 6, 7, 7, 23, // DEVIN ( 61 ) - 0, 0, 0, 0, // THE RAT ( 62 ) - 8, 7, 8, 23, // ( 63 ) - 8, 8, 8, 22, // SLAY ( 64 ) - 0, 0, 0, 0, // ( 65 ) - 9, 4, 7, 22, // DYNAMO ( 66 ) - 8, 8, 8, 25, // SHANK ( 67 ) - 4, 6, 5, 22, // IGGY ( 68 ) - 8, 9, 7, 25, // VINCE ( 69 ) - 4, 7, 5, 25, // CONRAD ( 70 ) - 9, 7, 8, 22, // CARL ( 71 ) - 9, 7, 9, 25, // MADDOG ( 72 ) - 0, 0, 0, 0, // ( 73 ) - 0, 0, 0, 0, // ( 74 ) - - 9, 3, 8, 23, // MARIA ( 88 ) - - 9, 3, 8, 25, // JOEY ( 90 ) - - 11, 7, 9, 24, // SKYRIDER ( 97 ) - 9, 5, 7, 23, // Miner ( 106 ) - - 6, 4, 6, 24, // JOHN ( 118 ) - 12,4, 10, 24, // ( 119 ) - 8, 6, 8, 23, // Miner ( 148 ) - 6, 5, 6, 23, // Miner ( 156 ) - 13, 7, 11, 24, // Miner ( 157 ) - 9, 7, 8, 22, // Miner ( 158 ) - -}; - -UINT8 gubRPCSmallFaceProfileNum[] = -{ - 57, // entry 0 - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, // entry 9 - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 88, - 90, // entry 19 - 97, - 106, - 118, - 119, - 148, // entry 24 - 156, - 157, - 158, - -}; - -UINT8 ubRPCNumSmallFaceValues = 28; - +CAMO_FACE gCamoFace[255]; extern BOOLEAN gfSMDisableForItems; extern INT16 gsCurInterfacePanel; @@ -293,24 +213,91 @@ INT32 InternalInitFace( UINT8 usMercProfileID, UINT8 ubSoldierID, UINT32 uiInitF } else if ( usMercProfileID == TEX ) { - if( gMercProfiles[ TEX ].bSkillTrait2 == CAMOUFLAGED ) + // SANDRO - old/new traits check (I am not sure if this is used at all) + if ( gGameOptions.fNewTraitSystem ) { - sprintf( VObjectDesc.ImageFile, "FACES\\B167c.sti" ); + if ( ProfileHasSkillTrait( TEX, RANGER_NT ) > 0 ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\B167c.sti" ); + } + } + else + { + if ( ProfileHasSkillTrait( TEX, CAMOUFLAGED_OT ) > 0 ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\B167c.sti" ); + } } } - } else { - if( iFaceFileID < 100 ) + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) { - // The filename is the profile ID! - sprintf( VObjectDesc.ImageFile, "FACES\\%02d.sti", iFaceFileID ); + if( iFaceFileID < 100 ) + { + // The filename is the profile ID! + sprintf( VObjectDesc.ImageFile, "FACES\\%02d.sti", iFaceFileID ); + + if ( gCamoFace[usMercProfileID].gCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\WoodCamo\\%02d.sti", iFaceFileID ); + } + else if ( gCamoFace[usMercProfileID].gUrbanCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\UrbanCamo\\%02d.sti", iFaceFileID ); + } + else if ( gCamoFace[usMercProfileID].gDesertCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\DesertCamo\\%02d.sti", iFaceFileID ); + } + else if ( gCamoFace[usMercProfileID].gSnowCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\SnowCamo\\%02d.sti", iFaceFileID ); + } + + if (!FileExists(VObjectDesc.ImageFile)) + sprintf( VObjectDesc.ImageFile, "FACES\\%02d.sti", iFaceFileID ); + } + else + { + + sprintf( VObjectDesc.ImageFile, "FACES\\%03d.sti", iFaceFileID ); + + if ( gCamoFace[usMercProfileID].gCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\Woodcamo\\%03d.sti", iFaceFileID ); + } + else if ( gCamoFace[usMercProfileID].gUrbanCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\UrbanCamo\\%03d.sti", iFaceFileID ); + } + else if ( gCamoFace[usMercProfileID].gDesertCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\DesertCamo\\%03d.sti", iFaceFileID ); + } + else if ( gCamoFace[usMercProfileID].gSnowCamoface == TRUE ) + { + sprintf( VObjectDesc.ImageFile, "FACES\\SnowCamo\\%03d.sti", iFaceFileID ); + } + + if (!FileExists(VObjectDesc.ImageFile)) + sprintf( VObjectDesc.ImageFile, "FACES\\%03d.sti", iFaceFileID ); + + } } - else + else if (gGameExternalOptions.fShowCamouflageFaces == FALSE ) { - sprintf( VObjectDesc.ImageFile, "FACES\\%03d.sti", iFaceFileID ); + if( iFaceFileID < 100 ) + { + // The filename is the profile ID! + sprintf( VObjectDesc.ImageFile, "FACES\\%02d.sti", iFaceFileID ); + } + else + { + sprintf( VObjectDesc.ImageFile, "FACES\\%03d.sti", iFaceFileID ); + } } } @@ -507,50 +494,21 @@ void GetFaceRelativeCoordinates( FACETYPE *pFace, UINT16 *pusEyesX, UINT16 *pusE usMouthY = gMercProfiles[ usMercProfileID ].usMouthY; usMouthX = gMercProfiles[ usMercProfileID ].usMouthX; - //if( usMercProfileID == TEX && gMercProfiles[ TEX ].bSkillTrait2 == CAMOUFLAGED ) - //{ - // usEyesX = 13; - // usEyesY = 34; - // usMouthX = 13; - // usMouthY = 55; - //} - // Use some other values for x,y, base on if we are a RPC! if ( !( pFace->uiFlags & FACE_BIGFACE ) ||( pFace->uiFlags & FACE_FORCE_SMALL )) { - if (usMercProfileID == TEX) - { - // 3, 6, 3, 23, // Tex ( 64 ) - usEyesX = 3; - usEyesY = 6; - usMouthX = 3; - usMouthY = 23; - } - else if (usMercProfileID == BIGGENS) - { - // 5, 6, 5, 25, // Biggens ( 61 ) - usEyesX = 5; - usEyesY = 6; - usMouthX = 5; - usMouthY = 25; - - } - // Are we a recruited merc? .. or small? - else if( ( gMercProfiles[ usMercProfileID ].ubMiscFlags & ( PROFILE_MISC_FLAG_RECRUITED | PROFILE_MISC_FLAG_EPCACTIVE ) ) ||( pFace->uiFlags & FACE_FORCE_SMALL ) ) - { - // Loop through all values of availible merc IDs to find ours! - for ( cnt = 0; cnt < ubRPCNumSmallFaceValues; cnt++ ) - { - // We've found one! - if ( gubRPCSmallFaceProfileNum[ cnt ] == usMercProfileID ) - { - usEyesX = gRPCSmallFaceValues[ cnt ].bEyesX; - usEyesY = gRPCSmallFaceValues[ cnt ].bEyesY; - usMouthY = gRPCSmallFaceValues[ cnt ].bMouthY; - usMouthX = gRPCSmallFaceValues[ cnt ].bMouthX; - } - } - + // Loop through all values of availible merc IDs to find ours! + for ( cnt = 0; cnt < ubRPCNumSmallFaceValues; cnt++ ) + { + // We've found one! + if (gRPCSmallFaceValues[ cnt ].FaceIndex == usMercProfileID && + gRPCSmallFaceValues[ cnt ].uiIndex != 65535) + { + usEyesX = gRPCSmallFaceValues[ cnt ].bEyesX; + usEyesY = gRPCSmallFaceValues[ cnt ].bEyesY; + usMouthY = gRPCSmallFaceValues[ cnt ].bMouthY; + usMouthX = gRPCSmallFaceValues[ cnt ].bMouthX; + } } } @@ -558,7 +516,6 @@ void GetFaceRelativeCoordinates( FACETYPE *pFace, UINT16 *pusEyesX, UINT16 *pusE (*pusEyesY) = usEyesY; (*pusMouthX) = usMouthX; (*pusMouthY) = usMouthY; - } @@ -1195,6 +1152,88 @@ BOOLEAN RenderAutoFaceFromSoldier( UINT8 ubSoldierID ) return( RenderAutoFace( MercPtrs[ ubSoldierID ]->iFaceIndex ) ); } +//---------------------------------------LEGION------------------------------- + +void GetXYForIconPlacement_legion( FACETYPE *pFace, UINT16 ubIndex, INT16 sFaceX, INT16 sFaceY, INT16 *psX, INT16 *psY ) +{ + INT16 sX, sY; + UINT16 usWidth, usHeight; + ETRLEObject *pTrav; + HVOBJECT hVObject; + + // Get height, width of icon... + GetVideoObject( &hVObject, guiPORTRAITICONS_NV ); + pTrav = &(hVObject->pETRLEObject[ ubIndex ] ); + usHeight = pTrav->usHeight; + usWidth = pTrav->usWidth; + + sX = sFaceX + pFace->usFaceWidth - usWidth - 1; + sY = sFaceY + pFace->usFaceHeight - usHeight - 1; + + *psX = sX; + *psY = sY; +} + +void GetXYForRightIconPlacement_legion_NV( FACETYPE *pFace, UINT16 ubIndex, INT16 sFaceX, INT16 sFaceY, INT16 *psX, INT16 *psY, INT8 bNumIcons ) +{ + INT16 sX, sY; + UINT16 usWidth, usHeight; + ETRLEObject *pTrav; + HVOBJECT hVObject; + + // Get height, width of icon... + GetVideoObject( &hVObject, guiPORTRAITICONS_NV ); + pTrav = &(hVObject->pETRLEObject[ ubIndex ] ); + usHeight = pTrav->usHeight; + usWidth = pTrav->usWidth; + + sX = sFaceX + ( usWidth * bNumIcons ) + 1; + sY = sFaceY + pFace->usFaceHeight - usHeight - 1; + + *psX = sX; + *psY = sY; +} +void DoRightIcon_legion_NV( UINT32 uiRenderBuffer, FACETYPE *pFace, INT16 sFaceX, INT16 sFaceY, INT8 bNumIcons, UINT8 sIconIndex ) +{ + INT16 sIconX, sIconY; + + GetXYForRightIconPlacement_legion_NV( pFace, sIconIndex, sFaceX, sFaceY, &sIconX, &sIconY, bNumIcons ); + BltVideoObjectFromIndex( uiRenderBuffer, guiPORTRAITICONS_NV, sIconIndex, sIconX, sIconY, VO_BLT_SRCTRANSPARENCY, NULL ); + +} + +void GetXYForRightIconPlacement_legion_GAS_MASK( FACETYPE *pFace, UINT16 ubIndex, INT16 sFaceX, INT16 sFaceY, INT16 *psX, INT16 *psY, INT8 bNumIcons ) +{ + INT16 sX, sY; + UINT16 usWidth, usHeight; + ETRLEObject *pTrav; + HVOBJECT hVObject; + + // Get height, width of icon... + GetVideoObject( &hVObject, guiPORTRAITICONS_GAS_MASK ); + pTrav = &(hVObject->pETRLEObject[ ubIndex ] ); + usHeight = pTrav->usHeight; + usWidth = pTrav->usWidth; + + sX = sFaceX + ( usWidth * bNumIcons ) + 1; + sY = sFaceY + pFace->usFaceHeight - usHeight - 1; + + *psX = sX; + *psY = sY; +} +void DoRightIcon_legion_GAS_MASK( UINT32 uiRenderBuffer, FACETYPE *pFace, INT16 sFaceX, INT16 sFaceY, INT8 bNumIcons, UINT8 sIconIndex ) +{ + INT16 sIconX, sIconY; + + // Find X, y for placement + + GetXYForRightIconPlacement_legion_GAS_MASK( pFace, sIconIndex, sFaceX, sFaceY, &sIconX, &sIconY, bNumIcons ); + BltVideoObjectFromIndex( uiRenderBuffer, guiPORTRAITICONS_GAS_MASK, sIconIndex, sIconX, sIconY, VO_BLT_SRCTRANSPARENCY, NULL ); + +} +//---------------------------------------------------------------- + + void GetXYForIconPlacement( FACETYPE *pFace, UINT16 ubIndex, INT16 sFaceX, INT16 sFaceY, INT16 *psX, INT16 *psY ) { INT16 sX, sY; @@ -1268,6 +1307,14 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE UINT8 *pDestBuf; UINT16 usLineColor; INT8 bNumRightIcons = 0; + + BOOLEAN fDoIcon_legion = FALSE; //legion + INT16 sIconIndex_legion =-1; //legion + INT8 bNumRightIcons_legion = 0; + BOOLEAN MASK = FALSE; //legion + UINT32 uiFaceItemOne=0; + UINT32 uiFaceItemTwo=0; + UINT8 ubFaceItemsCombined=0; // If we are using an extern buffer... if ( fUseExternBuffer ) @@ -1428,6 +1475,310 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE fDoIcon = TRUE; } + + +//------------------------------------Legion 2 by jazz-------------------------------- + // rewritten by silversurfer + // this section chooses the icons for face gear if the ini setting "SHOW_TACTICAL_FACE_ICONS" is TRUE + // and the merc actually wears something to be shown + if (gGameExternalOptions.fShowTacticalFaceIcons == TRUE && MercPtrs[ pFace->ubSoldierID ]->stats.bLife > 0 && + ( MercPtrs[ pFace->ubSoldierID ]->inv[HEAD1POS].usItem + MercPtrs[ pFace->ubSoldierID ]->inv[HEAD2POS].usItem ) > 0 ) + { + uiFaceItemOne=MercPtrs[ pFace->ubSoldierID ]->inv[HEAD1POS].usItem; + uiFaceItemTwo=MercPtrs[ pFace->ubSoldierID ]->inv[HEAD2POS].usItem; + + // check first face slot + if ( uiFaceItemOne != NONE ) + { + switch( uiFaceItemOne ) + { + // gas mask + case GASMASK: + uiFaceItemOne = 1; + break; + // NV goggles + case 211: + case 246: + case 1024: + case 1025: + uiFaceItemOne = 2; + break; + // sun goggles + case 212: + uiFaceItemOne = 3; + break; + // extended ear + case 210: + uiFaceItemOne = 4; + break; + default: + uiFaceItemOne = 0; + break; + } + } + + // check second face slot + if ( uiFaceItemTwo != NONE ) + { + switch( uiFaceItemTwo ) + { + // gas mask + case GASMASK: + uiFaceItemTwo = 21; + break; + // NV goggles + case 211: + case 246: + case 1024: + case 1025: + uiFaceItemTwo = 42; + break; + // sun goggles + case 212: + uiFaceItemTwo = 63; + break; + // extended ear + case 210: + uiFaceItemTwo = 84; + break; + default: + uiFaceItemTwo = 0; + break; + } + } + + // Now select the correct icon. This uses a matrix from uiFaceOneItem and uiFaceTwoItem (simple addition) + // the numbers on the outer border are used if that is the only item worn in that slot + // + // 21 42 63 84 + // face slot 1 \ slot 2 gas mask | NV goggles | sun goggles | extended ear + // 1 gas mask -- 43 64 85 + // 2 NV goggles 23 -- -- 86 + // 3 sun goggles 24 -- -- 87 + // 4 extended ear 25 46 67 -- + // + // this matrix leaves room for expansion + ubFaceItemsCombined = uiFaceItemOne + uiFaceItemTwo; + + switch( ubFaceItemsCombined ) + { + // gas mask only + case 1: + case 21: + sIconIndex = 9; + fDoIcon = TRUE; + break; + // NV goggles only + case 2: + case 42: + sIconIndex = 10; + fDoIcon = TRUE; + break; + // sun goggles only + case 3: + case 63: + sIconIndex = 15; + fDoIcon = TRUE; + break; + // extended ear only + case 4: + case 84: + sIconIndex = 12; + fDoIcon = TRUE; + break; + // gas mask + NV goggles + case 23: + case 43: + sIconIndex = 11; + fDoIcon = TRUE; + break; + // gas mask + sun goggles + case 24: + case 64: + sIconIndex = 16; + fDoIcon = TRUE; + break; + // gas mask + extended ear + case 25: + case 85: + sIconIndex = 13; + fDoIcon = TRUE; + break; + // NV goggles + extended ear + case 46: + case 86: + sIconIndex = 14; + fDoIcon = TRUE; + break; + // sun goggles + extended ear + case 67: + case 87: + sIconIndex = 18; + fDoIcon = TRUE; + break; + default: + break; + } + } + + // this section chooses the pictures for gas mask and NV goggles if the ini setting "SHOW_TACTICAL_FACE_GEAR" is TRUE + // and the merc actually wears something to be shown + if (gGameExternalOptions.fShowTacticalFaceGear == TRUE && MercPtrs[ pFace->ubSoldierID ]->stats.bLife > 0 && + ( MercPtrs[ pFace->ubSoldierID ]->inv[HEAD1POS].usItem + MercPtrs[ pFace->ubSoldierID ]->inv[HEAD2POS].usItem ) > 0 && + // dirty hack for IMPs because they don't have pictures for face gear + ( MercPtrs[ pFace->ubSoldierID ]->ubProfile < 51 || MercPtrs[ pFace->ubSoldierID ]->ubProfile > 56 )) + { + // WANNE: Removed the limitation + // silversurfer: don't overwrite icons if they shall be shown! + //if ( !gGameExternalOptions.fShowTacticalFaceIcons ) + { + uiFaceItemOne=MercPtrs[ pFace->ubSoldierID ]->inv[HEAD1POS].usItem; + uiFaceItemTwo=MercPtrs[ pFace->ubSoldierID ]->inv[HEAD2POS].usItem; + + // check first face slot + if ( uiFaceItemOne != NONE ) + { + switch( uiFaceItemOne ) + { + // gas mask + case GASMASK: + uiFaceItemOne = 1; + break; + // NV goggles + case 211: + case 246: + case 1024: + case 1025: + uiFaceItemOne = 2; + break; + default: + uiFaceItemOne = 0; + break; + } + } + + // check second face slot + if ( uiFaceItemTwo != NONE ) + { + switch( uiFaceItemTwo ) + { + // gas mask + case GASMASK: + uiFaceItemTwo = 21; + break; + // NV goggles + case 211: + case 246: + case 1024: + case 1025: + uiFaceItemTwo = 42; + break; + default: + uiFaceItemTwo = 0; + break; + } + } + + // Now select the correct picture. This uses a matrix from uiFaceOneItem and uiFaceTwoItem (simple addition) + // the numbers on the outer border are used if that is the only item worn in that slot + // + // 21 42 63 84 + // face slot 1 \ slot 2 gas mask | NV goggles | sun goggles | extended ear + // 1 gas mask -- 43 64 85 + // 2 NV goggles 23 -- -- 86 + // 3 sun goggles 24 -- -- 87 + // 4 extended ear 25 46 67 -- + // + // this matrix leaves room for expansion + // we only need a few of the matrix' values this time because we only show gas mask or NV goggles pictures + ubFaceItemsCombined = uiFaceItemOne + uiFaceItemTwo; + } + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + // silversurfer: we don't want to display icons for gas mask or NV goggles because you can actually see the merc wearing the gear + // in case of gas mask together with NV we display the picture of the item in face slot 1 and the icon of the item + // in face slot 2 (if icons are allowed) + switch( ubFaceItemsCombined ) + { + // gas mask only + case 1: + case 21: + DoRightIcon_legion_GAS_MASK( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + //fDoIcon = FALSE; + + break; + // NV goggles only + case 2: + case 42: + DoRightIcon_legion_NV( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + //fDoIcon = FALSE; + + break; + // NV goggles + gas mask + case 23: + DoRightIcon_legion_NV( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + /*if ( gGameExternalOptions.fShowTacticalFaceIcons ) + { + sIconIndex = 9; + fDoIcon = TRUE; + }*/ + + break; + // gas mask + NV goggles + case 43: + DoRightIcon_legion_GAS_MASK( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + /*if ( gGameExternalOptions.fShowTacticalFaceIcons ) + { + sIconIndex = 10; + fDoIcon = TRUE; + }*/ + + break; + // gas mask + sun goggles + case 24: + case 64: + DoRightIcon_legion_GAS_MASK( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + //sIconIndex = 15; + //fDoIcon = TRUE; + + break; + // gas mask + extended ear + case 25: + case 85: + DoRightIcon_legion_GAS_MASK( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + //sIconIndex = 12; + //fDoIcon = TRUE; + + break; + // NV goggles + extended ear + case 46: + case 86: + DoRightIcon_legion_NV( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons_legion, MercPtrs[ pFace->ubSoldierID ]->ubProfile ); + + // WANNE: Removed silversurfers limitation, because it is too complex for the players :) + //sIconIndex = 12; + //fDoIcon = TRUE; + + break; + default: + break; + } + } + + //------------------------------------end of tactical face gear----------------------------- + // If blind... if ( MercPtrs[ pFace->ubSoldierID ]->bBlindedCounter > 0 ) { diff --git a/Tactical/Handle Doors.cpp b/Tactical/Handle Doors.cpp index d963c0de..72a0578f 100644 --- a/Tactical/Handle Doors.cpp +++ b/Tactical/Handle Doors.cpp @@ -338,16 +338,19 @@ void InteractWithOpenableStruct( SOLDIERTYPE *pSoldier, STRUCTURE *pStructure, U if ( pDoor ) { if ( DoTrapCheckOnStartingMenu( pSoldier, pDoor ) ) - { - fTrapsFound = TRUE; - } + { + fTrapsFound = TRUE; + } } // Pull Up Menu - if ( !fTrapsFound ) - { - InitDoorOpenMenu( pSoldier, pStructure, ubDirection, TRUE ); - } + if ( !fTrapsFound ) + { + // HEADROCK HAM 4: Why not just close the object? Why do we need a menu if there's only one option on it (CLOSE)? + // P.S. I don't think it's even possible for opened structures to be trapped to begin with. + //InitDoorOpenMenu( pSoldier, pStructure, ubDirection, TRUE ); + pSoldier->ChangeSoldierState( GetAnimStateForInteraction( pSoldier, fDoor, CLOSE_DOOR ), 0, FALSE ); + } } else { @@ -475,7 +478,7 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p if ( pStructure->fFlags & STRUCTURE_OPEN ) { // Set costs for these - sAPCost = APBPConstants[AP_OPEN_DOOR]; + sAPCost = GetAPsToOpenDoor( pSoldier ); // SANDRO sBPCost = APBPConstants[BP_OPEN_DOOR]; fHandleDoor = TRUE; @@ -500,7 +503,7 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p // Set costs for these // Set AP costs to that of opening a door - sAPCost = APBPConstants[AP_OPEN_DOOR]; + sAPCost = GetAPsToOpenDoor( pSoldier ); // SANDRO sBPCost = APBPConstants[BP_OPEN_DOOR]; pSoldier->ChangeSoldierState( GetAnimStateForInteraction( pSoldier, fDoor, END_OPEN_DOOR ), 0, FALSE ); @@ -584,7 +587,7 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p if ( pDoor == NULL ) { // Set costs for these - sAPCost = APBPConstants[AP_OPEN_DOOR]; + sAPCost = GetAPsToOpenDoor( pSoldier ); // SANDRO sBPCost = APBPConstants[BP_OPEN_DOOR]; // Open if it's not locked.... @@ -689,7 +692,7 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p case HANDLE_DOOR_EXPLODE: // Set costs for these - sAPCost = APBPConstants[AP_EXPLODE_DOOR]; + sAPCost = GetAPsToBombDoor( pSoldier ); // SANDRO sBPCost = APBPConstants[BP_EXPLODE_DOOR]; if ( pDoor == NULL ) @@ -717,7 +720,7 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p case HANDLE_DOOR_LOCKPICK: // Set costs for these - sAPCost = APBPConstants[AP_PICKLOCK]; + sAPCost = GetAPsToPicklock( pSoldier ); // SANDRO sBPCost = APBPConstants[BP_PICKLOCK]; // Attempt to pick lock @@ -834,7 +837,7 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p case HANDLE_DOOR_UNTRAP: // Set costs for these - sAPCost = APBPConstants[AP_UNTRAP_DOOR]; + sAPCost = GetAPsToUntrapDoor( pSoldier ); // SANDRO sBPCost = APBPConstants[BP_UNTRAP_DOOR]; // OK, if we have no lock, show that! @@ -931,7 +934,8 @@ BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT32 sGridNo, STRUCTURE *p else { // Set costs for these - sAPCost = APBPConstants[AP_OPEN_DOOR]; + // SANDRO - changed this + sAPCost = GetAPsToOpenDoor( pSoldier ); sBPCost = APBPConstants[BP_OPEN_DOOR]; // Open if it's not locked.... diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index 7d2cd9db..3d1f9597 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -61,6 +61,9 @@ #include "end game.h" #include "interface control.h" #include "Map Screen Interface Map Inventory.h" + // added by SANDRO + #include "Game Clock.h" + #include "Morale.h" #endif #define NUM_ITEMS_LISTED 8 @@ -437,26 +440,28 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa // If this is a player guy, show message about no APS if ( EnoughPoints( pSoldier, sAPCost, 0, fFromUI ) ) { - if ( (pSoldier->ubProfile != NO_PROFILE) && (gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == PSYCHO) ) + if ( (pSoldier->ubProfile != NO_PROFILE) && (gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO) ) { // psychos might possibly switch to burst if they can // Changed by ADB, rev 1513 //if ( !pSoldier->bDoBurst && IsGunBurstCapable( pSoldier, HANDPOS, FALSE ) ) - if ( !pSoldier->bDoBurst && IsGunBurstCapable( &pSoldier->inv[HANDPOS], FALSE, pSoldier ) ) + // SANDRO - messed this a little.. decrease morale a bit when we would like to go psycho, + // but have not a gun capable for it + if ( PreRandom( 3 + pSoldier->aiData.bAimTime ) == 0 && !pSoldier->bDoBurst ) { - // chance of firing burst if we have points... chance decreasing when ordered to do aimed shot - - // temporarily set burst to true to calculate action points - pSoldier->bDoBurst = TRUE; - sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, TRUE, 0 ); - // reset burst mode to false (which is what it was at originally) - pSoldier->bDoBurst = FALSE; - - if ( EnoughPoints( pSoldier, sAPCost, 0, FALSE ) ) + if ( IsGunBurstCapable( &pSoldier->inv[HANDPOS], FALSE, pSoldier ) ) { - // we have enough points to do this burst, roll the dice and see if we want to change - if ( Random( 3 + pSoldier->aiData.bAimTime ) == 0 ) + // chance of firing burst if we have points... chance decreasing when ordered to do aimed shot + + // temporarily set burst to true to calculate action points + pSoldier->bDoBurst = TRUE; + sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, TRUE, 0 ); + // reset burst mode to false (which is what it was at originally) + pSoldier->bDoBurst = FALSE; + + if ( EnoughPoints( pSoldier, sAPCost, 0, FALSE ) ) { + // we have enough points to do this burst, roll the dice and see if we want to change pSoldier->DoMercBattleSound( BATTLE_SOUND_LAUGH1 ); pSoldier->bDoBurst = TRUE; pSoldier->bWeaponMode = WM_BURST; @@ -465,7 +470,12 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 26 ], pSoldier->name ); } } - + else if ( !IsGunAutofireCapable( &pSoldier->inv[HANDPOS] ) ) + { + // reduce morale for we are using a gun without burst or autofire and cannot go psycho + //HandleMoraleEventForSoldier( pSoldier, MORALE_PSYCHO_UNABLE_TO_PSYCHO ); + HandleMoraleEvent( pSoldier, MORALE_PSYCHO_UNABLE_TO_PSYCHO, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ); + } } } @@ -480,7 +490,19 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa //Rounding down resulted in division by zero and caused a crash. UINT32 diceSides = RAND_MAX / ( max(10,pSoldier->stats.bMarksmanship) / 10) ; - DOUBLE avgAPadded = max(((400.0f-2.0f*pSoldier->stats.bAgility))*(63.0f-5.0f*(pSoldier->stats.bExpLevel+2.0f*NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS )))/2700.0f,1); //Important! don't make this zero, the formulae don't like it. + DOUBLE avgAPadded; + // SANDRO - Slightly changed this formula to make the auto weapons trait little more needed if new traits activated - + if( gGameOptions.fNewTraitSystem ) + { + // also include possible squadleader bonus + UINT8 uiEffExpLev = min( 10, (pSoldier->stats.bExpLevel + (gSkillTraitValues.ubSLEffectiveLevelInRadius * GetSquadleadersCountInVicinity( pSoldier, TRUE, FALSE )))); + avgAPadded = max(((400.0f-2.0f*pSoldier->stats.bDexterity))*(90.0f-5.0f*(uiEffExpLev+gSkillTraitValues.ubAWUnwantedBulletsReduction*NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/2700.0f,1); //Important! don't make this zero, the formulae don't like it. + } + else + { + avgAPadded = max(((400.0f-2.0f*pSoldier->stats.bAgility))*(63.0f-5.0f*(pSoldier->stats.bExpLevel+2.0f*NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT )))/2700.0f,1); //Important! don't make this zero, the formulae don't like it. + } + UINT32 chanceToMisfire = (UINT32)(((DOUBLE)diceSides*(2.0f*avgAPadded+1.0f-sqrt(4.0f*avgAPadded+1.0f)))/(2.0f*avgAPadded)); //derive the chace to misfire from the desired average AP overspent, derived suing UINT32 chanceToMisfireDry = (UINT32)(((DOUBLE)diceSides*(avgAPadded+1.0f-sqrt(2.0f*avgAPadded+1.0f)))/(avgAPadded)); //chance to misfire if weapon is dry. Designed to waste avgAPadded/2 APs //soldiers get better at controlling bursts with levels, and reflex time (agility) @@ -491,10 +513,13 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa //UINT32 startAPcost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, TRUE, 0 ); UINT32 roll; - if((pSoldier->ubProfile != NO_PROFILE) && (gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == PSYCHO) && Random(100) < 20) + // SANDRO - changed Random to PreRandom to avoid save-load mania + if((pSoldier->ubProfile != NO_PROFILE) && (gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO) && PreRandom(100) < 20) { chanceToMisfire = diceSides; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 26 ], pSoldier->name ); + + pSoldier->DoMercBattleSound( BATTLE_SOUND_LAUGH1 ); // Added the laugh sound when going Psycho on autofire - SANDRO } chanceToMisfire = __min(diceSides-1, chanceToMisfire); //cap the misfire chance, no-one has reflexes this bad @@ -503,11 +528,17 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa chanceToMisfireDry = __min(diceSides-1, chanceToMisfireDry); //cap the misfire chance, no-one has reflexes this bad chanceToMisfireDry = __max(1, chanceToMisfireDry); //cap the misfire chance, no-one has reflexes this good + //CHRISL: Since LMGs can only use autofire, give them slightly better control over misfire + if(Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponClass == MGCLASS && Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType == GUN_LMG){ + chanceToMisfire = (INT32)(chanceToMisfire * .75f); + chanceToMisfireDry = (INT32)(chanceToMisfireDry * .75f); + } + //roll dice for each AP to see if we failed to stop firing do { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"HandleItem: auto fire - Rolling dice"); - roll = Random(diceSides); + roll = PreRandom(diceSides); // changed Random to PreRandom - SANDRO //roll = rand();//Random(diceSides); //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Rolled %d vs %d", roll, ((pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire)?chanceToMisfire:chanceToMisfireDry)); @@ -540,7 +571,7 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa // 1 round else { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 63 ], pSoldier->name, __min(pSoldier->bDoAutofire,pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft) - startAuto ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 63 ], pSoldier->name ); // SANDRO - no need for attaching the number if only one round is shot } } } @@ -1457,7 +1488,16 @@ void HandleSoldierDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ) // EXPLOSIVES GAIN (25): Place a bomb, or buried and armed a mine StatChange( pSoldier, EXPLODEAMT, 25, FALSE ); - pSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( 10, ( EffectiveExplosive( pSoldier ) / 20) + (EffectiveExpLevel( pSoldier ) / 3) ); + // SANDRO - STOMP traits - Demolitions bonus to trap level + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT )) + { + // +5 trap level for Demolitions trait + pSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( max( 10, (8 + gSkillTraitValues.ubDEPlacedBombLevelBonus)), (( EffectiveExplosive( pSoldier ) / 20) + (EffectiveExpLevel( pSoldier ) / 3) + gSkillTraitValues.ubDEPlacedBombLevelBonus) ); + } + else + { + pSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( 10, ( EffectiveExplosive( pSoldier ) / 20) + (EffectiveExpLevel( pSoldier ) / 3) ); + } pSoldier->inv[ HANDPOS ][0]->data.misc.ubBombOwner = pSoldier->ubID + 2; // we now know there is something nasty here @@ -1538,11 +1578,27 @@ void HandleSoldierThrowItem( SOLDIERTYPE *pSoldier, INT32 sGridNo ) // Draw item depending on distance from buddy if ( GetRangeFromGridNoDiff( sGridNo, pSoldier->sGridNo ) < MIN_LOB_RANGE ) { - pSoldier->usPendingAnimation = LOB_ITEM; + + //ddd - + if( (pSoldier->pThrowParams->ubActionCode == THROW_ARM_ITEM) && + ( (pSoldier->ubBodyType == BIGMALE) || (pSoldier->ubBodyType == REGMALE) ) ) + pSoldier->usPendingAnimation = LOB_GRENADE_STANCE; + else + pSoldier->usPendingAnimation = LOB_ITEM; + } else - { - pSoldier->usPendingAnimation = THROW_ITEM; + { //ddd - + //INT32 uiItemClass; // . ? + // uiItemClass= Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass; + //if( (uiItemClass == IC_GRENADE) && + + + if( (pSoldier->pThrowParams->ubActionCode == THROW_ARM_ITEM) && + ( (pSoldier->ubBodyType == BIGMALE) || (pSoldier->ubBodyType == REGMALE) ) ) + pSoldier->usPendingAnimation = THROW_GRENADE_STANCE; + else + pSoldier->usPendingAnimation = THROW_ITEM; } } @@ -1913,7 +1969,7 @@ void SoldierGetItemFromWorld( SOLDIERTYPE *pSoldier, INT32 iItemIndex, INT32 sGr if ( fShouldSayCoolQuote && pSoldier->bTeam == gbPlayerNum ) { // Do we have this quote..? - if ( QuoteExp_GotGunOrUsedGun[ pSoldier->ubProfile ] == QUOTE_FOUND_SOMETHING_SPECIAL ) + if ( QuoteExp[ pSoldier->ubProfile ].QuoteExpGotGunOrUsedGun == QUOTE_FOUND_SOMETHING_SPECIAL ) { // Have we not said it today? if ( !( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_FOUND_SOMETHING_NICE ) ) @@ -2007,7 +2063,7 @@ void HandleSoldierPickupItem( SOLDIERTYPE *pSoldier, INT32 iItemIndex, INT32 sGr wchar_t string2[20]; ptr = wcscat(buffer, string); - _ltow(APBPConstants[AP_DISARM_MINE], string2, 10); + _ltow(GetAPsToDisarmMine( pSoldier ), string2, 10); // SANDRO ptr = wcscat(buffer, string2); string = L"AP)"; ptr = wcscat(buffer, string); @@ -3995,7 +4051,7 @@ void SoldierGiveItemFromAnimation( SOLDIERTYPE *pSoldier ) ubTargetMercID = (UINT8)pSoldier->aiData.uiPendingActionData4; // ATE: Deduct APs! - DeductPoints( pSoldier, APBPConstants[AP_PICKUP_ITEM], 0 ); + DeductPoints( pSoldier, GetBasicAPsToPickupItem( pSoldier ), 0 ); // SANDRO if ( VerifyGiveItem( pSoldier, &pTSoldier ) ) { @@ -4063,7 +4119,9 @@ void SoldierGiveItemFromAnimation( SOLDIERTYPE *pSoldier ) // Switch on target... // Are we a player dude.. ( target? ) - if ( ubProfile < FIRST_RPC || RPC_RECRUITED( pTSoldier ) || ubProfile >= GASTON ) + // if ( ubProfile < FIRST_RPC || RPC_RECRUITED( pTSoldier ) || ubProfile >= GASTON ) + //new profiles by Jazz + if ( ( gProfilesAIM[ubProfile].ProfilId == ubProfile || gProfilesMERC[ubProfile].ProfilId == ubProfile || gProfilesIMP[ubProfile].ProfilId == ubProfile ) || RPC_RECRUITED( pTSoldier ) ) { fToTargetPlayer = TRUE; } @@ -4314,7 +4372,17 @@ void BombMessageBoxCallBack( UINT8 ubExitValue ) if ( ArmBomb( &(gpTempSoldier->inv[HANDPOS]), ubExitValue ) ) { - gpTempSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( 10, ( EffectiveExplosive( gpTempSoldier ) / 20) + (EffectiveExpLevel( gpTempSoldier ) / 3) ); + // SANDRO - STOMP traits - Demolitions bonus to trap level + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( gpTempSoldier, DEMOLITIONS_NT )) + { + // increase trap level for Demolitions trait + gpTempSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( max( 10, (8 + gSkillTraitValues.ubDEPlacedBombLevelBonus)), (( EffectiveExplosive( gpTempSoldier ) / 20) + (EffectiveExpLevel( gpTempSoldier ) / 3) + gSkillTraitValues.ubDEPlacedBombLevelBonus) ); + } + else + { + gpTempSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( 10, ( EffectiveExplosive( gpTempSoldier ) / 20) + (EffectiveExpLevel( gpTempSoldier ) / 3) ); + } + // HACK IMMINENT! // value of 1 is stored in maps for SIDE of bomb owner... when we want to use IDs! // so we add 2 to all owner IDs passed through here and subtract 2 later @@ -4548,8 +4616,9 @@ void BoobyTrapMessageBoxCallBack( UINT8 ubExitValue ) //CHRISL: first things first. If we're in combat, we need to spend some APs to disarm the device if((gTacticalStatus.uiFlags & INCOMBAT) || (gTacticalStatus.fEnemyInSector)) { - if(EnoughPoints(gpBoobyTrapSoldier, APBPConstants[AP_DISARM_MINE], APBPConstants[BP_DISARM_MINE], TRUE)) - DeductPoints(gpBoobyTrapSoldier, APBPConstants[AP_DISARM_MINE], APBPConstants[BP_DISARM_MINE]); + // SANDRO was here, AP_DISARM_MINE changed to GetAPsToDisarmMine + if(EnoughPoints(gpBoobyTrapSoldier, GetAPsToDisarmMine( gpBoobyTrapSoldier ), APBPConstants[BP_DISARM_MINE], TRUE)) + DeductPoints(gpBoobyTrapSoldier, GetAPsToDisarmMine( gpBoobyTrapSoldier ), APBPConstants[BP_DISARM_MINE]); else return; } @@ -4589,12 +4658,18 @@ void BoobyTrapMessageBoxCallBack( UINT8 ubExitValue ) { // disarmed our team's boobytrap! StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (UINT16) (4 * gbTrapDifficulty), FALSE ); + + // SANDRO - merc records - trap removal count (don't count our own traps) + gMercProfiles[ gpBoobyTrapSoldier->ubProfile ].records.usTrapsRemoved++; } } else { // disarmed a boobytrap! StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (UINT16) (6 * gbTrapDifficulty), FALSE ); + + // SANDRO - merc records - trap removal count + gMercProfiles[ gpBoobyTrapSoldier->ubProfile ].records.usTrapsRemoved++; } // have merc say this is good @@ -4632,7 +4707,7 @@ void BoobyTrapMessageBoxCallBack( UINT8 ubExitValue ) CreateItem( DETONATOR, gTempObject[0]->data.misc.bBombStatus, &TempAttachment ); } - if (ValidAttachment( TempAttachment.usItem , gTempObject.usItem )) + if (ValidAttachment( TempAttachment.usItem , &gTempObject )) { gTempObject.AttachObject(NULL, &TempAttachment, FALSE); } @@ -4747,6 +4822,10 @@ void BoobyTrapInMapScreenMessageBoxCallBack( UINT8 ubExitValue ) // disarmed a boobytrap! StatChange( gpBoobyTrapSoldier, EXPLODEAMT, (UINT16) (6 * gbTrapDifficulty), FALSE ); + // SANDRO - merc records - trap removal count + if ( gpBoobyTrapSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ gpBoobyTrapSoldier->ubProfile ].records.usTrapsRemoved++; + // have merc say this is good gpBoobyTrapSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); @@ -5467,7 +5546,7 @@ UINT8 StealItems(SOLDIERTYPE* pSoldier,SOLDIERTYPE* pOpponent, UINT8* ubIndexRet fStealItem = FALSE; pObject=&pOpponent->inv[i]; - if (pObject->exists() == true) + if ((pObject->exists() == true) && !(Item[pObject->usItem].defaultundroppable )) // CHECK! Undroppable items cannot be stolen - SANDRO { // Is the enemy collapsed if ( pOpponent->stats.bLife < OKLIFE || pOpponent->bCollapsed ) @@ -5591,6 +5670,7 @@ void SoldierStealItemFromSoldier( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, BOOLEAN fPickup; BOOLEAN fShouldSayCoolQuote = FALSE; BOOLEAN fDidSayCoolQuote = FALSE; + BOOLEAN fNotEnoughAPs = FALSE; // added by SANDRO // OK. CHECK IF WE ARE DOING ALL IN THIS POOL.... if ( iItemIndex == ITEM_PICKUP_ACTION_ALL || iItemIndex == ITEM_PICKUP_SELECTION ) @@ -5611,17 +5691,51 @@ void SoldierStealItemFromSoldier( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, cnt++; if ( fPickup ) { - // Make copy of item - gTempObject = pOpponent->inv[pTempItemPool->iItemIndex]; - if ( ItemIsCool( &gTempObject ) ) + //////////////////////////////////////////////////////////////////// + // SANDRO - added mechanism for APs needed to steal all items.. + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) { - fShouldSayCoolQuote = TRUE; + if (pSoldier->bActionPoints >= GetBasicAPsToPickupItem( pSoldier ) ) + { + DeductPoints( pSoldier, GetBasicAPsToPickupItem( pSoldier ), 0 ); + + // Make copy of item + gTempObject = pOpponent->inv[pTempItemPool->iItemIndex]; + if ( ItemIsCool( &gTempObject ) ) + { + fShouldSayCoolQuote = TRUE; + } + if ( !AutoPlaceObject( pSoldier, &gTempObject, TRUE ) ) + { + AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + } + DeleteObj(&pOpponent->inv[pTempItemPool->iItemIndex]); + + // add to merc records + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usItemsStolen++; + + } + else + { + fNotEnoughAPs = TRUE; + } } - if ( !AutoPlaceObject( pSoldier, &gTempObject, TRUE ) ) + else // original code { - AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + // Make copy of item + gTempObject = pOpponent->inv[pTempItemPool->iItemIndex]; + if ( ItemIsCool( &gTempObject ) ) + { + fShouldSayCoolQuote = TRUE; + } + if ( !AutoPlaceObject( pSoldier, &gTempObject, TRUE ) ) + { + AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + } + DeleteObj(&pOpponent->inv[pTempItemPool->iItemIndex]); } - DeleteObj(&pOpponent->inv[pTempItemPool->iItemIndex]); + //////////////////////////////////////////////////////////////////// } pTempItemPool = pTempItemPool->pNext; } @@ -5649,6 +5763,13 @@ void SoldierStealItemFromSoldier( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, { pSoldier->DoMercBattleSound( BATTLE_SOUND_GOTIT ); } + + // SANDRO - show a message, that we had insufficient APs to take all items + if ( fNotEnoughAPs && pSoldier->bTeam == gbPlayerNum && gGameExternalOptions.fEnhancedCloseCombatSystem) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_NOT_ENOUGH_APS_TO_STEAL_ALL], pSoldier->name ); + } + gpTempSoldier = pSoldier; gsTempGridNo = sGridNo; SetCustomizableTimerCallbackAndDelay( 1000, CheckForPickedOwnership, TRUE ); diff --git a/Tactical/Handle Items.h b/Tactical/Handle Items.h index 767b2118..f6d6f25f 100644 --- a/Tactical/Handle Items.h +++ b/Tactical/Handle Items.h @@ -54,15 +54,15 @@ typedef struct TAG_ITEM_POOL struct TAG_ITEM_POOL *pNext; struct TAG_ITEM_POOL *pPrev; - INT32 iItemIndex; - INT8 bVisible; - INT8 bFlashColor; - UINT32 uiTimerID; - INT32 sGridNo; - UINT8 ubLevel; - UINT16 usFlags; - INT8 bRenderZHeightAboveLevel; - LEVELNODE *pLevelNode; + INT32 iItemIndex; + INT8 bVisible; + INT8 bFlashColor; + UINT32 uiTimerID; + INT32 sGridNo; + UINT8 ubLevel; + UINT16 usFlags; + INT8 bRenderZHeightAboveLevel; + LEVELNODE *pLevelNode; } ITEM_POOL; diff --git a/Tactical/Handle UI Plan.cpp b/Tactical/Handle UI Plan.cpp index 2449ce28..81140b3e 100644 --- a/Tactical/Handle UI Plan.cpp +++ b/Tactical/Handle UI Plan.cpp @@ -67,7 +67,7 @@ BOOLEAN AddUIPlan( INT32 sGridNo, UINT8 ubPlanID ) // Adjust for running if we are not already running if ( gpUIPlannedSoldier->usUIMovementMode == RUNNING ) { - sAPCost += APBPConstants[AP_START_RUN_COST]; + sAPCost += GetAPsStartRun( gpUIPlannedSoldier ); // changed by SANDRO } if ( EnoughPoints( gpUIPlannedSoldier, sAPCost, 0, FALSE ) ) diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index eb57745b..ed827448 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -88,10 +88,21 @@ #include "Map Information.h" #include "Soldier Control.h" #include "DisplayCover.h" + //ddd + #include "aiinternals.h" + //#include "los.h" + //#include "structure wrap.h" + //#include "DisplayCover.h" + //ddd #endif #include "teamturns.h" +////////////////////////////////////////////////////////////////////////////// +// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne() +// On the bottom here, there are these functions made +////////////////////////////////////////////////////////////////////// + //extern BOOLEAN gfDisplayFullCountRingBurst; extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); @@ -231,6 +242,8 @@ INT16 gsTreeRevealYPos; // taken out of header to remove multiple symbol definitions (jonathanl) BOOLEAN gfUICtHBar; +// HEADROCK HAM 4: A new Struct to contain all CTH display data +CTHDISPLAY gCTHDisplay; // HEADROCK HAM B1/2: Created an array to hold CTH of different bullets for Burst/Auto CTH Bar. UINT8 gbCtH[ 10 ]; UINT8 gbCtHBurstCount; @@ -396,6 +409,10 @@ BOOLEAN gfUserTurnRegionActive = FALSE; BOOLEAN fRightButtonDown = FALSE; BOOLEAN fLeftButtonDown = FALSE; BOOLEAN fIgnoreLeftUp = FALSE; +///*** dddd +BOOLEAN fMiddleButtonDown = FALSE; +BOOLEAN fX1ButtonDown = FALSE; +BOOLEAN fX2ButtonDown = FALSE; BOOLEAN gUITargetReady = FALSE; BOOLEAN gUITargetShotWaiting = FALSE; @@ -477,6 +494,54 @@ void SetUIMouseCursor( ); void ClearEvent( UI_EVENT *pUIEvent ); UINT8 GetAdjustedAnimHeight( UINT8 ubAnimHeight, INT8 bChange ); + +//-------------------------Legion 2 okno----------------------------------------------------------- +void GetMercOknoDirection( UINT8 ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pfGoUp ) +{ + INT8 bNewDirection; + SOLDIERTYPE *pSoldier; + + *pfGoDown = FALSE; + *pfGoUp = FALSE; + + if ( !GetSoldier( &pSoldier, ubSoldierID ) ) + { + return; + } + + if ( pSoldier->pathing.bLevel == 0 && ( pSoldier->ubDirection == NORTH || pSoldier->ubDirection == EAST || pSoldier->ubDirection == SOUTH || pSoldier->ubDirection == WEST )) + { + if ( FindHeigherLevelOkno( pSoldier, pSoldier->sGridNo, pSoldier->ubDirection, &bNewDirection ) ) + { + *pfGoUp = TRUE; + } + } +} + +void GetMercFenceDirection( UINT8 ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pfGoUp ) +{ + INT8 bNewDirection; + SOLDIERTYPE *pSoldier; + + *pfGoDown = FALSE; + *pfGoUp = FALSE; + + if ( !GetSoldier( &pSoldier, ubSoldierID ) ) + { + return; + } + + if ( pSoldier->pathing.bLevel == 0 ) + { + if ( FindHeigherLevelFence( pSoldier, pSoldier->sGridNo, pSoldier->ubDirection, &bNewDirection ) ) + { + *pfGoUp = TRUE; + } + } +} +//---------------------------------------------------------------------------------- + + void PreventFromTheFreezingBug(SOLDIERTYPE* pSoldier) { gfUIInterfaceSetBusy = FALSE; @@ -1207,6 +1272,59 @@ UINT32 UIHandleEndTurn( UI_EVENT *pUIEvent ) SaveGame( SAVE__END_TURN_NUM, L"End Turn Auto Save" ); } + ////ddd + if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT ) ) + { +//UINT32 uiStartTime, uiEndTime; +//uiStartTime = GetJA2Clock(); + + + memset( gubWorldTileInLight, FALSE, sizeof( gubWorldTileInLight ) ); + memset( gubIsCorpseThere, FALSE, sizeof( gubIsCorpseThere ) ); + memset( gubMerkCanSeeThisTile, FALSE, sizeof( gubMerkCanSeeThisTile ) ); + // . WORLD_MAX .. ! !!! ;) + for(INT32 i=0; istats.bLife >= OKLIFE && tS->sGridNo != NOWHERE && tS->bInSector ) + { + //loop through all the gridnos that we are interested in + for (sYOffset = -30; sYOffset <= 30; sYOffset++) + for (sXOffset = -30; sXOffset <= 30; sXOffset++) + { + sGridNo = tS->sGridNo + sXOffset + (MAXCOL * sYOffset); + if ( sGridNo <= 0 || sGridNo >= WORLD_MAX ) continue; + //usSightLimit = tS->GetMaxDistanceVisible(sGridNo, FALSE, CALC_FROM_WANTED_DIR); + if(gubMerkCanSeeThisTile[sGridNo]==0) + gubMerkCanSeeThisTile[sGridNo]=//SoldierToVirtualSoldierLineOfSightTest( tS, sGridNo, FALSE, ANIM_STAND, TRUE, usSightLimit ); + SoldierToVirtualSoldierLineOfSightTest( tS, sGridNo, tS->pathing.bLevel, + ANIM_STAND, TRUE, CALC_FROM_WANTED_DIR); + + }//fo + }//if +///////////////////////////////////////////////////////////////////////////// +//uiEndTime = GetJA2Clock(); +//ScreenMsg( 144,0, L"t=%d",uiEndTime - uiStartTime ); +// + } + //ddd ** + // End our turn! if (is_server || !is_client) { @@ -2100,7 +2218,7 @@ UINT32 UIHandleMCycleMovement( UI_EVENT *pUIEvent ) else if ( pSoldier->usUIMovementMode == SWATTING ) { pSoldier->usUIMovementMode = CRAWLING; - if ( IsValidMovementMode( pSoldier, CRAWLING ) ) + if ( IsValidMovementMode( pSoldier, CRAWLING ) && IsValidStance(pSoldier, ANIM_PRONE) ) { fGoodMode = TRUE; } @@ -2567,6 +2685,30 @@ void AttackRequesterCallback( UINT8 bExitValue ) } } +// SANDRO - added function +void SurgeryRequesterCallback( UINT8 bExitValue ) +{ + if( bExitValue == MSG_BOX_RETURN_YES ) + { + //gpRequesterMerc->ubSurgeryApprovalMerc = gpRequesterTargetMerc->ubID; + gTacticalStatus.ubLastRequesterSurgeryTargetID = gpRequesterTargetMerc->ubID; + + UIHandleMercAttack( gpRequesterMerc , gpRequesterTargetMerc, gsRequesterGridNo ); + } + else if( bExitValue == MSG_BOX_RETURN_NO ) + { + gTacticalStatus.ubLastRequesterSurgeryTargetID = NOBODY; + + if (!gpRequesterTargetMerc->bBleeding && gpRequesterTargetMerc->stats.bLife >= OKLIFE) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_NO_NEED_FIRST_AID_STR ], gpRequesterTargetMerc->name ); + } + else + { + UIHandleMercAttack( gpRequesterMerc , gpRequesterTargetMerc, gsRequesterGridNo ); + } + } +} UINT32 UIHandleCAMercShoot( UI_EVENT *pUIEvent ) { @@ -2611,6 +2753,30 @@ UINT32 UIHandleCAMercShoot( UI_EVENT *pUIEvent ) DoMessageBox( MSG_BOX_BASIC_STYLE, zStr, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, AttackRequesterCallback, NULL ); } + //////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Should we ask if we really want to do the surgery? + else if (Item[ pSoldier->inv[ HANDPOS ].usItem ].medicalkit && (NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery) + && (pTSoldier->bTeam == OUR_TEAM || pTSoldier->bTeam == MILITIA_TEAM) + && (IS_MERC_BODY_TYPE( pTSoldier ) || IS_CIV_BODY_TYPE( pTSoldier )) + && gGameOptions.fNewTraitSystem && pTSoldier->iHealableInjury >= 100 + && pTSoldier->ubID != pSoldier->ubID && gTacticalStatus.ubLastRequesterSurgeryTargetID != pTSoldier->ubID ) + { + CHAR16 zStr[200]; + + gpRequesterMerc = pSoldier; + gpRequesterTargetMerc = pTSoldier; + gsRequesterGridNo = usMapPos; + + fDidRequester = TRUE; + + if (pTSoldier->bBleeding) + swprintf( zStr, New113Message[ MSG113_DO_WE_WANT_SURGERY_FIRST ], pTSoldier->name, (pTSoldier->iHealableInjury * (gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop * NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT )) / 10000) ); + else + swprintf( zStr, New113Message[ MSG113_DO_WE_WANT_SURGERY ], pTSoldier->name, (pTSoldier->iHealableInjury * (gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop * NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT )) / 10000) ); + + DoMessageBox( MSG_BOX_BASIC_STYLE, zStr, GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_YESNO, SurgeryRequesterCallback, NULL ); + } + //////////////////////////////////////////////////////////////////////////////////////////////// } if ( !fDidRequester ) @@ -3801,7 +3967,7 @@ INT8 DrawUIMovementPath( SOLDIERTYPE *pSoldier, INT32 usMapPos, UINT32 uiFlags ) { sActionGridNo = sIntTileGridNo; } - CalcInteractiveObjectAPs( sIntTileGridNo, pStructure, &sAPCost, &sBPCost ); + CalcInteractiveObjectAPs( pSoldier, sIntTileGridNo, pStructure, &sAPCost, &sBPCost ); // SANDRO - added argument //sAPCost += UIPlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, PLOT, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints); sAPCost += UIPlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints); @@ -4033,7 +4199,23 @@ INT8 DrawUIMovementPath( SOLDIERTYPE *pSoldier, INT32 usMapPos, UINT32 uiFlags ) { sActionGridNo = sAdjustedGridNo; } - sAPCost += APBPConstants[AP_STEAL_ITEM]; + + ///////////////////////////////////////////////////////////////////////////////////////// + // CHANGED BY SANDRO - REDUCE AP COST TO STEAL FOR MARTIAL ARTS AND HAND TO HAND NEW TRAITS + if (MercPtrs[ gusUIFullTargetID ]->bCollapsed && gGameExternalOptions.fEnhancedCloseCombatSystem) + { + sAPCost += (GetBasicAPsToPickupItem( pSoldier )); // stealing from collapsed soldiers is treated differently + } + else if ((HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT )) && ( gGameOptions.fNewTraitSystem )) + { + sAPCost += max( 1, (INT16)((APBPConstants[AP_STEAL_ITEM] * (100 - gSkillTraitValues.ubMAReducedAPsToSteal * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/ 100) + 0.5)); + } + else + { + sAPCost += APBPConstants[AP_STEAL_ITEM]; + } + ///////////////////////////////////////////////////////////////////////////////////////// + // CJC August 13 2002: take into account stance in AP prediction if (!(PTR_STANDING)) { @@ -4097,12 +4279,12 @@ INT8 DrawUIMovementPath( SOLDIERTYPE *pSoldier, INT32 usMapPos, UINT32 uiFlags ) sAPCost += UIPlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, fPlot, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints); if ( sAPCost != 0 ) { - sAPCost += APBPConstants[AP_PICKUP_ITEM]; + sAPCost += GetBasicAPsToPickupItem( pSoldier ); // SANDRO } } else { - sAPCost += APBPConstants[AP_PICKUP_ITEM]; + sAPCost += GetBasicAPsToPickupItem( pSoldier ); // SANDRO } if ( sActionGridNo != pSoldier->sGridNo ) @@ -4145,19 +4327,21 @@ INT16 APsToTurnAround(SOLDIERTYPE *pSoldier, INT16 sAdjustedGridNo) { if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_BREATH | ANIM_OK_CHARGE_AP_FOR_TURN | ANIM_FIREREADY ) && !fInitalMove && !pSoldier->flags.fDontChargeTurningAPs ) { - // Which position has the soldier? - switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) - { - case ANIM_STAND: - sAPCost += APBPConstants[AP_LOOK_STANDING]; - break; - case ANIM_CROUCH: - sAPCost += APBPConstants[AP_LOOK_CROUCHED]; - break; - case ANIM_PRONE: - sAPCost += APBPConstants[AP_LOOK_PRONE]; - break; - } + // SANDRO - hey, we have a function for this, why not to use it, huh? + sAPCost += GetAPsToLook( pSoldier ); + //// Which position has the soldier? + //switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) + //{ + //case ANIM_STAND: + // sAPCost += APBPConstants[AP_LOOK_STANDING]; + // break; + //case ANIM_CROUCH: + // sAPCost += APBPConstants[AP_LOOK_CROUCHED]; + // break; + //case ANIM_PRONE: + // sAPCost += APBPConstants[AP_LOOK_PRONE]; + // break; + //} } } @@ -4312,18 +4496,27 @@ BOOLEAN UIMouseOnValidAttackLocation( SOLDIERTYPE *pSoldier ) return( FALSE ); } - if ( pTSoldier->bBleeding == 0 && pTSoldier->stats.bLife != pTSoldier->stats.bLifeMax ) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 19 ], pTSoldier->name ); - return( FALSE ); - } - - if ( pTSoldier->bBleeding == 0 && pTSoldier->stats.bLife >= OKLIFE ) + // SANDRO - doctor with medical bag trying to do the surgery + if ((NUM_SKILL_TRAITS( pSoldier, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery) && Item[pSoldier->inv[ HANDPOS ].usItem].medicalkit && gGameOptions.fNewTraitSystem + && (pTSoldier->stats.bLife != pTSoldier->stats.bLifeMax) && (pTSoldier->iHealableInjury >= 100)) { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_NO_NEED_FIRST_AID_STR ], pTSoldier->name ); - return( FALSE ); + // should come a question first if you really want to do the surgery + return( TRUE ); } + else + { + if ( pTSoldier->bBleeding == 0 && pTSoldier->stats.bLife != pTSoldier->stats.bLifeMax ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 19 ], pTSoldier->name ); + return( FALSE ); + } + if ( pTSoldier->bBleeding == 0 && pTSoldier->stats.bLife >= OKLIFE ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_NO_NEED_FIRST_AID_STR ], pTSoldier->name ); + return( FALSE ); + } + } } return( TRUE ); @@ -4377,42 +4570,42 @@ BOOLEAN SoldierCanAffordNewStance( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance if((UsingNewInventorySystem() == true)) if(pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) bAP = bBP = 1; - bAP += APBPConstants[AP_CROUCH]; + bAP += GetAPsCrouch(pSoldier, FALSE); bBP += APBPConstants[BP_CROUCH]; break; case ANIM_CROUCH - ANIM_STAND: if((UsingNewInventorySystem() == true)) if(pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) bAP = bBP = 2; - bAP += APBPConstants[AP_CROUCH]; + bAP += GetAPsCrouch(pSoldier, FALSE); bBP += APBPConstants[BP_CROUCH]; break; case ANIM_STAND - ANIM_PRONE: if((UsingNewInventorySystem() == true)) if(pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) bAP = bBP = 2; - bAP += APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]; + bAP += GetAPsCrouch(pSoldier, FALSE) + GetAPsProne(pSoldier, FALSE); bBP += APBPConstants[BP_CROUCH] + APBPConstants[BP_PRONE]; break; case ANIM_PRONE - ANIM_STAND: if((UsingNewInventorySystem() == true)) if(pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) bAP = bBP = 4; - bAP += APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]; + bAP += GetAPsCrouch(pSoldier, FALSE) + GetAPsProne(pSoldier, FALSE); bBP += APBPConstants[BP_CROUCH] + APBPConstants[BP_PRONE]; break; case ANIM_CROUCH - ANIM_PRONE: if((UsingNewInventorySystem() == true)) if(pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) bAP = bBP = 1; - bAP += APBPConstants[AP_PRONE]; + bAP += GetAPsProne(pSoldier, FALSE); bBP += APBPConstants[BP_PRONE]; break; case ANIM_PRONE - ANIM_CROUCH: if((UsingNewInventorySystem() == true)) if(pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) bAP = bBP = 2; - bAP += APBPConstants[AP_PRONE]; + bAP += GetAPsProne(pSoldier, FALSE); bBP += APBPConstants[BP_PRONE]; break; @@ -4466,6 +4659,9 @@ void SetMovementModeCursor( SOLDIERTYPE *pSoldier ) break; case SWATTING: + ///ddd quick fix for losed cursor { + case SWATTING_WK: + ///ddd quick fix for losed cursor } guiNewUICursor = MOVE_SWAT_UICURSOR; break; @@ -5590,7 +5786,9 @@ BOOLEAN IsValidTalkableNPC( UINT8 ubSoldierID, BOOLEAN fGive , BOOLEAN fAllowMer } } - if ( pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < GASTON && !RPC_RECRUITED( pSoldier ) && !AM_AN_EPC( pSoldier ) ) +// if ( pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < GASTON && !RPC_RECRUITED( pSoldier ) && !AM_AN_EPC( pSoldier ) ) + //new profiles by Jazz + if ( pSoldier->ubProfile != NO_PROFILE && ( gProfilesRPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesNPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile ) && !RPC_RECRUITED( pSoldier ) && !AM_AN_EPC( pSoldier ) ) { fValidGuy = TRUE; } @@ -5739,7 +5937,7 @@ BOOLEAN HandleTalkInit( ) case 1: - if ( QuoteExp_PassingDislike[ pTSoldier->ubProfile ] ) + if ( QuoteExp[ pTSoldier->ubProfile ].QuoteExpPassingDislike ) { ubQuoteNum = QUOTE_PASSING_DISLIKE; } @@ -6469,4 +6667,4 @@ BOOLEAN IsValidJumpLocation( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fChec } return( FALSE ); -} +} \ No newline at end of file diff --git a/Tactical/Handle UI.h b/Tactical/Handle UI.h index 14132fb4..672158a9 100644 --- a/Tactical/Handle UI.h +++ b/Tactical/Handle UI.h @@ -220,6 +220,20 @@ extern BOOLEAN gTintBulletCounts; extern BOOLEAN gfUIAutofireBulletCount; extern BOOLEAN gfUICtHBar; +// HEADROCK HAM 4: Now a STRUCT containing several variables for CTH display +typedef struct +{ + UINT8 MuzzleSwayPercentage; + FLOAT ScopeMagFactor; + FLOAT ProjectionFactor; + FLOAT FinalMagFactor; + INT32 iShooterGridNo; + INT32 iTargetGridNo; + FLOAT dTargetZ; // CellZ of target (not tile coordinates!) + BOOLEAN fMaxAimReached; +} CTHDISPLAY; + +extern CTHDISPLAY gCTHDisplay; // HEADROCK HAM B1/2: Multiple-bullet CTH bar array (replaces old single integer) extern UINT8 gbCtH[ 10 ]; extern UINT8 gbCtHBurstCount; @@ -353,4 +367,11 @@ void PreventFromTheFreezingBug(SOLDIERTYPE* pSoldier); void GetGridNoScreenXY( INT32 sGridNo, INT16 *pScreenX, INT16 *pScreenY ); +//Legion by Jazz +void GetMercOknoDirection( UINT8 ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pfGoUp ); +void GetMercFenceDirection( UINT8 ubSoldierID, BOOLEAN *pfGoDown, BOOLEAN *pfGoUp ); + +// HEADROCK HAM 4: Tells the targeting cursor whether we're adding bullets to autofire, or adding aim click levels. +extern BOOLEAN fAutofireBulletsMode; + #endif \ No newline at end of file diff --git a/Tactical/Interface Control.cpp b/Tactical/Interface Control.cpp index 80af3d22..4d633d96 100644 --- a/Tactical/Interface Control.cpp +++ b/Tactical/Interface Control.cpp @@ -49,6 +49,7 @@ #include "Militia Control.h" #include "Map Screen Interface.h" #include "civ quotes.h" + #include "GameSettings.h" #endif /* I deleted here declaration of clock coords for tactical screen i will declare them @@ -689,6 +690,14 @@ void RenderTopmostTacticalInterface( ) RenderAccumulatedBurstLocations( ); + // HEADROCK HAM 4: The NCTH indicator is now drawn to the FRAMEBUFFER instead of the MOUSEBUFFER. This is + // due to size constraints related to drawing directly on the cursor. This indicator follows the mouse, and + // is a mouse-cursor in everything but name. See the function itself for more details. + if (UsingNewCTHSystem() == true && gfUICtHBar) + { + DrawCTHIndicator(); + } + // Loop through all mercs and make go for ( cnt = 0; cnt < guiNumMercSlots; cnt++ ) { diff --git a/Tactical/Interface Dialogue.cpp b/Tactical/Interface Dialogue.cpp index 8ab979ee..b52bc05e 100644 --- a/Tactical/Interface Dialogue.cpp +++ b/Tactical/Interface Dialogue.cpp @@ -1800,7 +1800,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum ExitGrid.ubGotoSectorX = 10; ExitGrid.ubGotoSectorY = 1; ExitGrid.ubGotoSectorZ = 1; - ExitGrid.usGridNo = 12722; + ExitGrid.usGridNo = 12722; //dnl!!! ApplyMapChangesToMapTempFile( TRUE ); AddExitGridToWorld( 7887, &ExitGrid ); @@ -2260,7 +2260,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum case NPC_ACTION_SEND_PACOS_INTO_HIDING: pSoldier = FindSoldierByProfileID( 114, FALSE ); - sGridNo = 16028; + sGridNo = 16028; //dnl!!! if (pSoldier) { if (NewOKDestination( pSoldier, sGridNo, TRUE, 0 ) ) @@ -2280,7 +2280,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum break; case NPC_ACTION_HAVE_PACOS_FOLLOW: pSoldier = FindSoldierByProfileID( 114, FALSE ); - sGridNo = 18193; + sGridNo = 18193; //dnl!!! if (pSoldier) { if (NewOKDestination( pSoldier, sGridNo, TRUE, 0 ) ) @@ -2314,6 +2314,8 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum case NPC_ACTION_TRIGGER_END_OF_FOOD_QUEST: AddHistoryToPlayersLog( HISTORY_TALKED_TO_FATHER_WALKER, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); AddFutureDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay(), NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_TRIGGER_END_OF_FOOD_QUEST, 1 ); + // SANDRO - merc records - quest counter (food quest) + GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 4, NO_PROFILE ); break; case NPC_ACTION_REMOVE_CONRAD: @@ -2355,10 +2357,9 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum break; case NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE: - // set event to invoke Brenda's (#85) record 9 a minute from - // now + // set event to invoke Brenda's (#85) record 9 ten minutes from now DeleteTalkingMenu(); - AddSameDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay() + 360, NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE ); + AddSameDayStrategicEvent( EVENT_SET_BY_NPC_SYSTEM, GetWorldMinutesInDay() + 10, NPC_SYSTEM_EVENT_ACTION_PARAM_BONUS + NPC_ACTION_DELAYED_MAKE_BRENDA_LEAVE ); break; case NPC_ACTION_SEX: @@ -2373,7 +2374,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum // add a money item with $10000 to the tile in front of Kyle // and then have him pick it up { - INT32 sGridNo = 14952; + INT32 sGridNo = 14952; //dnl!!! INT32 iWorldItem; pSoldier = FindSoldierByProfileID( ubTargetNPC, FALSE ); @@ -2451,25 +2452,25 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum case NPC_ACTION_OPEN_CARLAS_DOOR: if (usActionCode == NPC_ACTION_OPEN_CARLAS_DOOR ) { - sGridNo = 12290; + sGridNo = 12290; //dnl!!! } // fall through case NPC_ACTION_OPEN_CINDYS_DOOR: if (usActionCode == NPC_ACTION_OPEN_CINDYS_DOOR ) { - sGridNo = 13413; + sGridNo = 13413; //dnl!!! } // fall through case NPC_ACTION_OPEN_BAMBIS_DOOR: if (usActionCode == NPC_ACTION_OPEN_BAMBIS_DOOR ) { - sGridNo = 11173; + sGridNo = 11173; //dnl!!! } // fall through case NPC_ACTION_OPEN_MARIAS_DOOR: if (usActionCode == NPC_ACTION_OPEN_MARIAS_DOOR ) { - sGridNo = 10852; + sGridNo = 10852; //dnl!!! } // JA3Gold: unlock the doors instead of opening them { @@ -2890,6 +2891,15 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum } // CJC Nov 28 2002 - fixed history record which didn't have location specified AddHistoryToPlayersLog( HISTORY_GAVE_CARMEN_HEAD, 0, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY ); + + // SANDRO - end the quest here - the team will gain exp and records by now + if (gMercProfiles[ CARMEN ].bNPCData <= 0) + { + SetFactTrue( FACT_ALL_TERRORISTS_KILLED ); + EndQuest( QUEST_KILL_TERRORISTS, gWorldSectorX, gWorldSectorY ); + + IncrementTownLoyaltyEverywhere( LOYALTY_BONUS_TERRORISTS_DEALT_WITH );// end terrorist quest + } break; case NPC_ACTION_CARMEN_LEAVES_FOR_GOOD: @@ -2903,13 +2913,14 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum break; case NPC_ACTION_CARMEN_LEAVES_ON_NEXT_SECTOR_LOAD: - if (gMercProfiles[ CARMEN ].bNPCData == 0) - { - SetFactTrue( FACT_ALL_TERRORISTS_KILLED ); - // the next time we change sectors, quest 2 will be set to done + // SANDRO - removed from here + // if (gMercProfiles[ CARMEN ].bNPCData == 0) + //{ + // SetFactTrue( FACT_ALL_TERRORISTS_KILLED ); + // // the next time we change sectors, quest 2 will be set to done - IncrementTownLoyaltyEverywhere( LOYALTY_BONUS_TERRORISTS_DEALT_WITH ); - } + // IncrementTownLoyaltyEverywhere( LOYALTY_BONUS_TERRORISTS_DEALT_WITH ); + //} // anyhow Carmen has given the player money so reset his balance to 0. gMercProfiles[ CARMEN ].uiMoney = 0; break; @@ -3186,7 +3197,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum if ( pSoldier->ubProfile == ARMAND ) { - sGridNo = 6968; + sGridNo = 6968; //dnl!!! } else { @@ -3933,6 +3944,8 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum else { TriggerNPCRecord( SERGEANT, 12 ); + // SANDRO - give reward for rescuing Krott and getting the rocket rifle + GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 5, CONRAD ); } break; @@ -3985,6 +3998,8 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum if ( gfLastBoxingMatchWonByPlayer && !BoxerAvailable() ) { TriggerNPCRecord( KINGPIN, 15 ); + // SANDRO - merc records - quest counter (Kingpin impressed) + GiveQuestRewardPoint( gWorldSectorX, gWorldSectorY, 4, NO_PROFILE ); } break; @@ -4845,7 +4860,7 @@ BOOLEAN NPCOpenThing( SOLDIERTYPE *pSoldier, BOOLEAN fDoor ) // for Armand, hard code to tile 6968 if ( pSoldier->ubProfile == ARMAND ) { - sStructGridNo = 6968; + sStructGridNo = 6968; //dnl!!! } else { diff --git a/Tactical/Interface Enhanced.cpp b/Tactical/Interface Enhanced.cpp index a131ee46..ba05102d 100644 --- a/Tactical/Interface Enhanced.cpp +++ b/Tactical/Interface Enhanced.cpp @@ -90,201 +90,23 @@ UINT32 guiItemInfoWeaponIcon; UINT32 guiItemInfoAmmoIcon; UINT32 guiItemInfoExplosiveIcon; UINT32 guiItemInfoArmorIcon; -UINT32 guiItemInfoMiscIcon; +//UINT32 guiItemInfoMiscIcon; +// HEADROCK HAM 4: Image for secondary icons +UINT32 guiItemInfoSecondaryIcon; +// HEADROCK HAM 4: This replaces "Misc" icons. +UINT32 guiItemInfoAdvancedIcon; -// HEADROCK: Start additional values. -INT16 BULLET_DRAW_X; -INT16 BULLET_DRAW_Y; -INT16 BULLET_AUTO_X; -INT16 BULLET_AUTO_Y; -INT16 BULLET_RELOAD_X; -INT16 BULLET_RELOAD_Y; -INT16 BULLET_MRELOAD_X; -INT16 BULLET_MRELOAD_Y; -INT16 BULLET_RANGE_X; -INT16 BULLET_RANGE_Y; -INT16 BULLET_DAMAGE_X; -INT16 BULLET_DAMAGE_Y; -INT16 BULLET_AUTOPEN_X; -INT16 BULLET_AUTOPEN_Y; -INT16 BULLET_AUTO5AP_X; -INT16 BULLET_AUTO5AP_Y; -INT16 BULLET_ACC_X; -INT16 BULLET_ACC_Y; -INT16 BULLET_RELIABILITY_X; -INT16 BULLET_RELIABILITY_Y; -INT16 BULLET_REPAIR_X; -INT16 BULLET_REPAIR_Y; -INT16 BULLET_LOUDNESS_X; -INT16 BULLET_LOUDNESS_Y; -INT16 BULLET_FLASH_X; -INT16 BULLET_FLASH_Y; -INT16 BULLET_TOHIT_X; -INT16 BULLET_TOHIT_Y; -INT16 BULLET_BESTLASERRANGE_X; -INT16 BULLET_BESTLASERRANGE_Y; -INT16 BULLET_AIMBONUS_X; -INT16 BULLET_AIMBONUS_Y; -INT16 BULLET_MINRANGEAIMBONUS_X; -INT16 BULLET_MINRANGEAIMBONUS_Y; -INT16 BULLET_BIPOD_X; -INT16 BULLET_BIPOD_Y; +// HEADROCK HAM 4: New tooltip regions for UDB replace the old regions. +#define NUM_UDB_FASTHELP_REGIONS 102 +MOUSE_REGION gUDBFasthelpRegions[NUM_UDB_FASTHELP_REGIONS]; -// HEADROCK: Icon Locations for AMMO stats -INT16 BULLET_ARMORPEN_X; -INT16 BULLET_ARMORPEN_Y; -INT16 BULLET_TUMBLE_X; -INT16 BULLET_TUMBLE_Y; -INT16 BULLET_PREARMOR_X; -INT16 BULLET_PREARMOR_Y; -INT16 BULLET_TRACER_X; -INT16 BULLET_TRACER_Y; -INT16 BULLET_ANTITANK_X; -INT16 BULLET_ANTITANK_Y; -INT16 BULLET_LOCKBUSTER_X; -INT16 BULLET_LOCKBUSTER_Y; -INT16 BULLET_IGNOREARMOR_X; -INT16 BULLET_IGNOREARMOR_Y; -INT16 BULLET_ACIDIC_X; -INT16 BULLET_ACIDIC_Y; -INT16 BULLET_AMMORANGEBON_X; -INT16 BULLET_AMMORANGEBON_Y; -INT16 BULLET_AMMODAMAGEBON_X; -INT16 BULLET_AMMODAMAGEBON_Y; -INT16 BULLET_AMMOTOHITBON_X; -INT16 BULLET_AMMOTOHITBON_Y; -INT16 BULLET_AMMOBURSTBON_X; -INT16 BULLET_AMMOBURSTBON_Y; -INT16 BULLET_AMMOAUTOBON_X; -INT16 BULLET_AMMOAUTOBON_Y; -INT16 BULLET_AMMORELIABILITYBON_X; -INT16 BULLET_AMMORELIABILITYBON_Y; -INT16 BULLET_AMMONOISESUPP_X; -INT16 BULLET_AMMONOISESUPP_Y; - -// HEADROCK: Icon Locations for EXPLOSIVES stats -INT16 BULLET_EXPLOSIVEDAMAGE_X; -INT16 BULLET_EXPLOSIVEDAMAGE_Y; -INT16 BULLET_EXPLOSIVESTUNDAMAGE_X; -INT16 BULLET_EXPLOSIVESTUNDAMAGE_Y; -INT16 BULLET_EXPLOSIVELOUDNESS_X; -INT16 BULLET_EXPLOSIVELOUDNESS_Y; -INT16 BULLET_EXPLOSIVEVOLATILITY_X; -INT16 BULLET_EXPLOSIVEVOLATILITY_Y; -INT16 BULLET_EXPLOSIVERADIUS_X; -INT16 BULLET_EXPLOSIVERADIUS_Y; -INT16 BULLET_EXPLOSIVESTARTRADIUS_X; -INT16 BULLET_EXPLOSIVESTARTRADIUS_Y; -INT16 BULLET_EXPLOSIVEARROW_X; -INT16 BULLET_EXPLOSIVEARROW_Y; -INT16 BULLET_EXPLOSIVEENDRADIUS_X; -INT16 BULLET_EXPLOSIVEENDRADIUS_Y; -INT16 BULLET_EXPLOSIVEDURATION_X; -INT16 BULLET_EXPLOSIVEDURATION_Y; - -// HEADROCK: Icon Locations for ARMOR stats -INT16 BULLET_ARMOR_X; -INT16 BULLET_ARMOR_Y; -INT16 BULLET_ARMORCOVERAGE_X; -INT16 BULLET_ARMORCOVERAGE_Y; -INT16 BULLET_ARMORDEGRADE_X; -INT16 BULLET_ARMORDEGRADE_Y; -INT16 BULLET_ARMORAPBONUS_X; -INT16 BULLET_ARMORAPBONUS_Y; -INT16 BULLET_ARMORAIMBONUS_X; -INT16 BULLET_ARMORAIMBONUS_Y; -INT16 BULLET_ARMORWOODCAMO_X; -INT16 BULLET_ARMORWOODCAMO_Y; -INT16 BULLET_ARMORURBANCAMO_X; -INT16 BULLET_ARMORURBANCAMO_Y; -INT16 BULLET_ARMORDESERTCAMO_X; -INT16 BULLET_ARMORDESERTCAMO_Y; -INT16 BULLET_ARMORSNOWCAMO_X; -INT16 BULLET_ARMORSNOWCAMO_Y; -INT16 BULLET_ARMORSTEALTH_X; -INT16 BULLET_ARMORSTEALTH_Y; -INT16 BULLET_ARMORVISIONRANGEBONUS_X; -INT16 BULLET_ARMORVISIONRANGEBONUS_Y; -INT16 BULLET_ARMORDAYVISIONRANGEBONUS_X; -INT16 BULLET_ARMORDAYVISIONRANGEBONUS_Y; -INT16 BULLET_ARMORNIGHTVISIONRANGEBONUS_X; -INT16 BULLET_ARMORNIGHTVISIONRANGEBONUS_Y; -INT16 BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_X; -INT16 BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_Y; -INT16 BULLET_ARMORCAVEVISIONRANGEBONUS_X; -INT16 BULLET_ARMORCAVEVISIONRANGEBONUS_Y; -INT16 BULLET_ARMORPERCENTTUNNELVISION_X; -INT16 BULLET_ARMORPERCENTTUNNELVISION_Y; -INT16 BULLET_ARMORHEARINGRANGEBONUS_X; -INT16 BULLET_ARMORHEARINGRANGEBONUS_Y; - -// HEADROCK: Generic Icon Locations for MISC Item Stats -INT16 BULLET_COL1ROW1_X; -INT16 BULLET_COL1ROW1_Y; -INT16 BULLET_COL1ROW2_X; -INT16 BULLET_COL1ROW2_Y; -INT16 BULLET_COL1ROW3_X; -INT16 BULLET_COL1ROW3_Y; -INT16 BULLET_COL1ROW4_X; -INT16 BULLET_COL1ROW4_Y; -INT16 BULLET_COL1ROW5_X; -INT16 BULLET_COL1ROW5_Y; -INT16 BULLET_COL1ROW6_X; -INT16 BULLET_COL1ROW6_Y; -INT16 BULLET_COL1ROW7_X; -INT16 BULLET_COL1ROW7_Y; -INT16 BULLET_COL1ROW8_X; -INT16 BULLET_COL1ROW8_Y; -INT16 BULLET_COL1ROW9_X; -INT16 BULLET_COL1ROW9_Y; -INT16 BULLET_COL1ROW10_X; -INT16 BULLET_COL1ROW10_Y; -INT16 BULLET_COL1ROW11_X; -INT16 BULLET_COL1ROW11_Y; -INT16 BULLET_COL1ROW12_X; -INT16 BULLET_COL1ROW12_Y; -INT16 BULLET_COL2ROW1_X; -INT16 BULLET_COL2ROW1_Y; -INT16 BULLET_COL2ROW2_X; -INT16 BULLET_COL2ROW2_Y; -INT16 BULLET_COL2ROW3_X; -INT16 BULLET_COL2ROW3_Y; -INT16 BULLET_COL2ROW4_X; -INT16 BULLET_COL2ROW4_Y; -INT16 BULLET_COL2ROW5_X; -INT16 BULLET_COL2ROW5_Y; -INT16 BULLET_COL2ROW6_X; -INT16 BULLET_COL2ROW6_Y; -INT16 BULLET_COL2ROW7_X; -INT16 BULLET_COL2ROW7_Y; -// HEADROCK: End additional values. - -// HEADROCK: New regions for stats tooltips -MOUSE_REGION gStatsFasthelpRegions[20]; - -extern INV_DESC_STATS gWeaponStats[]; extern INV_DESC_STATS gMoneyStats[]; -extern SGPRect gItemDescProsConsRects[]; extern INV_DESC_STATS gLBEStats[]; extern INV_ATTACHXY gItemDescAttachmentsXY[]; - -// HEADROCK: New array to contain locations for MiscItem stats. -INV_DESC_STATS gMiscItemStatsEDB[28]; - -// WEAPON stat tooltips -SGPRect gWeaponDescStatsRects[20]; - -// Ammo Stat Tooltips -SGPRect gAmmoDescStatsRects[20]; - -// ARMOR Stat Tooltips -SGPRect gArmorDescStatsRects[20]; - -// EXPLOSIVES Stat Tooltips -SGPRect gExplosiveDescStatsRects[20]; - -// MISC ITEM Stat Tooltips -SGPRect gMiscItemDescStatsRects[20]; +// HEADROCK HAM 4: Declare here so other functions may use it. +void DrawSecondaryStats( OBJECTTYPE * gpItemDescObject ); +void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject ); +void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject ); extern void HelpTextDoneCallback( void ); @@ -292,449 +114,583 @@ UINT8 UsingEDBSystem() { if(iResolution == 0) //640x480, never allow EDB return 0; + if(gGameSettings.fOptions[ TOPTION_ENHANCED_DESC_BOX ] == TRUE) { if(guiCurrentScreen == MAP_SCREEN) //Strategic { - if(gGameExternalOptions.iEnhancedDescriptionBox == 0) - return 1; - if(gGameExternalOptions.iEnhancedDescriptionBox == 1) + if(gGameExternalOptions.iEnhancedDescriptionBox == 0 || gGameExternalOptions.iEnhancedDescriptionBox == 1 ) return 1; } else //Tactical { - if(gGameExternalOptions.iEnhancedDescriptionBox == 0) - return (UsingNewInventorySystem()==true?1:2); - if(gGameExternalOptions.iEnhancedDescriptionBox == 2) - return (UsingNewInventorySystem()==true?1:2); + // HEADROCK HAM 4: With the introduction of UDB, it is no longer possible to display an extended + // description box for OIV (unless the interface panel is increased... which I doubt it will be). + if (UsingNewInventorySystem()==false) + return 0; + if(gGameExternalOptions.iEnhancedDescriptionBox == 0 || gGameExternalOptions.iEnhancedDescriptionBox == 2) + return 1; } } return 0; } -void InitEDBCoords() +void InitEDBCoords(OBJECTTYPE * pObject) { - if(UsingEDBSystem() == 0) - return; - if(guiCurrentScreen == MAP_SCREEN) + if (UsingEDBSystem() > 0) { - // Icon Locations - gMiscItemStatsEDB[0].sX = 47; gMiscItemStatsEDB[0].sY = 124; gMiscItemStatsEDB[0].sValDx = 0; // COL 1; ROW 1 - gMiscItemStatsEDB[1].sX = 47; gMiscItemStatsEDB[1].sY = 136; gMiscItemStatsEDB[1].sValDx = 0; // COL 1; ROW 2 - gMiscItemStatsEDB[2].sX = 47; gMiscItemStatsEDB[2].sY = 148; gMiscItemStatsEDB[2].sValDx = 0; // COL 1; ROW 3 - gMiscItemStatsEDB[3].sX = 47; gMiscItemStatsEDB[3].sY = 160; gMiscItemStatsEDB[3].sValDx = 0; // COL 1; ROW 4 - gMiscItemStatsEDB[4].sX = 47; gMiscItemStatsEDB[4].sY = 172; gMiscItemStatsEDB[4].sValDx = 0; // COL 1; ROW 5 - gMiscItemStatsEDB[5].sX = 47; gMiscItemStatsEDB[5].sY = 184; gMiscItemStatsEDB[5].sValDx = 0; // COL 1; ROW 6 - gMiscItemStatsEDB[6].sX = 47; gMiscItemStatsEDB[6].sY = 196; gMiscItemStatsEDB[6].sValDx = 0; // COL 1; ROW 7 - gMiscItemStatsEDB[7].sX = 144; gMiscItemStatsEDB[7].sY = 124; gMiscItemStatsEDB[7].sValDx = 0; // COL 2; ROW 1 - gMiscItemStatsEDB[8].sX = 144; gMiscItemStatsEDB[8].sY = 136; gMiscItemStatsEDB[8].sValDx = 0; // COL 2; ROW 2 - gMiscItemStatsEDB[9].sX = 144; gMiscItemStatsEDB[9].sY = 148; gMiscItemStatsEDB[9].sValDx = 0; // COL 2; ROW 3 - gMiscItemStatsEDB[10].sX = 144; gMiscItemStatsEDB[10].sY = 160; gMiscItemStatsEDB[10].sValDx = 0; // COL 2; ROW 4 - gMiscItemStatsEDB[11].sX = 144; gMiscItemStatsEDB[11].sY = 172; gMiscItemStatsEDB[11].sValDx = 0; // COL 2; ROW 5 - gMiscItemStatsEDB[12].sX = 144; gMiscItemStatsEDB[12].sY = 184; gMiscItemStatsEDB[12].sValDx = 0; // COL 2; ROW 6 - gMiscItemStatsEDB[13].sX = 144; gMiscItemStatsEDB[13].sY = 196; gMiscItemStatsEDB[13].sValDx = 0; // COL 2; ROW 7 - // EQUALS signs Locations - gMiscItemStatsEDB[14].sX = 97; gMiscItemStatsEDB[14].sY = 124; gMiscItemStatsEDB[14].sValDx = 12; // COL 1; ROW 1 - gMiscItemStatsEDB[15].sX = 97; gMiscItemStatsEDB[15].sY = 136; gMiscItemStatsEDB[15].sValDx = 12; // COL 1; ROW 2 - gMiscItemStatsEDB[16].sX = 97; gMiscItemStatsEDB[16].sY = 148; gMiscItemStatsEDB[16].sValDx = 12; // COL 1; ROW 3 - gMiscItemStatsEDB[17].sX = 97; gMiscItemStatsEDB[17].sY = 160; gMiscItemStatsEDB[17].sValDx = 12; // COL 1; ROW 4 - gMiscItemStatsEDB[18].sX = 97; gMiscItemStatsEDB[18].sY = 172; gMiscItemStatsEDB[18].sValDx = 12; // COL 1; ROW 5 - gMiscItemStatsEDB[19].sX = 97; gMiscItemStatsEDB[19].sY = 184; gMiscItemStatsEDB[19].sValDx = 12; // COL 1; ROW 6 - gMiscItemStatsEDB[20].sX = 97; gMiscItemStatsEDB[20].sY = 196; gMiscItemStatsEDB[20].sValDx = 12; // COL 1; ROW 7 - gMiscItemStatsEDB[21].sX = 194; gMiscItemStatsEDB[21].sY = 124; gMiscItemStatsEDB[21].sValDx = 12; // COL 2; ROW 1 - gMiscItemStatsEDB[22].sX = 194; gMiscItemStatsEDB[22].sY = 136; gMiscItemStatsEDB[22].sValDx = 12; // COL 2; ROW 2 - gMiscItemStatsEDB[23].sX = 194; gMiscItemStatsEDB[23].sY = 148; gMiscItemStatsEDB[23].sValDx = 12; // COL 2; ROW 3 - gMiscItemStatsEDB[24].sX = 194; gMiscItemStatsEDB[24].sY = 160; gMiscItemStatsEDB[24].sValDx = 12; // COL 2; ROW 4 - gMiscItemStatsEDB[25].sX = 194; gMiscItemStatsEDB[25].sY = 172; gMiscItemStatsEDB[25].sValDx = 12; // COL 2; ROW 5 - gMiscItemStatsEDB[26].sX = 194; gMiscItemStatsEDB[26].sY = 184; gMiscItemStatsEDB[26].sValDx = 12; // COL 2; ROW 6 - gMiscItemStatsEDB[27].sX = 194; gMiscItemStatsEDB[27].sY = 196; gMiscItemStatsEDB[27].sValDx = 12; // COL 2; ROW 7 + ////////////////////////////////////////////////////////////// + // UDB Offsets. + // These offsets allow us to efficiently render UDB in two different places (for Strategic + // and Tactical) without changing anything else. This is thanks to UDB being almost exactly + // the same interface in both screens! - gWeaponDescStatsRects[0].iLeft = 46; gWeaponDescStatsRects[0].iTop = 229; gWeaponDescStatsRects[0].iRight = 103; gWeaponDescStatsRects[0].iBottom = 240; // First Column - gWeaponDescStatsRects[1].iLeft = 46; gWeaponDescStatsRects[1].iTop = 241; gWeaponDescStatsRects[1].iRight = 103; gWeaponDescStatsRects[1].iBottom = 252; - gWeaponDescStatsRects[2].iLeft = 46; gWeaponDescStatsRects[2].iTop = 253; gWeaponDescStatsRects[2].iRight = 103; gWeaponDescStatsRects[2].iBottom = 264; - gWeaponDescStatsRects[3].iLeft = 46; gWeaponDescStatsRects[3].iTop = 265; gWeaponDescStatsRects[3].iRight = 103; gWeaponDescStatsRects[3].iBottom = 276; - gWeaponDescStatsRects[4].iLeft = 46; gWeaponDescStatsRects[4].iTop = 277; gWeaponDescStatsRects[4].iRight = 103; gWeaponDescStatsRects[4].iBottom = 288; - gWeaponDescStatsRects[5].iLeft = 46; gWeaponDescStatsRects[5].iTop = 289; gWeaponDescStatsRects[5].iRight = 103; gWeaponDescStatsRects[5].iBottom = 300; - gWeaponDescStatsRects[6].iLeft = 46; gWeaponDescStatsRects[6].iTop = 301; gWeaponDescStatsRects[6].iRight = 103; gWeaponDescStatsRects[6].iBottom = 312; - gWeaponDescStatsRects[7].iLeft = 111; gWeaponDescStatsRects[7].iTop = 241; gWeaponDescStatsRects[7].iRight = 168; gWeaponDescStatsRects[7].iBottom = 252; // Second Column - gWeaponDescStatsRects[8].iLeft = 111; gWeaponDescStatsRects[8].iTop = 253; gWeaponDescStatsRects[8].iRight = 168; gWeaponDescStatsRects[8].iBottom = 264; - gWeaponDescStatsRects[9].iLeft = 111; gWeaponDescStatsRects[9].iTop = 265; gWeaponDescStatsRects[9].iRight = 168; gWeaponDescStatsRects[9].iBottom = 276; - gWeaponDescStatsRects[10].iLeft = 111; gWeaponDescStatsRects[10].iTop = 277; gWeaponDescStatsRects[10].iRight = 168; gWeaponDescStatsRects[10].iBottom = 288; - gWeaponDescStatsRects[11].iLeft = 111; gWeaponDescStatsRects[11].iTop = 289; gWeaponDescStatsRects[11].iRight = 168; gWeaponDescStatsRects[11].iBottom = 300; - gWeaponDescStatsRects[12].iLeft = 111; gWeaponDescStatsRects[12].iTop = 301; gWeaponDescStatsRects[12].iRight = 168; gWeaponDescStatsRects[12].iBottom = 312; - gWeaponDescStatsRects[13].iLeft = 173; gWeaponDescStatsRects[13].iTop = 229; gWeaponDescStatsRects[13].iRight = 230; gWeaponDescStatsRects[13].iBottom = 240; // Third Column - gWeaponDescStatsRects[14].iLeft = 173; gWeaponDescStatsRects[14].iTop = 241; gWeaponDescStatsRects[14].iRight = 230; gWeaponDescStatsRects[14].iBottom = 252; - gWeaponDescStatsRects[15].iLeft = 173; gWeaponDescStatsRects[15].iTop = 253; gWeaponDescStatsRects[15].iRight = 230; gWeaponDescStatsRects[15].iBottom = 264; - gWeaponDescStatsRects[16].iLeft = 173; gWeaponDescStatsRects[16].iTop = 265; gWeaponDescStatsRects[16].iRight = 230; gWeaponDescStatsRects[16].iBottom = 276; - gWeaponDescStatsRects[17].iLeft = 173; gWeaponDescStatsRects[17].iTop = 277; gWeaponDescStatsRects[17].iRight = 230; gWeaponDescStatsRects[17].iBottom = 288; - gWeaponDescStatsRects[18].iLeft = 173; gWeaponDescStatsRects[18].iTop = 289; gWeaponDescStatsRects[18].iRight = 230; gWeaponDescStatsRects[18].iBottom = 300; - gWeaponDescStatsRects[19].iLeft = 173; gWeaponDescStatsRects[19].iTop = 301; gWeaponDescStatsRects[19].iRight = 230; gWeaponDescStatsRects[19].iBottom = 312; + INT16 UDBOffsetX; + INT16 UDBOffsetY; + + UDBOffsetX = gsInvDescX; + UDBOffsetY = gsInvDescY; - gAmmoDescStatsRects[0].iLeft = 46; gAmmoDescStatsRects[0].iTop = 229; gAmmoDescStatsRects[0].iRight = 103; gAmmoDescStatsRects[0].iBottom = 240; // First Column - gAmmoDescStatsRects[1].iLeft = 46; gAmmoDescStatsRects[1].iTop = 241; gAmmoDescStatsRects[1].iRight = 103; gAmmoDescStatsRects[1].iBottom = 252; - gAmmoDescStatsRects[2].iLeft = 46; gAmmoDescStatsRects[2].iTop = 253; gAmmoDescStatsRects[2].iRight = 103; gAmmoDescStatsRects[2].iBottom = 264; - gAmmoDescStatsRects[3].iLeft = 113; gAmmoDescStatsRects[3].iTop = 229; gAmmoDescStatsRects[3].iRight = 135; gAmmoDescStatsRects[3].iBottom = 252; // Second Column - gAmmoDescStatsRects[4].iLeft = 140; gAmmoDescStatsRects[4].iTop = 229; gAmmoDescStatsRects[4].iRight = 165; gAmmoDescStatsRects[4].iBottom = 252; - gAmmoDescStatsRects[5].iLeft = 113; gAmmoDescStatsRects[5].iTop = 253; gAmmoDescStatsRects[5].iRight = 135; gAmmoDescStatsRects[5].iBottom = 276; - gAmmoDescStatsRects[6].iLeft = 140; gAmmoDescStatsRects[6].iTop = 253; gAmmoDescStatsRects[6].iRight = 165; gAmmoDescStatsRects[6].iBottom = 276; - gAmmoDescStatsRects[7].iLeft = 113; gAmmoDescStatsRects[7].iTop = 277; gAmmoDescStatsRects[7].iRight = 135; gAmmoDescStatsRects[7].iBottom = 300; - gAmmoDescStatsRects[8].iLeft = 173; gAmmoDescStatsRects[8].iTop = 229; gAmmoDescStatsRects[8].iRight = 230; gAmmoDescStatsRects[8].iBottom = 240; // Third Column - gAmmoDescStatsRects[9].iLeft = 173; gAmmoDescStatsRects[9].iTop = 241; gAmmoDescStatsRects[9].iRight = 230; gAmmoDescStatsRects[9].iBottom = 252; - gAmmoDescStatsRects[10].iLeft = 173; gAmmoDescStatsRects[10].iTop = 253; gAmmoDescStatsRects[10].iRight = 230; gAmmoDescStatsRects[10].iBottom = 264; - gAmmoDescStatsRects[11].iLeft = 173; gAmmoDescStatsRects[11].iTop = 265; gAmmoDescStatsRects[11].iRight = 230; gAmmoDescStatsRects[11].iBottom = 276; - gAmmoDescStatsRects[12].iLeft = 173; gAmmoDescStatsRects[12].iTop = 277; gAmmoDescStatsRects[12].iRight = 230; gAmmoDescStatsRects[12].iBottom = 288; // Fourth Column - gAmmoDescStatsRects[13].iLeft = 173; gAmmoDescStatsRects[13].iTop = 289; gAmmoDescStatsRects[13].iRight = 230; gAmmoDescStatsRects[13].iBottom = 300; - gAmmoDescStatsRects[14].iLeft = 173; gAmmoDescStatsRects[14].iTop = 301; gAmmoDescStatsRects[14].iRight = 230; gAmmoDescStatsRects[14].iBottom = 312; // Placeholders - gAmmoDescStatsRects[15].iLeft = 0; gAmmoDescStatsRects[15].iTop = 0; gAmmoDescStatsRects[15].iRight = 1; gAmmoDescStatsRects[15].iBottom = 1; - gAmmoDescStatsRects[16].iLeft = 0; gAmmoDescStatsRects[16].iTop = 0; gAmmoDescStatsRects[16].iRight = 1; gAmmoDescStatsRects[16].iBottom = 1; - gAmmoDescStatsRects[17].iLeft = 0; gAmmoDescStatsRects[17].iTop = 0; gAmmoDescStatsRects[17].iRight = 1; gAmmoDescStatsRects[17].iBottom = 1; - gAmmoDescStatsRects[18].iLeft = 0; gAmmoDescStatsRects[18].iTop = 0; gAmmoDescStatsRects[18].iRight = 1; gAmmoDescStatsRects[18].iBottom = 1; - gAmmoDescStatsRects[19].iLeft = 0; gAmmoDescStatsRects[19].iTop = 0; gAmmoDescStatsRects[19].iRight = 1; gAmmoDescStatsRects[19].iBottom = 1; + // Adjust for NAS + if(UsingNewAttachmentSystem() == true) + { + UDBOffsetX += sNASXCorrection(pObject); + UDBOffsetY += sNASYCorrection(pObject); + } + // If no NAS, adjust tactical screen coordinates separately. + if (guiCurrentScreen != MAP_SCREEN) + { + UDBOffsetX += 224; + UDBOffsetY += -114; + if (UseNASDesc( pObject )) + { + UDBOffsetX -= 128; + } + } - gArmorDescStatsRects[0].iLeft = 46; gArmorDescStatsRects[0].iTop = 229; gArmorDescStatsRects[0].iRight = 103; gArmorDescStatsRects[0].iBottom = 240; // First Column - gArmorDescStatsRects[1].iLeft = 46; gArmorDescStatsRects[1].iTop = 241; gArmorDescStatsRects[1].iRight = 103; gArmorDescStatsRects[1].iBottom = 252; - gArmorDescStatsRects[2].iLeft = 46; gArmorDescStatsRects[2].iTop = 253; gArmorDescStatsRects[2].iRight = 103; gArmorDescStatsRects[2].iBottom = 264; - gArmorDescStatsRects[3].iLeft = 111; gArmorDescStatsRects[3].iTop = 229; gArmorDescStatsRects[3].iRight = 168; gArmorDescStatsRects[3].iBottom = 240; // Second Column - gArmorDescStatsRects[4].iLeft = 111; gArmorDescStatsRects[4].iTop = 241; gArmorDescStatsRects[4].iRight = 168; gArmorDescStatsRects[4].iBottom = 252; - gArmorDescStatsRects[5].iLeft = 111; gArmorDescStatsRects[5].iTop = 253; gArmorDescStatsRects[5].iRight = 168; gArmorDescStatsRects[5].iBottom = 264; - gArmorDescStatsRects[6].iLeft = 111; gArmorDescStatsRects[6].iTop = 265; gArmorDescStatsRects[6].iRight = 168; gArmorDescStatsRects[6].iBottom = 276; - gArmorDescStatsRects[7].iLeft = 111; gArmorDescStatsRects[7].iTop = 277; gArmorDescStatsRects[7].iRight = 168; gArmorDescStatsRects[7].iBottom = 288; - gArmorDescStatsRects[8].iLeft = 111; gArmorDescStatsRects[8].iTop = 289; gArmorDescStatsRects[8].iRight = 168; gArmorDescStatsRects[8].iBottom = 300; - gArmorDescStatsRects[9].iLeft = 111; gArmorDescStatsRects[9].iTop = 301; gArmorDescStatsRects[9].iRight = 168; gArmorDescStatsRects[9].iBottom = 312; - gArmorDescStatsRects[10].iLeft = 173; gArmorDescStatsRects[10].iTop = 229; gArmorDescStatsRects[10].iRight = 230; gArmorDescStatsRects[10].iBottom = 240; // Third Column - gArmorDescStatsRects[11].iLeft = 173; gArmorDescStatsRects[11].iTop = 241; gArmorDescStatsRects[11].iRight = 230; gArmorDescStatsRects[11].iBottom = 252; - gArmorDescStatsRects[12].iLeft = 173; gArmorDescStatsRects[12].iTop = 253; gArmorDescStatsRects[12].iRight = 230; gArmorDescStatsRects[12].iBottom = 264; - gArmorDescStatsRects[13].iLeft = 173; gArmorDescStatsRects[13].iTop = 265; gArmorDescStatsRects[13].iRight = 230; gArmorDescStatsRects[13].iBottom = 276; - gArmorDescStatsRects[14].iLeft = 173; gArmorDescStatsRects[14].iTop = 277; gArmorDescStatsRects[14].iRight = 230; gArmorDescStatsRects[14].iBottom = 288; - gArmorDescStatsRects[15].iLeft = 173; gArmorDescStatsRects[15].iTop = 289; gArmorDescStatsRects[15].iRight = 230; gArmorDescStatsRects[15].iBottom = 300; - gArmorDescStatsRects[16].iLeft = 173; gArmorDescStatsRects[16].iTop = 301; gArmorDescStatsRects[16].iRight = 230; gArmorDescStatsRects[16].iBottom = 312; - gArmorDescStatsRects[17].iLeft = 0; gArmorDescStatsRects[17].iTop = 0; gArmorDescStatsRects[17].iRight = 1; gArmorDescStatsRects[17].iBottom = 1; // Placeholders - gArmorDescStatsRects[18].iLeft = 0; gArmorDescStatsRects[18].iTop = 0; gArmorDescStatsRects[18].iRight = 1; gArmorDescStatsRects[18].iBottom = 1; - gArmorDescStatsRects[19].iLeft = 0; gArmorDescStatsRects[19].iTop = 0; gArmorDescStatsRects[19].iRight = 1; gArmorDescStatsRects[19].iBottom = 1; + /////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB LBE background coordinates + // These depend on Strategic/Tactical... + if (guiCurrentScreen == MAP_SCREEN) + { + gItemDescLBEBackground[0].sLeft = 58 + UDBOffsetX; gItemDescLBEBackground[0].sTop = 366 + UDBOffsetY; + gItemDescLBEBackground[1].sLeft = 15 + UDBOffsetX; gItemDescLBEBackground[1].sTop = 416 + UDBOffsetY; + gItemDescLBEBackground[2].sLeft = 59 + UDBOffsetX; gItemDescLBEBackground[2].sTop = 340 + UDBOffsetY; + gItemDescLBEBackground[3].sLeft = 25 + UDBOffsetX; gItemDescLBEBackground[3].sTop = 346 + UDBOffsetY; + } + else + { + gItemDescLBEBackground[0].sLeft = 251 + UDBOffsetX; gItemDescLBEBackground[0].sTop = 121 + UDBOffsetY; + gItemDescLBEBackground[1].sLeft = 251 + UDBOffsetX; gItemDescLBEBackground[1].sTop = 121 + UDBOffsetY; + gItemDescLBEBackground[2].sLeft = 251 + UDBOffsetX; gItemDescLBEBackground[2].sTop = 121 + UDBOffsetY; + gItemDescLBEBackground[3].sLeft = 251 + UDBOffsetX; gItemDescLBEBackground[3].sTop = 121 + UDBOffsetY; + } - gExplosiveDescStatsRects[0].iLeft = 46; gExplosiveDescStatsRects[0].iTop = 229; gExplosiveDescStatsRects[0].iRight = 103; gExplosiveDescStatsRects[0].iBottom = 240; // First Column - gExplosiveDescStatsRects[1].iLeft = 46; gExplosiveDescStatsRects[1].iTop = 241; gExplosiveDescStatsRects[1].iRight = 103; gExplosiveDescStatsRects[1].iBottom = 252; - gExplosiveDescStatsRects[2].iLeft = 46; gExplosiveDescStatsRects[2].iTop = 253; gExplosiveDescStatsRects[2].iRight = 103; gExplosiveDescStatsRects[2].iBottom = 264; - gExplosiveDescStatsRects[3].iLeft = 46; gExplosiveDescStatsRects[3].iTop = 265; gExplosiveDescStatsRects[3].iRight = 103; gExplosiveDescStatsRects[3].iBottom = 276; - gExplosiveDescStatsRects[4].iLeft = 131; gExplosiveDescStatsRects[4].iTop = 229; gExplosiveDescStatsRects[4].iRight = 147; gExplosiveDescStatsRects[4].iBottom = 264; // Second Column - gExplosiveDescStatsRects[5].iLeft = 113; gExplosiveDescStatsRects[5].iTop = 229; gExplosiveDescStatsRects[5].iRight = 129; gExplosiveDescStatsRects[5].iBottom = 264; - gExplosiveDescStatsRects[6].iLeft = 145; gExplosiveDescStatsRects[6].iTop = 229; gExplosiveDescStatsRects[6].iRight = 165; gExplosiveDescStatsRects[6].iBottom = 264; - gExplosiveDescStatsRects[7].iLeft = 111; gExplosiveDescStatsRects[7].iTop = 277; gExplosiveDescStatsRects[7].iRight = 168; gExplosiveDescStatsRects[7].iBottom = 288; - gExplosiveDescStatsRects[8].iLeft = 0; gExplosiveDescStatsRects[8].iTop = 0; gExplosiveDescStatsRects[8].iRight = 1; gExplosiveDescStatsRects[8].iBottom = 1; // Placeholders - gExplosiveDescStatsRects[9].iLeft = 0; gExplosiveDescStatsRects[9].iTop = 0; gExplosiveDescStatsRects[9].iRight = 1; gExplosiveDescStatsRects[9].iBottom = 1; - gExplosiveDescStatsRects[10].iLeft = 0; gExplosiveDescStatsRects[10].iTop = 0; gExplosiveDescStatsRects[10].iRight = 1; gExplosiveDescStatsRects[10].iBottom = 1; - gExplosiveDescStatsRects[11].iLeft = 0; gExplosiveDescStatsRects[11].iTop = 0; gExplosiveDescStatsRects[11].iRight = 1; gExplosiveDescStatsRects[11].iBottom = 1; - gExplosiveDescStatsRects[12].iLeft = 0; gExplosiveDescStatsRects[12].iTop = 0; gExplosiveDescStatsRects[12].iRight = 1; gExplosiveDescStatsRects[12].iBottom = 1; - gExplosiveDescStatsRects[13].iLeft = 0; gExplosiveDescStatsRects[13].iTop = 0; gExplosiveDescStatsRects[13].iRight = 1; gExplosiveDescStatsRects[13].iBottom = 1; - gExplosiveDescStatsRects[14].iLeft = 0; gExplosiveDescStatsRects[14].iTop = 0; gExplosiveDescStatsRects[14].iRight = 1; gExplosiveDescStatsRects[14].iBottom = 1; - gExplosiveDescStatsRects[15].iLeft = 0; gExplosiveDescStatsRects[15].iTop = 0; gExplosiveDescStatsRects[15].iRight = 1; gExplosiveDescStatsRects[15].iBottom = 1; - gExplosiveDescStatsRects[16].iLeft = 0; gExplosiveDescStatsRects[16].iTop = 0; gExplosiveDescStatsRects[16].iRight = 1; gExplosiveDescStatsRects[16].iBottom = 1; - gExplosiveDescStatsRects[17].iLeft = 0; gExplosiveDescStatsRects[17].iTop = 0; gExplosiveDescStatsRects[17].iRight = 1; gExplosiveDescStatsRects[17].iBottom = 1; - gExplosiveDescStatsRects[18].iLeft = 0; gExplosiveDescStatsRects[18].iTop = 0; gExplosiveDescStatsRects[18].iRight = 1; gExplosiveDescStatsRects[18].iBottom = 1; - gExplosiveDescStatsRects[19].iLeft = 0; gExplosiveDescStatsRects[19].iTop = 0; gExplosiveDescStatsRects[19].iRight = 1; gExplosiveDescStatsRects[19].iBottom = 1; + /////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB Description Page - gMiscItemDescStatsRects[0].iLeft = 46; gMiscItemDescStatsRects[0].iTop = 229; gMiscItemDescStatsRects[0].iRight = 103; gMiscItemDescStatsRects[0].iBottom = 240; // First Column - gMiscItemDescStatsRects[1].iLeft = 46; gMiscItemDescStatsRects[1].iTop = 241; gMiscItemDescStatsRects[1].iRight = 103; gMiscItemDescStatsRects[1].iBottom = 252; - gMiscItemDescStatsRects[2].iLeft = 46; gMiscItemDescStatsRects[2].iTop = 253; gMiscItemDescStatsRects[2].iRight = 103; gMiscItemDescStatsRects[2].iBottom = 264; - gMiscItemDescStatsRects[3].iLeft = 46; gMiscItemDescStatsRects[3].iTop = 265; gMiscItemDescStatsRects[3].iRight = 103; gMiscItemDescStatsRects[3].iBottom = 276; - gMiscItemDescStatsRects[4].iLeft = 46; gMiscItemDescStatsRects[4].iTop = 277; gMiscItemDescStatsRects[4].iRight = 103; gMiscItemDescStatsRects[4].iBottom = 288; - gMiscItemDescStatsRects[5].iLeft = 46; gMiscItemDescStatsRects[5].iTop = 289; gMiscItemDescStatsRects[5].iRight = 103; gMiscItemDescStatsRects[5].iBottom = 300; - gMiscItemDescStatsRects[6].iLeft = 46; gMiscItemDescStatsRects[6].iTop = 301; gMiscItemDescStatsRects[6].iRight = 103; gMiscItemDescStatsRects[6].iBottom = 312; - gMiscItemDescStatsRects[7].iLeft = 144; gMiscItemDescStatsRects[7].iTop = 229; gMiscItemDescStatsRects[7].iRight = 230; gMiscItemDescStatsRects[7].iBottom = 240; // First Column - gMiscItemDescStatsRects[8].iLeft = 144; gMiscItemDescStatsRects[8].iTop = 241; gMiscItemDescStatsRects[8].iRight = 230; gMiscItemDescStatsRects[8].iBottom = 252; - gMiscItemDescStatsRects[9].iLeft = 144; gMiscItemDescStatsRects[9].iTop = 253; gMiscItemDescStatsRects[9].iRight = 230; gMiscItemDescStatsRects[9].iBottom = 264; - gMiscItemDescStatsRects[10].iLeft = 144; gMiscItemDescStatsRects[10].iTop = 265; gMiscItemDescStatsRects[10].iRight = 230; gMiscItemDescStatsRects[10].iBottom = 276; - gMiscItemDescStatsRects[11].iLeft = 144; gMiscItemDescStatsRects[11].iTop = 277; gMiscItemDescStatsRects[11].iRight = 230; gMiscItemDescStatsRects[11].iBottom = 288; - gMiscItemDescStatsRects[12].iLeft = 144; gMiscItemDescStatsRects[12].iTop = 289; gMiscItemDescStatsRects[12].iRight = 230; gMiscItemDescStatsRects[12].iBottom = 300; - gMiscItemDescStatsRects[13].iLeft = 144; gMiscItemDescStatsRects[13].iTop = 301; gMiscItemDescStatsRects[13].iRight = 230; gMiscItemDescStatsRects[13].iBottom = 312; - gMiscItemDescStatsRects[14].iLeft = 0; gMiscItemDescStatsRects[14].iTop = 0; gMiscItemDescStatsRects[14].iRight = 1; gMiscItemDescStatsRects[14].iBottom = 1; // Placeholders - gMiscItemDescStatsRects[15].iLeft = 0; gMiscItemDescStatsRects[15].iTop = 0; gMiscItemDescStatsRects[15].iRight = 1; gMiscItemDescStatsRects[15].iBottom = 1; - gMiscItemDescStatsRects[16].iLeft = 0; gMiscItemDescStatsRects[16].iTop = 0; gMiscItemDescStatsRects[16].iRight = 1; gMiscItemDescStatsRects[16].iBottom = 1; - gMiscItemDescStatsRects[17].iLeft = 0; gMiscItemDescStatsRects[17].iTop = 0; gMiscItemDescStatsRects[17].iRight = 1; gMiscItemDescStatsRects[17].iBottom = 1; - gMiscItemDescStatsRects[18].iLeft = 0; gMiscItemDescStatsRects[18].iTop = 0; gMiscItemDescStatsRects[18].iRight = 1; gMiscItemDescStatsRects[18].iBottom = 1; - gMiscItemDescStatsRects[19].iLeft = 0; gMiscItemDescStatsRects[19].iTop = 0; gMiscItemDescStatsRects[19].iRight = 1; gMiscItemDescStatsRects[19].iBottom = 1; + // Full item description + gItemDescTextRegions[0].sLeft = 20 + UDBOffsetX; gItemDescTextRegions[0].sTop = 128 + UDBOffsetY; gItemDescTextRegions[0].sRight = 230 + UDBOffsetX; gItemDescTextRegions[0].sBottom = 200 + UDBOffsetY; + + // Condition + gItemDescTextRegions[1].sLeft = 20 + UDBOffsetX; gItemDescTextRegions[1].sTop = 230 + UDBOffsetY; gItemDescTextRegions[1].sRight = 230 + UDBOffsetX; gItemDescTextRegions[1].sBottom = 238 + UDBOffsetY; + + // Weight + gItemDescTextRegions[2].sLeft = 20 + UDBOffsetX; gItemDescTextRegions[2].sTop = 242 + UDBOffsetY; gItemDescTextRegions[2].sRight = 230 + UDBOffsetX; gItemDescTextRegions[2].sBottom = 250 + UDBOffsetY; + + // PROS label + gItemDescTextRegions[3].sLeft = 20 + UDBOffsetX; gItemDescTextRegions[3].sTop = 280 + UDBOffsetY; gItemDescTextRegions[3].sRight = 230 + UDBOffsetX; gItemDescTextRegions[3].sBottom = 288 + UDBOffsetY; + + // PROS text + gItemDescTextRegions[4].sLeft = 50 + UDBOffsetX; gItemDescTextRegions[4].sTop = 280 + UDBOffsetY; gItemDescTextRegions[4].sRight = 230 + UDBOffsetX; gItemDescTextRegions[4].sBottom = 288 + UDBOffsetY; + + // CONS label + gItemDescTextRegions[5].sLeft = 20 + UDBOffsetX; gItemDescTextRegions[5].sTop = 292 + UDBOffsetY; gItemDescTextRegions[5].sRight = 230 + UDBOffsetX; gItemDescTextRegions[5].sBottom = 300 + UDBOffsetY; + + // CONS text + gItemDescTextRegions[6].sLeft = 50 + UDBOffsetX; gItemDescTextRegions[6].sTop = 292 + UDBOffsetY; gItemDescTextRegions[6].sRight = 230 + UDBOffsetX; gItemDescTextRegions[6].sBottom = 300 + UDBOffsetY; + + ////////////////// MONEY TEXT COORDINATES + gMoneyStats[0].sX = 20 + UDBOffsetX; gMoneyStats[0].sY = 230 + UDBOffsetY; // Money + gMoneyStats[1].sX = 63 + UDBOffsetX; gMoneyStats[1].sY = 230 + UDBOffsetY; // Remaining + gMoneyStats[2].sX = 20 + UDBOffsetX; gMoneyStats[2].sY = 245 + UDBOffsetY; // Money + gMoneyStats[3].sX = 63 + UDBOffsetX; gMoneyStats[3].sY = 245 + UDBOffsetY; // Removing + gMoneyStats[4].sX = 145 + UDBOffsetX; gMoneyStats[4].sY = 230 + UDBOffsetY; // AMT remaining + gMoneyStats[5].sX = 145 + UDBOffsetX; gMoneyStats[5].sY = 245 + UDBOffsetY; // AMT removing + + /////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB General Page - Header locations + + // "Primary" header + gItemDescGenHeaderRegions[0].sLeft = 12 + UDBOffsetX; gItemDescGenHeaderRegions[0].sTop = 119 + UDBOffsetY; gItemDescGenHeaderRegions[0].sRight = 126 + UDBOffsetX; gItemDescGenHeaderRegions[0].sBottom = 131 + UDBOffsetY; + + // "Secondary" header (for weapons: "AP costs") + gItemDescGenHeaderRegions[1].sLeft = 128 + UDBOffsetX; gItemDescGenHeaderRegions[1].sTop = 119 + UDBOffsetY; gItemDescGenHeaderRegions[1].sRight = 242 + UDBOffsetX; gItemDescGenHeaderRegions[1].sBottom = 131 + UDBOffsetY; + + // "Burst / Auto" header (for weapons only) + gItemDescGenHeaderRegions[2].sLeft = 128 + UDBOffsetX; gItemDescGenHeaderRegions[2].sTop = 230 + UDBOffsetY; gItemDescGenHeaderRegions[2].sRight = 242 + UDBOffsetX; gItemDescGenHeaderRegions[2].sBottom = 242 + UDBOffsetY; + + /////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB General Page - Index Locations + + // "Primary" index + gItemDescGenIndexRegions[0][0].sLeft = 12 + UDBOffsetX; gItemDescGenIndexRegions[0][0].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[0][0].sRight = 61 + UDBOffsetX; gItemDescGenIndexRegions[0][0].sBottom = 146 + UDBOffsetY; + gItemDescGenIndexRegions[0][1].sLeft = 63 + UDBOffsetX; gItemDescGenIndexRegions[0][1].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[0][1].sRight = 84 + UDBOffsetX; gItemDescGenIndexRegions[0][1].sBottom = 146 + UDBOffsetY; + gItemDescGenIndexRegions[0][2].sLeft = 86 + UDBOffsetX; gItemDescGenIndexRegions[0][2].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[0][2].sRight = 105 + UDBOffsetX; gItemDescGenIndexRegions[0][2].sBottom = 146 + UDBOffsetY; + gItemDescGenIndexRegions[0][3].sLeft = 107 + UDBOffsetX; gItemDescGenIndexRegions[0][3].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[0][3].sRight = 127 + UDBOffsetX; gItemDescGenIndexRegions[0][3].sBottom = 146 + UDBOffsetY; + + // "Secondary" index + gItemDescGenIndexRegions[1][0].sLeft = 130 + UDBOffsetX; gItemDescGenIndexRegions[1][0].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[1][0].sRight = 179 + UDBOffsetX; gItemDescGenIndexRegions[1][0].sBottom = 146 + UDBOffsetY; + gItemDescGenIndexRegions[1][1].sLeft = 181 + UDBOffsetX; gItemDescGenIndexRegions[1][1].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[1][1].sRight = 202 + UDBOffsetX; gItemDescGenIndexRegions[1][1].sBottom = 146 + UDBOffsetY; + gItemDescGenIndexRegions[1][2].sLeft = 204 + UDBOffsetX; gItemDescGenIndexRegions[1][2].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[1][2].sRight = 223 + UDBOffsetX; gItemDescGenIndexRegions[1][2].sBottom = 146 + UDBOffsetY; + gItemDescGenIndexRegions[1][3].sLeft = 225 + UDBOffsetX; gItemDescGenIndexRegions[1][3].sTop = 134 + UDBOffsetY; gItemDescGenIndexRegions[1][3].sRight = 245 + UDBOffsetX; gItemDescGenIndexRegions[1][3].sBottom = 146 + UDBOffsetY; + + // "Tertiary" index (for weapons only) + gItemDescGenIndexRegions[2][0].sLeft = 130 + UDBOffsetX; gItemDescGenIndexRegions[2][0].sTop = 245 + UDBOffsetY; gItemDescGenIndexRegions[2][0].sRight = 179 + UDBOffsetX; gItemDescGenIndexRegions[2][0].sBottom = 257 + UDBOffsetY; + gItemDescGenIndexRegions[2][1].sLeft = 181 + UDBOffsetX; gItemDescGenIndexRegions[2][1].sTop = 245 + UDBOffsetY; gItemDescGenIndexRegions[2][1].sRight = 202 + UDBOffsetX; gItemDescGenIndexRegions[2][1].sBottom = 257 + UDBOffsetY; + gItemDescGenIndexRegions[2][2].sLeft = 204 + UDBOffsetX; gItemDescGenIndexRegions[2][2].sTop = 245 + UDBOffsetY; gItemDescGenIndexRegions[2][2].sRight = 223 + UDBOffsetX; gItemDescGenIndexRegions[2][2].sBottom = 257 + UDBOffsetY; + gItemDescGenIndexRegions[2][3].sLeft = 225 + UDBOffsetX; gItemDescGenIndexRegions[2][3].sTop = 245 + UDBOffsetY; gItemDescGenIndexRegions[2][3].sRight = 245 + UDBOffsetX; gItemDescGenIndexRegions[2][3].sBottom = 257 + UDBOffsetY; + + ////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB General Page - Data locations + // There are NUM_UDB_GEN_LINES*2 lines on the UDB page. Half are on the left side, half + // on the right. Each line has 4 individual parts, see the indexes above. + // The right column is currently only used for WEAPONS. Other item types have their + // own coordinate arrays as they are used to display non-tabulated information. + + // Left Column, row 1 + gItemDescGenRegions[0][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[0][0].sTop = 150 + UDBOffsetY; gItemDescGenRegions[0][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[0][0].sBottom = 162 + UDBOffsetY; + gItemDescGenRegions[0][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[0][1].sTop = 150 + UDBOffsetY; gItemDescGenRegions[0][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[0][1].sBottom = 162 + UDBOffsetY; + gItemDescGenRegions[0][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[0][2].sTop = 150 + UDBOffsetY; gItemDescGenRegions[0][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[0][2].sBottom = 162 + UDBOffsetY; + gItemDescGenRegions[0][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[0][3].sTop = 150 + UDBOffsetY; gItemDescGenRegions[0][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[0][3].sBottom = 162 + UDBOffsetY; + + // Left Column, row 2 + gItemDescGenRegions[1][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[1][0].sTop = 163 + UDBOffsetY; gItemDescGenRegions[1][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[1][0].sBottom = 175 + UDBOffsetY; + gItemDescGenRegions[1][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[1][1].sTop = 163 + UDBOffsetY; gItemDescGenRegions[1][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[1][1].sBottom = 175 + UDBOffsetY; + gItemDescGenRegions[1][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[1][2].sTop = 163 + UDBOffsetY; gItemDescGenRegions[1][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[1][2].sBottom = 175 + UDBOffsetY; + gItemDescGenRegions[1][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[1][3].sTop = 163 + UDBOffsetY; gItemDescGenRegions[1][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[1][3].sBottom = 175 + UDBOffsetY; + + // Left Column, row 3 + gItemDescGenRegions[2][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[2][0].sTop = 176 + UDBOffsetY; gItemDescGenRegions[2][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[2][0].sBottom = 188 + UDBOffsetY; + gItemDescGenRegions[2][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[2][1].sTop = 176 + UDBOffsetY; gItemDescGenRegions[2][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[2][1].sBottom = 188 + UDBOffsetY; + gItemDescGenRegions[2][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[2][2].sTop = 176 + UDBOffsetY; gItemDescGenRegions[2][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[2][2].sBottom = 188 + UDBOffsetY; + gItemDescGenRegions[2][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[2][3].sTop = 176 + UDBOffsetY; gItemDescGenRegions[2][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[2][3].sBottom = 188 + UDBOffsetY; + + // Left Column, row 4 + gItemDescGenRegions[3][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[3][0].sTop = 189 + UDBOffsetY; gItemDescGenRegions[3][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[3][0].sBottom = 201 + UDBOffsetY; + gItemDescGenRegions[3][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[3][1].sTop = 189 + UDBOffsetY; gItemDescGenRegions[3][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[3][1].sBottom = 201 + UDBOffsetY; + gItemDescGenRegions[3][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[3][2].sTop = 189 + UDBOffsetY; gItemDescGenRegions[3][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[3][2].sBottom = 201 + UDBOffsetY; + gItemDescGenRegions[3][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[3][3].sTop = 189 + UDBOffsetY; gItemDescGenRegions[3][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[3][3].sBottom = 201 + UDBOffsetY; + + // Left Column, row 5 + gItemDescGenRegions[4][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[4][0].sTop = 202 + UDBOffsetY; gItemDescGenRegions[4][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[4][0].sBottom = 214 + UDBOffsetY; + gItemDescGenRegions[4][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[4][1].sTop = 202 + UDBOffsetY; gItemDescGenRegions[4][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[4][1].sBottom = 214 + UDBOffsetY; + gItemDescGenRegions[4][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[4][2].sTop = 202 + UDBOffsetY; gItemDescGenRegions[4][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[4][2].sBottom = 214 + UDBOffsetY; + gItemDescGenRegions[4][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[4][3].sTop = 202 + UDBOffsetY; gItemDescGenRegions[4][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[4][3].sBottom = 214 + UDBOffsetY; + + // Left Column, row 6 + gItemDescGenRegions[5][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[5][0].sTop = 215 + UDBOffsetY; gItemDescGenRegions[5][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[5][0].sBottom = 227 + UDBOffsetY; + gItemDescGenRegions[5][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[5][1].sTop = 215 + UDBOffsetY; gItemDescGenRegions[5][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[5][1].sBottom = 227 + UDBOffsetY; + gItemDescGenRegions[5][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[5][2].sTop = 215 + UDBOffsetY; gItemDescGenRegions[5][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[5][2].sBottom = 227 + UDBOffsetY; + gItemDescGenRegions[5][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[5][3].sTop = 215 + UDBOffsetY; gItemDescGenRegions[5][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[5][3].sBottom = 227 + UDBOffsetY; + + // Left Column, row 7 + gItemDescGenRegions[6][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[6][0].sTop = 228 + UDBOffsetY; gItemDescGenRegions[6][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[6][0].sBottom = 242 + UDBOffsetY; + gItemDescGenRegions[6][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[6][1].sTop = 228 + UDBOffsetY; gItemDescGenRegions[6][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[6][1].sBottom = 242 + UDBOffsetY; + gItemDescGenRegions[6][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[6][2].sTop = 228 + UDBOffsetY; gItemDescGenRegions[6][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[6][2].sBottom = 242 + UDBOffsetY; + gItemDescGenRegions[6][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[6][3].sTop = 228 + UDBOffsetY; gItemDescGenRegions[6][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[6][3].sBottom = 242 + UDBOffsetY; + + // Left Column, row 8 + gItemDescGenRegions[7][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[7][0].sTop = 243 + UDBOffsetY; gItemDescGenRegions[7][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[7][0].sBottom = 255 + UDBOffsetY; + gItemDescGenRegions[7][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[7][1].sTop = 243 + UDBOffsetY; gItemDescGenRegions[7][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[7][1].sBottom = 255 + UDBOffsetY; + gItemDescGenRegions[7][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[7][2].sTop = 243 + UDBOffsetY; gItemDescGenRegions[7][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[7][2].sBottom = 255 + UDBOffsetY; + gItemDescGenRegions[7][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[7][3].sTop = 243 + UDBOffsetY; gItemDescGenRegions[7][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[7][3].sBottom = 255 + UDBOffsetY; + + // Left Column, row 9 + gItemDescGenRegions[8][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[8][0].sTop = 256 + UDBOffsetY; gItemDescGenRegions[8][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[8][0].sBottom = 268 + UDBOffsetY; + gItemDescGenRegions[8][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[8][1].sTop = 256 + UDBOffsetY; gItemDescGenRegions[8][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[8][1].sBottom = 268 + UDBOffsetY; + gItemDescGenRegions[8][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[8][2].sTop = 256 + UDBOffsetY; gItemDescGenRegions[8][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[8][2].sBottom = 268 + UDBOffsetY; + gItemDescGenRegions[8][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[8][3].sTop = 256 + UDBOffsetY; gItemDescGenRegions[8][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[8][3].sBottom = 268 + UDBOffsetY; + + // Left Column, row 10 + gItemDescGenRegions[9][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[9][0].sTop = 269 + UDBOffsetY; gItemDescGenRegions[9][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[9][0].sBottom = 281 + UDBOffsetY; + gItemDescGenRegions[9][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[9][1].sTop = 269 + UDBOffsetY; gItemDescGenRegions[9][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[9][1].sBottom = 281 + UDBOffsetY; + gItemDescGenRegions[9][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[9][2].sTop = 269 + UDBOffsetY; gItemDescGenRegions[9][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[9][2].sBottom = 281 + UDBOffsetY; + gItemDescGenRegions[9][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[9][3].sTop = 269 + UDBOffsetY; gItemDescGenRegions[9][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[9][3].sBottom = 281 + UDBOffsetY; + + // Left Column, row 11 + gItemDescGenRegions[10][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[10][0].sTop = 282 + UDBOffsetY; gItemDescGenRegions[10][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[10][0].sBottom = 294 + UDBOffsetY; + gItemDescGenRegions[10][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[10][1].sTop = 282 + UDBOffsetY; gItemDescGenRegions[10][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[10][1].sBottom = 294 + UDBOffsetY; + gItemDescGenRegions[10][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[10][2].sTop = 282 + UDBOffsetY; gItemDescGenRegions[10][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[10][2].sBottom = 294 + UDBOffsetY; + gItemDescGenRegions[10][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[10][3].sTop = 282 + UDBOffsetY; gItemDescGenRegions[10][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[10][3].sBottom = 294 + UDBOffsetY; + + // Left Column, row 12 + gItemDescGenRegions[11][0].sLeft = 12 + UDBOffsetX; gItemDescGenRegions[11][0].sTop = 295 + UDBOffsetY; gItemDescGenRegions[11][0].sRight = 61 + UDBOffsetX; gItemDescGenRegions[11][0].sBottom = 307 + UDBOffsetY; + gItemDescGenRegions[11][1].sLeft = 63 + UDBOffsetX; gItemDescGenRegions[11][1].sTop = 295 + UDBOffsetY; gItemDescGenRegions[11][1].sRight = 84 + UDBOffsetX; gItemDescGenRegions[11][1].sBottom = 307 + UDBOffsetY; + gItemDescGenRegions[11][2].sLeft = 86 + UDBOffsetX; gItemDescGenRegions[11][2].sTop = 295 + UDBOffsetY; gItemDescGenRegions[11][2].sRight = 105 + UDBOffsetX; gItemDescGenRegions[11][2].sBottom = 307 + UDBOffsetY; + gItemDescGenRegions[11][3].sLeft = 107 + UDBOffsetX; gItemDescGenRegions[11][3].sTop = 295 + UDBOffsetY; gItemDescGenRegions[11][3].sRight = 127 + UDBOffsetX; gItemDescGenRegions[11][3].sBottom = 307 + UDBOffsetY; + + // Right Column, row 1 + gItemDescGenRegions[13][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[13][0].sTop = 150 + UDBOffsetY; gItemDescGenRegions[13][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[13][0].sBottom = 162 + UDBOffsetY; + gItemDescGenRegions[13][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[13][1].sTop = 150 + UDBOffsetY; gItemDescGenRegions[13][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[13][1].sBottom = 162 + UDBOffsetY; + gItemDescGenRegions[13][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[13][2].sTop = 150 + UDBOffsetY; gItemDescGenRegions[13][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[13][2].sBottom = 162 + UDBOffsetY; + gItemDescGenRegions[13][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[13][3].sTop = 150 + UDBOffsetY; gItemDescGenRegions[13][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[13][3].sBottom = 162 + UDBOffsetY; + + // Right Column, row 2 + gItemDescGenRegions[14][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[14][0].sTop = 163 + UDBOffsetY; gItemDescGenRegions[14][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[14][0].sBottom = 175 + UDBOffsetY; + gItemDescGenRegions[14][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[14][1].sTop = 163 + UDBOffsetY; gItemDescGenRegions[14][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[14][1].sBottom = 175 + UDBOffsetY; + gItemDescGenRegions[14][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[14][2].sTop = 163 + UDBOffsetY; gItemDescGenRegions[14][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[14][2].sBottom = 175 + UDBOffsetY; + gItemDescGenRegions[14][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[14][3].sTop = 163 + UDBOffsetY; gItemDescGenRegions[14][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[14][3].sBottom = 175 + UDBOffsetY; + + // Right Column, row 3 + gItemDescGenRegions[15][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[15][0].sTop = 176 + UDBOffsetY; gItemDescGenRegions[15][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[15][0].sBottom = 188 + UDBOffsetY; + gItemDescGenRegions[15][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[15][1].sTop = 176 + UDBOffsetY; gItemDescGenRegions[15][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[15][1].sBottom = 188 + UDBOffsetY; + gItemDescGenRegions[15][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[15][2].sTop = 176 + UDBOffsetY; gItemDescGenRegions[15][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[15][2].sBottom = 188 + UDBOffsetY; + gItemDescGenRegions[15][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[15][3].sTop = 176 + UDBOffsetY; gItemDescGenRegions[15][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[15][3].sBottom = 188 + UDBOffsetY; + + // Right Column, row 4 + gItemDescGenRegions[16][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[16][0].sTop = 189 + UDBOffsetY; gItemDescGenRegions[16][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[16][0].sBottom = 201 + UDBOffsetY; + gItemDescGenRegions[16][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[16][1].sTop = 189 + UDBOffsetY; gItemDescGenRegions[16][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[16][1].sBottom = 201 + UDBOffsetY; + gItemDescGenRegions[16][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[16][2].sTop = 189 + UDBOffsetY; gItemDescGenRegions[16][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[16][2].sBottom = 201 + UDBOffsetY; + gItemDescGenRegions[16][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[16][3].sTop = 189 + UDBOffsetY; gItemDescGenRegions[16][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[16][3].sBottom = 201 + UDBOffsetY; + + // Right Column, row 5 + gItemDescGenRegions[17][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[17][0].sTop = 202 + UDBOffsetY; gItemDescGenRegions[17][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[17][0].sBottom = 214 + UDBOffsetY; + gItemDescGenRegions[17][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[17][1].sTop = 202 + UDBOffsetY; gItemDescGenRegions[17][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[17][1].sBottom = 214 + UDBOffsetY; + gItemDescGenRegions[17][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[17][2].sTop = 202 + UDBOffsetY; gItemDescGenRegions[17][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[17][2].sBottom = 214 + UDBOffsetY; + gItemDescGenRegions[17][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[17][3].sTop = 202 + UDBOffsetY; gItemDescGenRegions[17][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[17][3].sBottom = 214 + UDBOffsetY; + + // Right Column, row 6 + gItemDescGenRegions[18][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[18][0].sTop = 215 + UDBOffsetY; gItemDescGenRegions[18][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[18][0].sBottom = 227 + UDBOffsetY; + gItemDescGenRegions[18][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[18][1].sTop = 215 + UDBOffsetY; gItemDescGenRegions[18][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[18][1].sBottom = 227 + UDBOffsetY; + gItemDescGenRegions[18][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[18][2].sTop = 215 + UDBOffsetY; gItemDescGenRegions[18][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[18][2].sBottom = 227 + UDBOffsetY; + gItemDescGenRegions[18][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[18][3].sTop = 215 + UDBOffsetY; gItemDescGenRegions[18][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[18][3].sBottom = 227 + UDBOffsetY; + + // NOTE a skip of Y here - these belong to the "tertiary" column, which is below the "secondary" column, separated by an index and header. + // Right Column, row 7 + gItemDescGenRegions[19][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[19][0].sTop = 261 + UDBOffsetY; gItemDescGenRegions[19][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[19][0].sBottom = 273 + UDBOffsetY; + gItemDescGenRegions[19][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[19][1].sTop = 261 + UDBOffsetY; gItemDescGenRegions[19][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[19][1].sBottom = 273 + UDBOffsetY; + gItemDescGenRegions[19][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[19][2].sTop = 261 + UDBOffsetY; gItemDescGenRegions[19][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[19][2].sBottom = 273 + UDBOffsetY; + gItemDescGenRegions[19][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[19][3].sTop = 261 + UDBOffsetY; gItemDescGenRegions[19][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[19][3].sBottom = 273 + UDBOffsetY; + + // Right Column, row 8 + gItemDescGenRegions[20][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[20][0].sTop = 274 + UDBOffsetY; gItemDescGenRegions[20][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[20][0].sBottom = 286 + UDBOffsetY; + gItemDescGenRegions[20][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[20][1].sTop = 274 + UDBOffsetY; gItemDescGenRegions[20][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[20][1].sBottom = 286 + UDBOffsetY; + gItemDescGenRegions[20][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[20][2].sTop = 274 + UDBOffsetY; gItemDescGenRegions[20][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[20][2].sBottom = 286 + UDBOffsetY; + gItemDescGenRegions[20][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[20][3].sTop = 274 + UDBOffsetY; gItemDescGenRegions[20][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[20][3].sBottom = 286 + UDBOffsetY; + + // Right Column, row 9 + gItemDescGenRegions[21][0].sLeft = 130 + UDBOffsetX; gItemDescGenRegions[21][0].sTop = 287 + UDBOffsetY; gItemDescGenRegions[21][0].sRight = 179 + UDBOffsetX; gItemDescGenRegions[21][0].sBottom = 299 + UDBOffsetY; + gItemDescGenRegions[21][1].sLeft = 181 + UDBOffsetX; gItemDescGenRegions[21][1].sTop = 287 + UDBOffsetY; gItemDescGenRegions[21][1].sRight = 202 + UDBOffsetX; gItemDescGenRegions[21][1].sBottom = 299 + UDBOffsetY; + gItemDescGenRegions[21][2].sLeft = 204 + UDBOffsetX; gItemDescGenRegions[21][2].sTop = 287 + UDBOffsetY; gItemDescGenRegions[21][2].sRight = 223 + UDBOffsetX; gItemDescGenRegions[21][2].sBottom = 299 + UDBOffsetY; + gItemDescGenRegions[21][3].sLeft = 225 + UDBOffsetX; gItemDescGenRegions[21][3].sTop = 287 + UDBOffsetY; gItemDescGenRegions[21][3].sRight = 245 + UDBOffsetX; gItemDescGenRegions[21][3].sBottom = 299 + UDBOffsetY; + + /////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB General Page - Secondary Data locations + // These icons will appear on the RIGHT columns of the general page. The are larger + // than the normal icons, and indicate flags. Armor, Ammo and Misc Items will use + // these to display special flag properties like "Electronic" or "Tracer effect". + + // First row + gItemDescGenSecondaryRegions[0].sLeft = 131 + UDBOffsetX; gItemDescGenSecondaryRegions[0].sTop = 135 + UDBOffsetY; gItemDescGenSecondaryRegions[0].sRight = 156 + UDBOffsetX; gItemDescGenSecondaryRegions[0].sBottom = 160 + UDBOffsetY; + gItemDescGenSecondaryRegions[1].sLeft = 159 + UDBOffsetX; gItemDescGenSecondaryRegions[1].sTop = 135 + UDBOffsetY; gItemDescGenSecondaryRegions[1].sRight = 184 + UDBOffsetX; gItemDescGenSecondaryRegions[1].sBottom = 160 + UDBOffsetY; + gItemDescGenSecondaryRegions[2].sLeft = 187 + UDBOffsetX; gItemDescGenSecondaryRegions[2].sTop = 135 + UDBOffsetY; gItemDescGenSecondaryRegions[2].sRight = 212 + UDBOffsetX; gItemDescGenSecondaryRegions[2].sBottom = 160 + UDBOffsetY; + gItemDescGenSecondaryRegions[3].sLeft = 215 + UDBOffsetX; gItemDescGenSecondaryRegions[3].sTop = 135 + UDBOffsetY; gItemDescGenSecondaryRegions[3].sRight = 240 + UDBOffsetX; gItemDescGenSecondaryRegions[3].sBottom = 160 + UDBOffsetY; + + // Second row + gItemDescGenSecondaryRegions[4].sLeft = 131 + UDBOffsetX; gItemDescGenSecondaryRegions[4].sTop = 163 + UDBOffsetY; gItemDescGenSecondaryRegions[4].sRight = 156 + UDBOffsetX; gItemDescGenSecondaryRegions[4].sBottom = 188 + UDBOffsetY; + gItemDescGenSecondaryRegions[5].sLeft = 159 + UDBOffsetX; gItemDescGenSecondaryRegions[5].sTop = 163 + UDBOffsetY; gItemDescGenSecondaryRegions[5].sRight = 184 + UDBOffsetX; gItemDescGenSecondaryRegions[5].sBottom = 188 + UDBOffsetY; + gItemDescGenSecondaryRegions[6].sLeft = 187 + UDBOffsetX; gItemDescGenSecondaryRegions[6].sTop = 163 + UDBOffsetY; gItemDescGenSecondaryRegions[6].sRight = 212 + UDBOffsetX; gItemDescGenSecondaryRegions[6].sBottom = 188 + UDBOffsetY; + gItemDescGenSecondaryRegions[7].sLeft = 215 + UDBOffsetX; gItemDescGenSecondaryRegions[7].sTop = 163 + UDBOffsetY; gItemDescGenSecondaryRegions[7].sRight = 240 + UDBOffsetX; gItemDescGenSecondaryRegions[7].sBottom = 188 + UDBOffsetY; + + // Third row + + gItemDescGenSecondaryRegions[8].sLeft = 131 + UDBOffsetX; gItemDescGenSecondaryRegions[8].sTop = 191 + UDBOffsetY; gItemDescGenSecondaryRegions[8].sRight = 156 + UDBOffsetX; gItemDescGenSecondaryRegions[8].sBottom = 216 + UDBOffsetY; + gItemDescGenSecondaryRegions[9].sLeft = 159 + UDBOffsetX; gItemDescGenSecondaryRegions[9].sTop = 191 + UDBOffsetY; gItemDescGenSecondaryRegions[9].sRight = 184 + UDBOffsetX; gItemDescGenSecondaryRegions[9].sBottom = 216 + UDBOffsetY; + gItemDescGenSecondaryRegions[10].sLeft = 187 + UDBOffsetX; gItemDescGenSecondaryRegions[10].sTop = 191 + UDBOffsetY; gItemDescGenSecondaryRegions[10].sRight = 212 + UDBOffsetX; gItemDescGenSecondaryRegions[10].sBottom = 216 + UDBOffsetY; + gItemDescGenSecondaryRegions[11].sLeft = 215 + UDBOffsetX; gItemDescGenSecondaryRegions[11].sTop = 191 + UDBOffsetY; gItemDescGenSecondaryRegions[11].sRight = 240 + UDBOffsetX; gItemDescGenSecondaryRegions[11].sBottom = 216 + UDBOffsetY; + + // Fourth row + gItemDescGenSecondaryRegions[12].sLeft = 131 + UDBOffsetX; gItemDescGenSecondaryRegions[12].sTop = 219 + UDBOffsetY; gItemDescGenSecondaryRegions[12].sRight = 156 + UDBOffsetX; gItemDescGenSecondaryRegions[12].sBottom = 244 + UDBOffsetY; + gItemDescGenSecondaryRegions[13].sLeft = 159 + UDBOffsetX; gItemDescGenSecondaryRegions[13].sTop = 219 + UDBOffsetY; gItemDescGenSecondaryRegions[13].sRight = 184 + UDBOffsetX; gItemDescGenSecondaryRegions[13].sBottom = 244 + UDBOffsetY; + gItemDescGenSecondaryRegions[14].sLeft = 187 + UDBOffsetX; gItemDescGenSecondaryRegions[14].sTop = 219 + UDBOffsetY; gItemDescGenSecondaryRegions[14].sRight = 212 + UDBOffsetX; gItemDescGenSecondaryRegions[14].sBottom = 244 + UDBOffsetY; + gItemDescGenSecondaryRegions[15].sLeft = 215 + UDBOffsetX; gItemDescGenSecondaryRegions[15].sTop = 219 + UDBOffsetY; gItemDescGenSecondaryRegions[15].sRight = 240 + UDBOffsetX; gItemDescGenSecondaryRegions[15].sBottom = 244 + UDBOffsetY; + + // Fifth row + gItemDescGenSecondaryRegions[16].sLeft = 131 + UDBOffsetX; gItemDescGenSecondaryRegions[16].sTop = 247 + UDBOffsetY; gItemDescGenSecondaryRegions[16].sRight = 156 + UDBOffsetX; gItemDescGenSecondaryRegions[16].sBottom = 272 + UDBOffsetY; + gItemDescGenSecondaryRegions[17].sLeft = 159 + UDBOffsetX; gItemDescGenSecondaryRegions[17].sTop = 247 + UDBOffsetY; gItemDescGenSecondaryRegions[17].sRight = 184 + UDBOffsetX; gItemDescGenSecondaryRegions[17].sBottom = 272 + UDBOffsetY; + gItemDescGenSecondaryRegions[18].sLeft = 187 + UDBOffsetX; gItemDescGenSecondaryRegions[18].sTop = 247 + UDBOffsetY; gItemDescGenSecondaryRegions[18].sRight = 212 + UDBOffsetX; gItemDescGenSecondaryRegions[18].sBottom = 272 + UDBOffsetY; + gItemDescGenSecondaryRegions[19].sLeft = 215 + UDBOffsetX; gItemDescGenSecondaryRegions[19].sTop = 247 + UDBOffsetY; gItemDescGenSecondaryRegions[19].sRight = 240 + UDBOffsetX; gItemDescGenSecondaryRegions[19].sBottom = 272 + UDBOffsetY; + + // Sixth row + gItemDescGenSecondaryRegions[20].sLeft = 131 + UDBOffsetX; gItemDescGenSecondaryRegions[20].sTop = 275 + UDBOffsetY; gItemDescGenSecondaryRegions[20].sRight = 156 + UDBOffsetX; gItemDescGenSecondaryRegions[20].sBottom = 300 + UDBOffsetY; + gItemDescGenSecondaryRegions[21].sLeft = 159 + UDBOffsetX; gItemDescGenSecondaryRegions[21].sTop = 275 + UDBOffsetY; gItemDescGenSecondaryRegions[21].sRight = 184 + UDBOffsetX; gItemDescGenSecondaryRegions[21].sBottom = 300 + UDBOffsetY; + gItemDescGenSecondaryRegions[22].sLeft = 187 + UDBOffsetX; gItemDescGenSecondaryRegions[22].sTop = 275 + UDBOffsetY; gItemDescGenSecondaryRegions[22].sRight = 212 + UDBOffsetX; gItemDescGenSecondaryRegions[22].sBottom = 300 + UDBOffsetY; + gItemDescGenSecondaryRegions[23].sLeft = 215 + UDBOffsetX; gItemDescGenSecondaryRegions[23].sTop = 275 + UDBOffsetY; gItemDescGenSecondaryRegions[23].sRight = 240 + UDBOffsetX; gItemDescGenSecondaryRegions[23].sBottom = 300 + UDBOffsetY; + + /////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB Advanced Page + // The set of data appears on the third UDB page. It shows bonuses given by items either + // to other items (through attachment/ammo) or directly to the person wearing/using + // the item. + // Each row contains 4 elements, the first being the icon position, and then + // one element per stance (Standing, crouching, prone). + + /////////// INDEX + gItemDescAdvIndexRegions[0][0].sLeft = 12 + UDBOffsetX; gItemDescAdvIndexRegions[0][0].sTop = 119 + UDBOffsetY; gItemDescAdvIndexRegions[0][0].sRight = 125 + UDBOffsetX; gItemDescAdvIndexRegions[0][0].sBottom = 132 + UDBOffsetY; + gItemDescAdvIndexRegions[0][1].sLeft = 128 + UDBOffsetX; gItemDescAdvIndexRegions[0][1].sTop = 119 + UDBOffsetY; gItemDescAdvIndexRegions[0][1].sRight = 157 + UDBOffsetX; gItemDescAdvIndexRegions[0][1].sBottom = 132 + UDBOffsetY; + gItemDescAdvIndexRegions[0][2].sLeft = 160 + UDBOffsetX; gItemDescAdvIndexRegions[0][2].sTop = 119 + UDBOffsetY; gItemDescAdvIndexRegions[0][2].sRight = 189 + UDBOffsetX; gItemDescAdvIndexRegions[0][2].sBottom = 132 + UDBOffsetY; + gItemDescAdvIndexRegions[0][3].sLeft = 193 + UDBOffsetX; gItemDescAdvIndexRegions[0][3].sTop = 119 + UDBOffsetY; gItemDescAdvIndexRegions[0][3].sRight = 220 + UDBOffsetX; gItemDescAdvIndexRegions[0][3].sBottom = 132 + UDBOffsetY; + + gItemDescAdvRegions[0][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[0][0].sTop = 138 + UDBOffsetY; gItemDescAdvRegions[0][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[0][0].sBottom = 150 + UDBOffsetY; + gItemDescAdvRegions[0][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[0][1].sTop = 138 + UDBOffsetY; gItemDescAdvRegions[0][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[0][1].sBottom = 150 + UDBOffsetY; + gItemDescAdvRegions[0][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[0][2].sTop = 138 + UDBOffsetY; gItemDescAdvRegions[0][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[0][2].sBottom = 150 + UDBOffsetY; + gItemDescAdvRegions[0][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[0][3].sTop = 138 + UDBOffsetY; gItemDescAdvRegions[0][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[0][3].sBottom = 150 + UDBOffsetY; + + gItemDescAdvRegions[1][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[1][0].sTop = 151 + UDBOffsetY; gItemDescAdvRegions[1][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[1][0].sBottom = 163 + UDBOffsetY; + gItemDescAdvRegions[1][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[1][1].sTop = 151 + UDBOffsetY; gItemDescAdvRegions[1][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[1][1].sBottom = 163 + UDBOffsetY; + gItemDescAdvRegions[1][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[1][2].sTop = 151 + UDBOffsetY; gItemDescAdvRegions[1][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[1][2].sBottom = 163 + UDBOffsetY; + gItemDescAdvRegions[1][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[1][3].sTop = 151 + UDBOffsetY; gItemDescAdvRegions[1][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[1][3].sBottom = 163 + UDBOffsetY; + + gItemDescAdvRegions[2][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[2][0].sTop = 164 + UDBOffsetY; gItemDescAdvRegions[2][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[2][0].sBottom = 176 + UDBOffsetY; + gItemDescAdvRegions[2][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[2][1].sTop = 164 + UDBOffsetY; gItemDescAdvRegions[2][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[2][1].sBottom = 176 + UDBOffsetY; + gItemDescAdvRegions[2][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[2][2].sTop = 164 + UDBOffsetY; gItemDescAdvRegions[2][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[2][2].sBottom = 176 + UDBOffsetY; + gItemDescAdvRegions[2][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[2][3].sTop = 164 + UDBOffsetY; gItemDescAdvRegions[2][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[2][3].sBottom = 176 + UDBOffsetY; + + gItemDescAdvRegions[3][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[3][0].sTop = 177 + UDBOffsetY; gItemDescAdvRegions[3][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[3][0].sBottom = 189 + UDBOffsetY; + gItemDescAdvRegions[3][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[3][1].sTop = 177 + UDBOffsetY; gItemDescAdvRegions[3][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[3][1].sBottom = 189 + UDBOffsetY; + gItemDescAdvRegions[3][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[3][2].sTop = 177 + UDBOffsetY; gItemDescAdvRegions[3][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[3][2].sBottom = 189 + UDBOffsetY; + gItemDescAdvRegions[3][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[3][3].sTop = 177 + UDBOffsetY; gItemDescAdvRegions[3][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[3][3].sBottom = 189 + UDBOffsetY; + + gItemDescAdvRegions[4][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[4][0].sTop = 190 + UDBOffsetY; gItemDescAdvRegions[4][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[4][0].sBottom = 202 + UDBOffsetY; + gItemDescAdvRegions[4][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[4][1].sTop = 190 + UDBOffsetY; gItemDescAdvRegions[4][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[4][1].sBottom = 202 + UDBOffsetY; + gItemDescAdvRegions[4][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[4][2].sTop = 190 + UDBOffsetY; gItemDescAdvRegions[4][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[4][2].sBottom = 202 + UDBOffsetY; + gItemDescAdvRegions[4][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[4][3].sTop = 190 + UDBOffsetY; gItemDescAdvRegions[4][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[4][3].sBottom = 202 + UDBOffsetY; + + gItemDescAdvRegions[5][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[5][0].sTop = 203 + UDBOffsetY; gItemDescAdvRegions[5][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[5][0].sBottom = 215 + UDBOffsetY; + gItemDescAdvRegions[5][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[5][1].sTop = 203 + UDBOffsetY; gItemDescAdvRegions[5][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[5][1].sBottom = 215 + UDBOffsetY; + gItemDescAdvRegions[5][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[5][2].sTop = 203 + UDBOffsetY; gItemDescAdvRegions[5][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[5][2].sBottom = 215 + UDBOffsetY; + gItemDescAdvRegions[5][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[5][3].sTop = 203 + UDBOffsetY; gItemDescAdvRegions[5][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[5][3].sBottom = 215 + UDBOffsetY; + + gItemDescAdvRegions[6][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[6][0].sTop = 216 + UDBOffsetY; gItemDescAdvRegions[6][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[6][0].sBottom = 228 + UDBOffsetY; + gItemDescAdvRegions[6][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[6][1].sTop = 216 + UDBOffsetY; gItemDescAdvRegions[6][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[6][1].sBottom = 228 + UDBOffsetY; + gItemDescAdvRegions[6][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[6][2].sTop = 216 + UDBOffsetY; gItemDescAdvRegions[6][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[6][2].sBottom = 228 + UDBOffsetY; + gItemDescAdvRegions[6][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[6][3].sTop = 216 + UDBOffsetY; gItemDescAdvRegions[6][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[6][3].sBottom = 228 + UDBOffsetY; + + gItemDescAdvRegions[7][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[7][0].sTop = 229 + UDBOffsetY; gItemDescAdvRegions[7][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[7][0].sBottom = 241 + UDBOffsetY; + gItemDescAdvRegions[7][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[7][1].sTop = 229 + UDBOffsetY; gItemDescAdvRegions[7][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[7][1].sBottom = 241 + UDBOffsetY; + gItemDescAdvRegions[7][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[7][2].sTop = 229 + UDBOffsetY; gItemDescAdvRegions[7][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[7][2].sBottom = 241 + UDBOffsetY; + gItemDescAdvRegions[7][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[7][3].sTop = 229 + UDBOffsetY; gItemDescAdvRegions[7][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[7][3].sBottom = 241 + UDBOffsetY; + + gItemDescAdvRegions[8][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[8][0].sTop = 242 + UDBOffsetY; gItemDescAdvRegions[8][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[8][0].sBottom = 254 + UDBOffsetY; + gItemDescAdvRegions[8][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[8][1].sTop = 242 + UDBOffsetY; gItemDescAdvRegions[8][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[8][1].sBottom = 254 + UDBOffsetY; + gItemDescAdvRegions[8][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[8][2].sTop = 242 + UDBOffsetY; gItemDescAdvRegions[8][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[8][2].sBottom = 254 + UDBOffsetY; + gItemDescAdvRegions[8][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[8][3].sTop = 242 + UDBOffsetY; gItemDescAdvRegions[8][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[8][3].sBottom = 254 + UDBOffsetY; + + gItemDescAdvRegions[9][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[9][0].sTop = 255 + UDBOffsetY; gItemDescAdvRegions[9][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[9][0].sBottom = 267 + UDBOffsetY; + gItemDescAdvRegions[9][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[9][1].sTop = 255 + UDBOffsetY; gItemDescAdvRegions[9][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[9][1].sBottom = 267 + UDBOffsetY; + gItemDescAdvRegions[9][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[9][2].sTop = 255 + UDBOffsetY; gItemDescAdvRegions[9][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[9][2].sBottom = 267 + UDBOffsetY; + gItemDescAdvRegions[9][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[9][3].sTop = 255 + UDBOffsetY; gItemDescAdvRegions[9][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[9][3].sBottom = 267 + UDBOffsetY; + + gItemDescAdvRegions[10][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[10][0].sTop = 268 + UDBOffsetY; gItemDescAdvRegions[10][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[10][0].sBottom = 280 + UDBOffsetY; + gItemDescAdvRegions[10][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[10][1].sTop = 268 + UDBOffsetY; gItemDescAdvRegions[10][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[10][1].sBottom = 280 + UDBOffsetY; + gItemDescAdvRegions[10][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[10][2].sTop = 268 + UDBOffsetY; gItemDescAdvRegions[10][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[10][2].sBottom = 280 + UDBOffsetY; + gItemDescAdvRegions[10][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[10][3].sTop = 268 + UDBOffsetY; gItemDescAdvRegions[10][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[10][3].sBottom = 280 + UDBOffsetY; + + gItemDescAdvRegions[11][0].sLeft = 12 + UDBOffsetX; gItemDescAdvRegions[11][0].sTop = 281 + UDBOffsetY; gItemDescAdvRegions[11][0].sRight = 126 + UDBOffsetX; gItemDescAdvRegions[11][0].sBottom = 293 + UDBOffsetY; + gItemDescAdvRegions[11][1].sLeft = 130 + UDBOffsetX; gItemDescAdvRegions[11][1].sTop = 281 + UDBOffsetY; gItemDescAdvRegions[11][1].sRight = 157 + UDBOffsetX; gItemDescAdvRegions[11][1].sBottom = 293 + UDBOffsetY; + gItemDescAdvRegions[11][2].sLeft = 162 + UDBOffsetX; gItemDescAdvRegions[11][2].sTop = 281 + UDBOffsetY; gItemDescAdvRegions[11][2].sRight = 189 + UDBOffsetX; gItemDescAdvRegions[11][2].sBottom = 293 + UDBOffsetY; + gItemDescAdvRegions[11][3].sLeft = 194 + UDBOffsetX; gItemDescAdvRegions[11][3].sTop = 281 + UDBOffsetY; gItemDescAdvRegions[11][3].sRight = 221 + UDBOffsetX; gItemDescAdvRegions[11][3].sBottom = 293 + UDBOffsetY; } - else + else // ODB { - if (UsingEDBSystem() == 1) + /////////////////////////////////////////////////////////// + // HEADROCK HAM 4: UDB LBE background coordinates + // These depend on Strategic/Tactical... + if (guiCurrentScreen == MAP_SCREEN) { - // Icon Locations - gMiscItemStatsEDB[0].sX = 203; gMiscItemStatsEDB[0].sY = 44; gMiscItemStatsEDB[0].sValDx = 0; // 0) COL 1; ROW 1 - gMiscItemStatsEDB[1].sX = 203; gMiscItemStatsEDB[1].sY = 56; gMiscItemStatsEDB[1].sValDx = 0; // 1) COL 1; ROW 2 - gMiscItemStatsEDB[2].sX = 203; gMiscItemStatsEDB[2].sY = 68; gMiscItemStatsEDB[2].sValDx = 0; // 2) COL 1; ROW 3 - gMiscItemStatsEDB[3].sX = 203; gMiscItemStatsEDB[3].sY = 80; gMiscItemStatsEDB[3].sValDx = 0; // 3) COL 1; ROW 4 - gMiscItemStatsEDB[4].sX = 203; gMiscItemStatsEDB[4].sY = 92; gMiscItemStatsEDB[4].sValDx = 0; // 4) COL 1; ROW 5 - gMiscItemStatsEDB[5].sX = 203; gMiscItemStatsEDB[5].sY = 104; gMiscItemStatsEDB[5].sValDx = 0; // 5) COL 1; ROW 6 - gMiscItemStatsEDB[6].sX = 203; gMiscItemStatsEDB[6].sY = 116; gMiscItemStatsEDB[6].sValDx = 0; // 6) COL 1; ROW 7 - gMiscItemStatsEDB[7].sX = 203; gMiscItemStatsEDB[7].sY = 128; gMiscItemStatsEDB[7].sValDx = 0; // 7) COL 1; ROW 8 - gMiscItemStatsEDB[8].sX = 203; gMiscItemStatsEDB[8].sY = 140; gMiscItemStatsEDB[8].sValDx = 0; // 8) COL 1; ROW 9 - gMiscItemStatsEDB[9].sX = 203; gMiscItemStatsEDB[9].sY = 152; gMiscItemStatsEDB[9].sValDx = 0; // 9) COL 1; ROW 10 - gMiscItemStatsEDB[10].sX = 203; gMiscItemStatsEDB[10].sY = 164; gMiscItemStatsEDB[10].sValDx = 0; // 10) COL 1; ROW 11 - gMiscItemStatsEDB[11].sX = 203; gMiscItemStatsEDB[11].sY = 176; gMiscItemStatsEDB[11].sValDx = 0; // 11) COL 1; ROW 12 - // EQUALS signs Locations - gMiscItemStatsEDB[12].sX = 283; gMiscItemStatsEDB[12].sY = 44; gMiscItemStatsEDB[12].sValDx = 12; // 12) COL 1; ROW 1 - gMiscItemStatsEDB[13].sX = 283; gMiscItemStatsEDB[13].sY = 56; gMiscItemStatsEDB[13].sValDx = 12; // 13) COL 1; ROW 2 - gMiscItemStatsEDB[14].sX = 283; gMiscItemStatsEDB[14].sY = 68; gMiscItemStatsEDB[14].sValDx = 12; // 14) COL 1; ROW 3 - gMiscItemStatsEDB[15].sX = 283; gMiscItemStatsEDB[15].sY = 80; gMiscItemStatsEDB[15].sValDx = 12; // 15) COL 1; ROW 4 - gMiscItemStatsEDB[16].sX = 283; gMiscItemStatsEDB[16].sY = 92; gMiscItemStatsEDB[16].sValDx = 12; // 16) COL 1; ROW 5 - gMiscItemStatsEDB[17].sX = 283; gMiscItemStatsEDB[17].sY = 104; gMiscItemStatsEDB[17].sValDx = 12; // 17) COL 1; ROW 6 - gMiscItemStatsEDB[18].sX = 283; gMiscItemStatsEDB[18].sY = 116; gMiscItemStatsEDB[18].sValDx = 12; // 18) COL 1; ROW 7 - gMiscItemStatsEDB[19].sX = 283; gMiscItemStatsEDB[19].sY = 128; gMiscItemStatsEDB[19].sValDx = 12; // 19) COL 1; ROW 8 - gMiscItemStatsEDB[20].sX = 283; gMiscItemStatsEDB[20].sY = 140; gMiscItemStatsEDB[20].sValDx = 12; // 20) COL 1; ROW 9 - gMiscItemStatsEDB[21].sX = 283; gMiscItemStatsEDB[21].sY = 152; gMiscItemStatsEDB[21].sValDx = 12; // 21) COL 1; ROW 10 - gMiscItemStatsEDB[22].sX = 283; gMiscItemStatsEDB[22].sY = 164; gMiscItemStatsEDB[22].sValDx = 12; // 22) COL 1; ROW 11 - gMiscItemStatsEDB[23].sX = 283; gMiscItemStatsEDB[23].sY = 176; gMiscItemStatsEDB[23].sValDx = 12; // 23) COL 1; ROW 12 - // MISC - gMiscItemStatsEDB[24].sX = 0; gMiscItemStatsEDB[24].sY = 0; gMiscItemStatsEDB[24].sValDx = 0; - gMiscItemStatsEDB[25].sX = 0; gMiscItemStatsEDB[25].sY = 0; gMiscItemStatsEDB[25].sValDx = 0; - gMiscItemStatsEDB[26].sX = 0; gMiscItemStatsEDB[26].sY = 0; gMiscItemStatsEDB[26].sValDx = 0; - gMiscItemStatsEDB[27].sX = 0; gMiscItemStatsEDB[27].sY = 0; gMiscItemStatsEDB[27].sValDx = 0; + INT16 sOffsetY = sNASYCorrection( pObject ); - gWeaponDescStatsRects[0].iLeft = 202; gWeaponDescStatsRects[0].iTop = 42; gWeaponDescStatsRects[0].iRight = 260; gWeaponDescStatsRects[0].iBottom = 53; // First Column - gWeaponDescStatsRects[1].iLeft = 202; gWeaponDescStatsRects[1].iTop = 54; gWeaponDescStatsRects[1].iRight = 260; gWeaponDescStatsRects[1].iBottom = 65; - gWeaponDescStatsRects[2].iLeft = 202; gWeaponDescStatsRects[2].iTop = 66; gWeaponDescStatsRects[2].iRight = 260; gWeaponDescStatsRects[2].iBottom = 77; - gWeaponDescStatsRects[3].iLeft = 202; gWeaponDescStatsRects[3].iTop = 78; gWeaponDescStatsRects[3].iRight = 260; gWeaponDescStatsRects[3].iBottom = 89; - gWeaponDescStatsRects[4].iLeft = 202; gWeaponDescStatsRects[4].iTop = 90; gWeaponDescStatsRects[4].iRight = 260; gWeaponDescStatsRects[4].iBottom = 101; - gWeaponDescStatsRects[5].iLeft = 202; gWeaponDescStatsRects[5].iTop = 102; gWeaponDescStatsRects[5].iRight = 260; gWeaponDescStatsRects[5].iBottom = 113; - gWeaponDescStatsRects[6].iLeft = 202; gWeaponDescStatsRects[6].iTop = 114; gWeaponDescStatsRects[6].iRight = 260; gWeaponDescStatsRects[6].iBottom = 125; - gWeaponDescStatsRects[7].iLeft = 267; gWeaponDescStatsRects[7].iTop = 54; gWeaponDescStatsRects[7].iRight = 325; gWeaponDescStatsRects[7].iBottom = 65; // Second Column - gWeaponDescStatsRects[8].iLeft = 267; gWeaponDescStatsRects[8].iTop = 66; gWeaponDescStatsRects[8].iRight = 325; gWeaponDescStatsRects[8].iBottom = 77; - gWeaponDescStatsRects[9].iLeft = 267; gWeaponDescStatsRects[9].iTop = 78; gWeaponDescStatsRects[9].iRight = 325; gWeaponDescStatsRects[9].iBottom = 89; - gWeaponDescStatsRects[10].iLeft = 267; gWeaponDescStatsRects[10].iTop = 90; gWeaponDescStatsRects[10].iRight = 325; gWeaponDescStatsRects[10].iBottom = 101; - gWeaponDescStatsRects[11].iLeft = 267; gWeaponDescStatsRects[11].iTop = 102; gWeaponDescStatsRects[11].iRight = 325; gWeaponDescStatsRects[11].iBottom = 113; - gWeaponDescStatsRects[12].iLeft = 267; gWeaponDescStatsRects[12].iTop = 114; gWeaponDescStatsRects[12].iRight = 325; gWeaponDescStatsRects[12].iBottom = 125; - gWeaponDescStatsRects[13].iLeft = 267; gWeaponDescStatsRects[13].iTop = 134; gWeaponDescStatsRects[13].iRight = 325; gWeaponDescStatsRects[13].iBottom = 145; - gWeaponDescStatsRects[14].iLeft = 267; gWeaponDescStatsRects[14].iTop = 146; gWeaponDescStatsRects[14].iRight = 325; gWeaponDescStatsRects[14].iBottom = 157; - gWeaponDescStatsRects[15].iLeft = 267; gWeaponDescStatsRects[15].iTop = 158; gWeaponDescStatsRects[15].iRight = 325; gWeaponDescStatsRects[15].iBottom = 169; - gWeaponDescStatsRects[16].iLeft = 267; gWeaponDescStatsRects[16].iTop = 170; gWeaponDescStatsRects[16].iRight = 325; gWeaponDescStatsRects[16].iBottom = 181; - gWeaponDescStatsRects[17].iLeft = 225; gWeaponDescStatsRects[17].iTop = 134; gWeaponDescStatsRects[17].iRight = 241; gWeaponDescStatsRects[17].iBottom = 157; - gWeaponDescStatsRects[18].iLeft = 202; gWeaponDescStatsRects[18].iTop = 158; gWeaponDescStatsRects[18].iRight = 260; gWeaponDescStatsRects[18].iBottom = 169; - gWeaponDescStatsRects[19].iLeft = 202; gWeaponDescStatsRects[19].iTop = 170; gWeaponDescStatsRects[19].iRight = 260; gWeaponDescStatsRects[19].iBottom = 181; + gItemDescLBEBackground[0].sLeft = 94 + gsInvDescX; gItemDescLBEBackground[0].sTop = 286 + gsInvDescY + sOffsetY; + gItemDescLBEBackground[1].sLeft = 15 + gsInvDescX; gItemDescLBEBackground[1].sTop = 298 + gsInvDescY + sOffsetY; + gItemDescLBEBackground[2].sLeft = 94 + gsInvDescX; gItemDescLBEBackground[2].sTop = 286 + gsInvDescY + sOffsetY; + gItemDescLBEBackground[3].sLeft = 61 + gsInvDescX; gItemDescLBEBackground[3].sTop = 274 + gsInvDescY + sOffsetY; - gAmmoDescStatsRects[0].iLeft = 202; gAmmoDescStatsRects[0].iTop = 42; gAmmoDescStatsRects[0].iRight = 260; gAmmoDescStatsRects[0].iBottom = 53; // First Column - gAmmoDescStatsRects[1].iLeft = 202; gAmmoDescStatsRects[1].iTop = 54; gAmmoDescStatsRects[1].iRight = 260; gAmmoDescStatsRects[1].iBottom = 65; - gAmmoDescStatsRects[2].iLeft = 202; gAmmoDescStatsRects[2].iTop = 66; gAmmoDescStatsRects[2].iRight = 260; gAmmoDescStatsRects[2].iBottom = 77; - gAmmoDescStatsRects[3].iLeft = 269; gAmmoDescStatsRects[3].iTop = 42; gAmmoDescStatsRects[3].iRight = 291; gAmmoDescStatsRects[3].iBottom = 65; // Second Column - gAmmoDescStatsRects[4].iLeft = 296; gAmmoDescStatsRects[4].iTop = 42; gAmmoDescStatsRects[4].iRight = 321; gAmmoDescStatsRects[4].iBottom = 65; - gAmmoDescStatsRects[5].iLeft = 269; gAmmoDescStatsRects[5].iTop = 66; gAmmoDescStatsRects[5].iRight = 291; gAmmoDescStatsRects[5].iBottom = 89; - gAmmoDescStatsRects[6].iLeft = 296; gAmmoDescStatsRects[6].iTop = 66; gAmmoDescStatsRects[6].iRight = 321; gAmmoDescStatsRects[6].iBottom = 89; - gAmmoDescStatsRects[7].iLeft = 269; gAmmoDescStatsRects[7].iTop = 90; gAmmoDescStatsRects[7].iRight = 291; gAmmoDescStatsRects[7].iBottom = 113; - gAmmoDescStatsRects[8].iLeft = 202; gAmmoDescStatsRects[8].iTop = 134; gAmmoDescStatsRects[8].iRight = 260; gAmmoDescStatsRects[8].iBottom = 145; // Third Column - gAmmoDescStatsRects[9].iLeft = 202; gAmmoDescStatsRects[9].iTop = 158; gAmmoDescStatsRects[9].iRight = 260; gAmmoDescStatsRects[9].iBottom = 169; - gAmmoDescStatsRects[10].iLeft = 267; gAmmoDescStatsRects[10].iTop = 134; gAmmoDescStatsRects[10].iRight = 325; gAmmoDescStatsRects[10].iBottom = 145; - gAmmoDescStatsRects[11].iLeft = 267; gAmmoDescStatsRects[11].iTop = 146; gAmmoDescStatsRects[11].iRight = 325; gAmmoDescStatsRects[11].iBottom = 157; - gAmmoDescStatsRects[12].iLeft = 267; gAmmoDescStatsRects[12].iTop = 158; gAmmoDescStatsRects[12].iRight = 325; gAmmoDescStatsRects[12].iBottom = 169; // Fourth Column - gAmmoDescStatsRects[13].iLeft = 202; gAmmoDescStatsRects[13].iTop = 170; gAmmoDescStatsRects[13].iRight = 260; gAmmoDescStatsRects[13].iBottom = 181; - gAmmoDescStatsRects[14].iLeft = 267; gAmmoDescStatsRects[14].iTop = 170; gAmmoDescStatsRects[14].iRight = 325; gAmmoDescStatsRects[14].iBottom = 181; // Placeholders - gAmmoDescStatsRects[15].iLeft = 0; gAmmoDescStatsRects[15].iTop = 0; gAmmoDescStatsRects[15].iRight = 1; gAmmoDescStatsRects[15].iBottom = 1; - gAmmoDescStatsRects[16].iLeft = 0; gAmmoDescStatsRects[16].iTop = 0; gAmmoDescStatsRects[16].iRight = 1; gAmmoDescStatsRects[16].iBottom = 1; - gAmmoDescStatsRects[17].iLeft = 0; gAmmoDescStatsRects[17].iTop = 0; gAmmoDescStatsRects[17].iRight = 1; gAmmoDescStatsRects[17].iBottom = 1; - gAmmoDescStatsRects[18].iLeft = 0; gAmmoDescStatsRects[18].iTop = 0; gAmmoDescStatsRects[18].iRight = 1; gAmmoDescStatsRects[18].iBottom = 1; - gAmmoDescStatsRects[19].iLeft = 0; gAmmoDescStatsRects[19].iTop = 0; gAmmoDescStatsRects[19].iRight = 1; gAmmoDescStatsRects[19].iBottom = 1; + ////////////////// MONEY TEXT COORDINATES + gMoneyStats[0].sX = 48 + gsInvDescX; gMoneyStats[0].sY = 98 + gsInvDescY + sOffsetY; // Money + gMoneyStats[1].sX = 56 + gsInvDescX; gMoneyStats[1].sY = 108 + gsInvDescY + sOffsetY; // Remaining + gMoneyStats[2].sX = 48 + gsInvDescX; gMoneyStats[2].sY = 125 + gsInvDescY + sOffsetY; // Money + gMoneyStats[3].sX = 56 + gsInvDescX; gMoneyStats[3].sY = 135 + gsInvDescY + sOffsetY; // Removing + gMoneyStats[4].sX = 140 + gsInvDescX; gMoneyStats[4].sY = 108 + gsInvDescY + sOffsetY; // AMT remaining + gMoneyStats[5].sX = 140 + gsInvDescX; gMoneyStats[5].sY = 135 + gsInvDescY + sOffsetY; // AMT removing - gArmorDescStatsRects[0].iLeft = 202; gArmorDescStatsRects[0].iTop = 42; gArmorDescStatsRects[0].iRight = 260; gArmorDescStatsRects[0].iBottom = 53; // First Column - gArmorDescStatsRects[1].iLeft = 202; gArmorDescStatsRects[1].iTop = 54; gArmorDescStatsRects[1].iRight = 260; gArmorDescStatsRects[1].iBottom = 65; - gArmorDescStatsRects[2].iLeft = 202; gArmorDescStatsRects[2].iTop = 66; gArmorDescStatsRects[2].iRight = 260; gArmorDescStatsRects[2].iBottom = 77; - gArmorDescStatsRects[3].iLeft = 267; gArmorDescStatsRects[3].iTop = 42; gArmorDescStatsRects[3].iRight = 325; gArmorDescStatsRects[3].iBottom = 53; // Second Column - gArmorDescStatsRects[4].iLeft = 267; gArmorDescStatsRects[4].iTop = 54; gArmorDescStatsRects[4].iRight = 325; gArmorDescStatsRects[4].iBottom = 65; - gArmorDescStatsRects[5].iLeft = 267; gArmorDescStatsRects[5].iTop = 66; gArmorDescStatsRects[5].iRight = 325; gArmorDescStatsRects[5].iBottom = 77; - gArmorDescStatsRects[6].iLeft = 267; gArmorDescStatsRects[6].iTop = 78; gArmorDescStatsRects[6].iRight = 325; gArmorDescStatsRects[6].iBottom = 89; - gArmorDescStatsRects[7].iLeft = 267; gArmorDescStatsRects[7].iTop = 90; gArmorDescStatsRects[7].iRight = 325; gArmorDescStatsRects[7].iBottom = 101; - gArmorDescStatsRects[8].iLeft = 267; gArmorDescStatsRects[8].iTop = 102; gArmorDescStatsRects[8].iRight = 325; gArmorDescStatsRects[8].iBottom = 113; - gArmorDescStatsRects[9].iLeft = 267; gArmorDescStatsRects[9].iTop = 114; gArmorDescStatsRects[9].iRight = 325; gArmorDescStatsRects[9].iBottom = 125; - gArmorDescStatsRects[10].iLeft = 202; gArmorDescStatsRects[10].iTop = 134; gArmorDescStatsRects[10].iRight = 260; gArmorDescStatsRects[10].iBottom = 145; // Third Column - gArmorDescStatsRects[11].iLeft = 202; gArmorDescStatsRects[11].iTop = 146; gArmorDescStatsRects[11].iRight = 260; gArmorDescStatsRects[11].iBottom = 157; - gArmorDescStatsRects[12].iLeft = 202; gArmorDescStatsRects[12].iTop = 158; gArmorDescStatsRects[12].iRight = 260; gArmorDescStatsRects[12].iBottom = 169; - gArmorDescStatsRects[13].iLeft = 202; gArmorDescStatsRects[13].iTop = 170; gArmorDescStatsRects[13].iRight = 260; gArmorDescStatsRects[13].iBottom = 181; - gArmorDescStatsRects[14].iLeft = 267; gArmorDescStatsRects[14].iTop = 134; gArmorDescStatsRects[14].iRight = 325; gArmorDescStatsRects[14].iBottom = 145; // Fourth Column - gArmorDescStatsRects[15].iLeft = 267; gArmorDescStatsRects[15].iTop = 146; gArmorDescStatsRects[15].iRight = 325; gArmorDescStatsRects[15].iBottom = 157; - gArmorDescStatsRects[16].iLeft = 267; gArmorDescStatsRects[16].iTop = 158; gArmorDescStatsRects[16].iRight = 325; gArmorDescStatsRects[16].iBottom = 169; - gArmorDescStatsRects[17].iLeft = 0; gArmorDescStatsRects[17].iTop = 0; gArmorDescStatsRects[17].iRight = 1; gArmorDescStatsRects[17].iBottom = 1; // Placeholders - gArmorDescStatsRects[18].iLeft = 0; gArmorDescStatsRects[18].iTop = 0; gArmorDescStatsRects[18].iRight = 1; gArmorDescStatsRects[18].iBottom = 1; - gArmorDescStatsRects[19].iLeft = 0; gArmorDescStatsRects[19].iTop = 0; gArmorDescStatsRects[19].iRight = 1; gArmorDescStatsRects[19].iBottom = 1; + ////////////////////////////////////////////////////////////////////// + // ODB has exactly four separate regions. Each has 8 sub-regions, which can be + // used to display data at irregular intervals. This allows ODB to function as + // smoothly as EDB does. + // In addition, ODB uses some of the UDB regions to display things like PROS/CONS + // and Description Text. This reduces the use of redundant arrays... - gExplosiveDescStatsRects[0].iLeft = 202; gExplosiveDescStatsRects[0].iTop = 42; gExplosiveDescStatsRects[0].iRight = 260; gExplosiveDescStatsRects[0].iBottom = 53; // First Column - gExplosiveDescStatsRects[1].iLeft = 202; gExplosiveDescStatsRects[1].iTop = 54; gExplosiveDescStatsRects[1].iRight = 260; gExplosiveDescStatsRects[1].iBottom = 65; - gExplosiveDescStatsRects[2].iLeft = 202; gExplosiveDescStatsRects[2].iTop = 66; gExplosiveDescStatsRects[2].iRight = 260; gExplosiveDescStatsRects[2].iBottom = 77; - gExplosiveDescStatsRects[3].iLeft = 202; gExplosiveDescStatsRects[3].iTop = 78; gExplosiveDescStatsRects[3].iRight = 260; gExplosiveDescStatsRects[3].iBottom = 89; - gExplosiveDescStatsRects[4].iLeft = 290; gExplosiveDescStatsRects[4].iTop = 42; gExplosiveDescStatsRects[4].iRight = 306; gExplosiveDescStatsRects[4].iBottom = 77; // Second Column - gExplosiveDescStatsRects[5].iLeft = 269; gExplosiveDescStatsRects[5].iTop = 42; gExplosiveDescStatsRects[5].iRight = 285; gExplosiveDescStatsRects[5].iBottom = 77; - gExplosiveDescStatsRects[6].iLeft = 301; gExplosiveDescStatsRects[6].iTop = 42; gExplosiveDescStatsRects[6].iRight = 321; gExplosiveDescStatsRects[6].iBottom = 77; - gExplosiveDescStatsRects[7].iLeft = 267; gExplosiveDescStatsRects[7].iTop = 90; gExplosiveDescStatsRects[7].iRight = 325; gExplosiveDescStatsRects[7].iBottom = 101; - gExplosiveDescStatsRects[8].iLeft = 0; gExplosiveDescStatsRects[8].iTop = 0; gExplosiveDescStatsRects[8].iRight = 1; gExplosiveDescStatsRects[8].iBottom = 1; // Placeholders - gExplosiveDescStatsRects[9].iLeft = 0; gExplosiveDescStatsRects[9].iTop = 0; gExplosiveDescStatsRects[9].iRight = 1; gExplosiveDescStatsRects[9].iBottom = 1; - gExplosiveDescStatsRects[10].iLeft = 0; gExplosiveDescStatsRects[10].iTop = 0; gExplosiveDescStatsRects[10].iRight = 1; gExplosiveDescStatsRects[10].iBottom = 1; - gExplosiveDescStatsRects[11].iLeft = 0; gExplosiveDescStatsRects[11].iTop = 0; gExplosiveDescStatsRects[11].iRight = 1; gExplosiveDescStatsRects[11].iBottom = 1; - gExplosiveDescStatsRects[12].iLeft = 0; gExplosiveDescStatsRects[12].iTop = 0; gExplosiveDescStatsRects[12].iRight = 1; gExplosiveDescStatsRects[12].iBottom = 1; - gExplosiveDescStatsRects[13].iLeft = 0; gExplosiveDescStatsRects[13].iTop = 0; gExplosiveDescStatsRects[13].iRight = 1; gExplosiveDescStatsRects[13].iBottom = 1; - gExplosiveDescStatsRects[14].iLeft = 0; gExplosiveDescStatsRects[14].iTop = 0; gExplosiveDescStatsRects[14].iRight = 1; gExplosiveDescStatsRects[14].iBottom = 1; - gExplosiveDescStatsRects[15].iLeft = 0; gExplosiveDescStatsRects[15].iTop = 0; gExplosiveDescStatsRects[15].iRight = 1; gExplosiveDescStatsRects[15].iBottom = 1; - gExplosiveDescStatsRects[16].iLeft = 0; gExplosiveDescStatsRects[16].iTop = 0; gExplosiveDescStatsRects[16].iRight = 1; gExplosiveDescStatsRects[16].iBottom = 1; - gExplosiveDescStatsRects[17].iLeft = 0; gExplosiveDescStatsRects[17].iTop = 0; gExplosiveDescStatsRects[17].iRight = 1; gExplosiveDescStatsRects[17].iBottom = 1; - gExplosiveDescStatsRects[18].iLeft = 0; gExplosiveDescStatsRects[18].iTop = 0; gExplosiveDescStatsRects[18].iRight = 1; gExplosiveDescStatsRects[18].iBottom = 1; - gExplosiveDescStatsRects[19].iLeft = 0; gExplosiveDescStatsRects[19].iTop = 0; gExplosiveDescStatsRects[19].iRight = 1; gExplosiveDescStatsRects[19].iBottom = 1; + // First Data Row (Condition / Ammo label) + gODBItemDescRegions[0][0].sLeft = 52 + gsInvDescX; gODBItemDescRegions[0][0].sTop = 98 + gsInvDescY + sOffsetY; gODBItemDescRegions[0][0].sRight = 167 + gsInvDescX; gODBItemDescRegions[0][0].sBottom = 106 + gsInvDescY + sOffsetY; + + // Second Data Row (Weight) + gODBItemDescRegions[1][0].sLeft = 52 + gsInvDescX; gODBItemDescRegions[1][0].sTop = 108 + gsInvDescY + sOffsetY; gODBItemDescRegions[1][0].sRight = 167 + gsInvDescX; gODBItemDescRegions[1][0].sBottom = 116 + gsInvDescY + sOffsetY; + + // Third Data Row (Usually basic Gun Statistics) + // Left Side + gODBItemDescRegions[2][0].sLeft = 52 + gsInvDescX; gODBItemDescRegions[2][0].sTop = 124 + gsInvDescY + sOffsetY; + gODBItemDescRegions[2][3].sLeft = 91 + gsInvDescX; gODBItemDescRegions[2][3].sTop = 124 + gsInvDescY + sOffsetY; gODBItemDescRegions[2][3].sRight = 107 + gsInvDescX; gODBItemDescRegions[2][3].sBottom = 132 + gsInvDescY + sOffsetY; + + // Right Side + gODBItemDescRegions[2][4].sLeft = 117 + gsInvDescX; gODBItemDescRegions[2][4].sTop = 124 + gsInvDescY + sOffsetY; + gODBItemDescRegions[2][7].sLeft = 152 + gsInvDescX; gODBItemDescRegions[2][7].sTop = 124 + gsInvDescY + sOffsetY; gODBItemDescRegions[2][7].sRight = 168 + gsInvDescX; gODBItemDescRegions[2][7].sBottom = 132 + gsInvDescY + sOffsetY; + + // Fourth Data Row (Usually AP Costs) + // Left Side + gODBItemDescRegions[3][0].sLeft = 52 + gsInvDescX; gODBItemDescRegions[3][0].sTop = 135 + gsInvDescY + sOffsetY; + gODBItemDescRegions[3][1].sLeft = 77 + gsInvDescX; gODBItemDescRegions[3][1].sTop = 135 + gsInvDescY + sOffsetY; + gODBItemDescRegions[3][2].sLeft = 86 + gsInvDescX; gODBItemDescRegions[3][2].sTop = 135 + gsInvDescY + sOffsetY; + gODBItemDescRegions[3][3].sLeft = 91 + gsInvDescX; gODBItemDescRegions[3][3].sTop = 135 + gsInvDescY + sOffsetY; gODBItemDescRegions[3][3].sRight = 107 + gsInvDescX; gODBItemDescRegions[3][3].sBottom = 143 + gsInvDescY + sOffsetY; + // Right Side + gODBItemDescRegions[3][4].sLeft = 117 + gsInvDescX; gODBItemDescRegions[3][4].sTop = 135 + gsInvDescY + sOffsetY; + gODBItemDescRegions[3][6].sLeft = 145 + gsInvDescX; gODBItemDescRegions[3][6].sTop = 135 + gsInvDescY + sOffsetY; + gODBItemDescRegions[3][7].sLeft = 152 + gsInvDescX; gODBItemDescRegions[3][7].sTop = 135 + gsInvDescY + sOffsetY; gODBItemDescRegions[3][7].sRight = 168 + gsInvDescX; gODBItemDescRegions[3][7].sBottom = 143 + gsInvDescY + sOffsetY; + + // Description Text Area + gItemDescTextRegions[0].sLeft = 23 + gsInvDescX; gItemDescTextRegions[0].sTop = 170 + gsInvDescY + sOffsetY; gItemDescTextRegions[0].sRight = 233 + gsInvDescX; + + // PROS/CONS areas + gItemDescTextRegions[3].sLeft = 23 + gsInvDescX; gItemDescTextRegions[3].sTop = 230 + gsInvDescY + sOffsetY; gItemDescTextRegions[3].sRight = 233 + gsInvDescX; gItemDescTextRegions[3].sBottom = 238 + gsInvDescY + sOffsetY; + gItemDescTextRegions[4].sLeft = 59 + gsInvDescX; gItemDescTextRegions[4].sTop = 230 + gsInvDescY + sOffsetY; gItemDescTextRegions[4].sRight = 233 + gsInvDescX; gItemDescTextRegions[4].sBottom = 238 + gsInvDescY + sOffsetY; + gItemDescTextRegions[5].sLeft = 23 + gsInvDescX; gItemDescTextRegions[5].sTop = 240 + gsInvDescY + sOffsetY; gItemDescTextRegions[5].sRight = 233 + gsInvDescX; gItemDescTextRegions[5].sBottom = 250 + gsInvDescY + sOffsetY; + gItemDescTextRegions[6].sLeft = 59 + gsInvDescX; gItemDescTextRegions[6].sTop = 240 + gsInvDescY + sOffsetY; gItemDescTextRegions[6].sRight = 233 + gsInvDescX; gItemDescTextRegions[6].sBottom = 250 + gsInvDescY + sOffsetY; - gMiscItemDescStatsRects[0].iLeft = 202; gMiscItemDescStatsRects[0].iTop = 42; gMiscItemDescStatsRects[0].iRight = 325; gMiscItemDescStatsRects[0].iBottom = 53; // Only one column for misc items in tactical - 12 fields. - gMiscItemDescStatsRects[1].iLeft = 202; gMiscItemDescStatsRects[1].iTop = 54; gMiscItemDescStatsRects[1].iRight = 325; gMiscItemDescStatsRects[1].iBottom = 65; - gMiscItemDescStatsRects[2].iLeft = 202; gMiscItemDescStatsRects[2].iTop = 66; gMiscItemDescStatsRects[2].iRight = 325; gMiscItemDescStatsRects[2].iBottom = 77; - gMiscItemDescStatsRects[3].iLeft = 202; gMiscItemDescStatsRects[3].iTop = 78; gMiscItemDescStatsRects[3].iRight = 325; gMiscItemDescStatsRects[3].iBottom = 89; - gMiscItemDescStatsRects[4].iLeft = 202; gMiscItemDescStatsRects[4].iTop = 90; gMiscItemDescStatsRects[4].iRight = 325; gMiscItemDescStatsRects[4].iBottom = 101; - gMiscItemDescStatsRects[5].iLeft = 202; gMiscItemDescStatsRects[5].iTop = 102; gMiscItemDescStatsRects[5].iRight = 325; gMiscItemDescStatsRects[5].iBottom = 113; - gMiscItemDescStatsRects[6].iLeft = 202; gMiscItemDescStatsRects[6].iTop = 114; gMiscItemDescStatsRects[6].iRight = 325; gMiscItemDescStatsRects[6].iBottom = 125; - gMiscItemDescStatsRects[7].iLeft = 202; gMiscItemDescStatsRects[7].iTop = 126; gMiscItemDescStatsRects[7].iRight = 325; gMiscItemDescStatsRects[7].iBottom = 137; - gMiscItemDescStatsRects[8].iLeft = 202; gMiscItemDescStatsRects[8].iTop = 138; gMiscItemDescStatsRects[8].iRight = 325; gMiscItemDescStatsRects[8].iBottom = 149; - gMiscItemDescStatsRects[9].iLeft = 202; gMiscItemDescStatsRects[9].iTop = 150; gMiscItemDescStatsRects[9].iRight = 325; gMiscItemDescStatsRects[9].iBottom = 161; - gMiscItemDescStatsRects[10].iLeft = 202; gMiscItemDescStatsRects[10].iTop = 162; gMiscItemDescStatsRects[10].iRight = 325; gMiscItemDescStatsRects[10].iBottom = 173; - gMiscItemDescStatsRects[11].iLeft = 202; gMiscItemDescStatsRects[11].iTop = 174; gMiscItemDescStatsRects[11].iRight = 325; gMiscItemDescStatsRects[11].iBottom = 185; - gMiscItemDescStatsRects[12].iLeft = 0; gMiscItemDescStatsRects[12].iTop = 0; gMiscItemDescStatsRects[12].iRight = 1; gMiscItemDescStatsRects[12].iBottom = 1; // Placeholders - gMiscItemDescStatsRects[13].iLeft = 0; gMiscItemDescStatsRects[13].iTop = 0; gMiscItemDescStatsRects[13].iRight = 1; gMiscItemDescStatsRects[13].iBottom = 1; - gMiscItemDescStatsRects[14].iLeft = 0; gMiscItemDescStatsRects[14].iTop = 0; gMiscItemDescStatsRects[14].iRight = 1; gMiscItemDescStatsRects[14].iBottom = 1; - gMiscItemDescStatsRects[15].iLeft = 0; gMiscItemDescStatsRects[15].iTop = 0; gMiscItemDescStatsRects[15].iRight = 1; gMiscItemDescStatsRects[15].iBottom = 1; - gMiscItemDescStatsRects[16].iLeft = 0; gMiscItemDescStatsRects[16].iTop = 0; gMiscItemDescStatsRects[16].iRight = 1; gMiscItemDescStatsRects[16].iBottom = 1; - gMiscItemDescStatsRects[17].iLeft = 0; gMiscItemDescStatsRects[17].iTop = 0; gMiscItemDescStatsRects[17].iRight = 1; gMiscItemDescStatsRects[17].iBottom = 1; - gMiscItemDescStatsRects[18].iLeft = 0; gMiscItemDescStatsRects[18].iTop = 0; gMiscItemDescStatsRects[18].iRight = 1; gMiscItemDescStatsRects[18].iBottom = 1; - gMiscItemDescStatsRects[19].iLeft = 0; gMiscItemDescStatsRects[19].iTop = 0; gMiscItemDescStatsRects[19].iRight = 1; gMiscItemDescStatsRects[19].iBottom = 1; } - else if (UsingEDBSystem() == 2) // Tactical OIV-EDB + else { - // Icon Locations - gMiscItemStatsEDB[0].sX = 274; gMiscItemStatsEDB[0].sY = 14; gMiscItemStatsEDB[0].sValDx = 0; // 0) COL 1; ROW 1 - gMiscItemStatsEDB[1].sX = 274; gMiscItemStatsEDB[1].sY = 26; gMiscItemStatsEDB[1].sValDx = 0; // 1) COL 1; ROW 2 - gMiscItemStatsEDB[2].sX = 274; gMiscItemStatsEDB[2].sY = 38; gMiscItemStatsEDB[2].sValDx = 0; // 2) COL 1; ROW 3 - gMiscItemStatsEDB[3].sX = 274; gMiscItemStatsEDB[3].sY = 50; gMiscItemStatsEDB[3].sValDx = 0; // 3) COL 1; ROW 4 - gMiscItemStatsEDB[4].sX = 274; gMiscItemStatsEDB[4].sY = 62; gMiscItemStatsEDB[4].sValDx = 0; // 4) COL 1; ROW 5 - gMiscItemStatsEDB[5].sX = 274; gMiscItemStatsEDB[5].sY = 74; gMiscItemStatsEDB[5].sValDx = 0; // 5) COL 1; ROW 6 - gMiscItemStatsEDB[6].sX = 274; gMiscItemStatsEDB[6].sY = 86; gMiscItemStatsEDB[6].sValDx = 0; // 6) COL 1; ROW 7 - gMiscItemStatsEDB[7].sX = 375; gMiscItemStatsEDB[7].sY = 14; gMiscItemStatsEDB[7].sValDx = 0; // 7) COL 1; ROW 8 - gMiscItemStatsEDB[8].sX = 375; gMiscItemStatsEDB[8].sY = 26; gMiscItemStatsEDB[8].sValDx = 0; // 8) COL 1; ROW 9 - gMiscItemStatsEDB[9].sX = 375; gMiscItemStatsEDB[9].sY = 38; gMiscItemStatsEDB[9].sValDx = 0; // 9) COL 1; ROW 10 - gMiscItemStatsEDB[10].sX = 375; gMiscItemStatsEDB[10].sY = 50; gMiscItemStatsEDB[10].sValDx = 0; // 10) COL 1; ROW 11 - gMiscItemStatsEDB[11].sX = 375; gMiscItemStatsEDB[11].sY = 62; gMiscItemStatsEDB[11].sValDx = 0; // 11) COL 1; ROW 12 - // EQUALS signs Locations - gMiscItemStatsEDB[12].sX = 324; gMiscItemStatsEDB[12].sY = 14; gMiscItemStatsEDB[12].sValDx = 12; // 12) COL 1; ROW 1 - gMiscItemStatsEDB[13].sX = 324; gMiscItemStatsEDB[13].sY = 26; gMiscItemStatsEDB[13].sValDx = 12; // 13) COL 1; ROW 2 - gMiscItemStatsEDB[14].sX = 324; gMiscItemStatsEDB[14].sY = 38; gMiscItemStatsEDB[14].sValDx = 12; // 14) COL 1; ROW 3 - gMiscItemStatsEDB[15].sX = 324; gMiscItemStatsEDB[15].sY = 50; gMiscItemStatsEDB[15].sValDx = 12; // 15) COL 1; ROW 4 - gMiscItemStatsEDB[16].sX = 324; gMiscItemStatsEDB[16].sY = 62; gMiscItemStatsEDB[16].sValDx = 12; // 16) COL 1; ROW 5 - gMiscItemStatsEDB[17].sX = 324; gMiscItemStatsEDB[17].sY = 74; gMiscItemStatsEDB[17].sValDx = 12; // 17) COL 1; ROW 6 - gMiscItemStatsEDB[18].sX = 324; gMiscItemStatsEDB[18].sY = 86; gMiscItemStatsEDB[18].sValDx = 12; // 18) COL 1; ROW 7 - gMiscItemStatsEDB[19].sX = 425; gMiscItemStatsEDB[19].sY = 14; gMiscItemStatsEDB[19].sValDx = 12; // 19) COL 1; ROW 8 - gMiscItemStatsEDB[20].sX = 425; gMiscItemStatsEDB[20].sY = 26; gMiscItemStatsEDB[20].sValDx = 12; // 20) COL 1; ROW 9 - gMiscItemStatsEDB[21].sX = 425; gMiscItemStatsEDB[21].sY = 38; gMiscItemStatsEDB[21].sValDx = 12; // 21) COL 1; ROW 10 - gMiscItemStatsEDB[22].sX = 425; gMiscItemStatsEDB[22].sY = 50; gMiscItemStatsEDB[22].sValDx = 12; // 22) COL 1; ROW 11 - gMiscItemStatsEDB[23].sX = 425; gMiscItemStatsEDB[23].sY = 62; gMiscItemStatsEDB[23].sValDx = 12; // 23) COL 1; ROW 12 - // MISC - gMiscItemStatsEDB[24].sX = 0; gMiscItemStatsEDB[24].sY = 0; gMiscItemStatsEDB[24].sValDx = 0; - gMiscItemStatsEDB[25].sX = 0; gMiscItemStatsEDB[25].sY = 0; gMiscItemStatsEDB[25].sValDx = 0; - gMiscItemStatsEDB[26].sX = 0; gMiscItemStatsEDB[26].sY = 0; gMiscItemStatsEDB[26].sValDx = 0; - gMiscItemStatsEDB[27].sX = 0; gMiscItemStatsEDB[27].sY = 0; gMiscItemStatsEDB[27].sValDx = 0; + // Tactical NAS/ODB and regular ODB are radically different in shape, so we need two separate + // definition tables. + if (UseNASDesc( pObject )) + { + // No LBE/MONEY coordinates, since NAS doesn't run with either such item. + /* + gItemDescLBEBackground[0].sLeft = 320 + gsInvDescX; gItemDescLBEBackground[0].sTop = 8 + gsInvDescY; + gItemDescLBEBackground[1].sLeft = 3 + gsInvDescX; gItemDescLBEBackground[1].sTop = 137 + gsInvDescY; + gItemDescLBEBackground[2].sLeft = 320 + gsInvDescX; gItemDescLBEBackground[2].sTop = 8 + gsInvDescY; + gItemDescLBEBackground[3].sLeft = 320 + gsInvDescX; gItemDescLBEBackground[3].sTop = 8 + gsInvDescY; - gWeaponDescStatsRects[0].iLeft = 273; gWeaponDescStatsRects[0].iTop = 12; gWeaponDescStatsRects[0].iRight = 331; gWeaponDescStatsRects[0].iBottom = 23; // First Column - gWeaponDescStatsRects[1].iLeft = 273; gWeaponDescStatsRects[1].iTop = 24; gWeaponDescStatsRects[1].iRight = 331; gWeaponDescStatsRects[1].iBottom = 35; - gWeaponDescStatsRects[2].iLeft = 273; gWeaponDescStatsRects[2].iTop = 36; gWeaponDescStatsRects[2].iRight = 331; gWeaponDescStatsRects[2].iBottom = 47; - gWeaponDescStatsRects[3].iLeft = 273; gWeaponDescStatsRects[3].iTop = 48; gWeaponDescStatsRects[3].iRight = 331; gWeaponDescStatsRects[3].iBottom = 59; - gWeaponDescStatsRects[4].iLeft = 273; gWeaponDescStatsRects[4].iTop = 60; gWeaponDescStatsRects[4].iRight = 331; gWeaponDescStatsRects[4].iBottom = 71; - gWeaponDescStatsRects[5].iLeft = 273; gWeaponDescStatsRects[5].iTop = 72; gWeaponDescStatsRects[5].iRight = 331; gWeaponDescStatsRects[5].iBottom = 83; - gWeaponDescStatsRects[6].iLeft = 273; gWeaponDescStatsRects[6].iTop = 84; gWeaponDescStatsRects[6].iRight = 331; gWeaponDescStatsRects[6].iBottom = 95; - gWeaponDescStatsRects[7].iLeft = 340; gWeaponDescStatsRects[7].iTop = 24; gWeaponDescStatsRects[7].iRight = 398; gWeaponDescStatsRects[7].iBottom = 35; // Second Column - gWeaponDescStatsRects[8].iLeft = 340; gWeaponDescStatsRects[8].iTop = 36; gWeaponDescStatsRects[8].iRight = 398; gWeaponDescStatsRects[8].iBottom = 47; - gWeaponDescStatsRects[9].iLeft = 340; gWeaponDescStatsRects[9].iTop = 48; gWeaponDescStatsRects[9].iRight = 398; gWeaponDescStatsRects[9].iBottom = 59; - gWeaponDescStatsRects[10].iLeft = 340; gWeaponDescStatsRects[10].iTop = 60; gWeaponDescStatsRects[10].iRight = 398; gWeaponDescStatsRects[10].iBottom = 71; - gWeaponDescStatsRects[11].iLeft = 340; gWeaponDescStatsRects[11].iTop = 72; gWeaponDescStatsRects[11].iRight = 398; gWeaponDescStatsRects[11].iBottom = 83; - gWeaponDescStatsRects[12].iLeft = 340; gWeaponDescStatsRects[12].iTop = 84; gWeaponDescStatsRects[12].iRight = 398; gWeaponDescStatsRects[12].iBottom = 95; - gWeaponDescStatsRects[13].iLeft = 407; gWeaponDescStatsRects[13].iTop = 36; gWeaponDescStatsRects[13].iRight = 465; gWeaponDescStatsRects[13].iBottom = 47; // These are non-sequential! - gWeaponDescStatsRects[14].iLeft = 407; gWeaponDescStatsRects[14].iTop = 48; gWeaponDescStatsRects[14].iRight = 465; gWeaponDescStatsRects[14].iBottom = 59; - gWeaponDescStatsRects[15].iLeft = 407; gWeaponDescStatsRects[15].iTop = 60; gWeaponDescStatsRects[15].iRight = 465; gWeaponDescStatsRects[15].iBottom = 71; - gWeaponDescStatsRects[16].iLeft = 407; gWeaponDescStatsRects[16].iTop = 72; gWeaponDescStatsRects[16].iRight = 465; gWeaponDescStatsRects[16].iBottom = 83; - gWeaponDescStatsRects[17].iLeft = 407; gWeaponDescStatsRects[17].iTop = 12; gWeaponDescStatsRects[17].iRight = 465; gWeaponDescStatsRects[17].iBottom = 23; - gWeaponDescStatsRects[18].iLeft = 407; gWeaponDescStatsRects[18].iTop = 24; gWeaponDescStatsRects[18].iRight = 465; gWeaponDescStatsRects[18].iBottom = 35; - gWeaponDescStatsRects[19].iLeft = 407; gWeaponDescStatsRects[19].iTop = 84; gWeaponDescStatsRects[19].iRight = 465; gWeaponDescStatsRects[19].iBottom = 95; + ////////////////// MONEY TEXT COORDINATES + gMoneyStats[0].sX = 204 + gsInvDescX; gMoneyStats[0].sY = 14 + gsInvDescY; // Money + gMoneyStats[1].sX = 212 + gsInvDescX; gMoneyStats[1].sY = 24 + gsInvDescY; // Remaining + gMoneyStats[2].sX = 204 + gsInvDescX; gMoneyStats[2].sY = 41 + gsInvDescY; // Money + gMoneyStats[3].sX = 212 + gsInvDescX; gMoneyStats[3].sY = 51 + gsInvDescY; // Removing + gMoneyStats[4].sX = 282 + gsInvDescX; gMoneyStats[4].sY = 24 + gsInvDescY; // AMT remaining + gMoneyStats[5].sX = 282 + gsInvDescX; gMoneyStats[5].sY = 51 + gsInvDescY; // AMT removing + */ - gAmmoDescStatsRects[0].iLeft = 273; gAmmoDescStatsRects[0].iTop = 12; gAmmoDescStatsRects[0].iRight = 331; gAmmoDescStatsRects[0].iBottom = 23; // First Column - gAmmoDescStatsRects[1].iLeft = 273; gAmmoDescStatsRects[1].iTop = 24; gAmmoDescStatsRects[1].iRight = 331; gAmmoDescStatsRects[1].iBottom = 35; - gAmmoDescStatsRects[2].iLeft = 273; gAmmoDescStatsRects[2].iTop = 36; gAmmoDescStatsRects[2].iRight = 331; gAmmoDescStatsRects[2].iBottom = 47; - gAmmoDescStatsRects[3].iLeft = 342; gAmmoDescStatsRects[3].iTop = 12; gAmmoDescStatsRects[3].iRight = 364; gAmmoDescStatsRects[3].iBottom = 35; // Second Column - gAmmoDescStatsRects[4].iLeft = 369; gAmmoDescStatsRects[4].iTop = 12; gAmmoDescStatsRects[4].iRight = 391; gAmmoDescStatsRects[4].iBottom = 35; - gAmmoDescStatsRects[5].iLeft = 342; gAmmoDescStatsRects[5].iTop = 36; gAmmoDescStatsRects[5].iRight = 364; gAmmoDescStatsRects[5].iBottom = 59; - gAmmoDescStatsRects[6].iLeft = 369; gAmmoDescStatsRects[6].iTop = 36; gAmmoDescStatsRects[6].iRight = 391; gAmmoDescStatsRects[6].iBottom = 59; - gAmmoDescStatsRects[7].iLeft = 342; gAmmoDescStatsRects[7].iTop = 60; gAmmoDescStatsRects[7].iRight = 364; gAmmoDescStatsRects[7].iBottom = 83; - gAmmoDescStatsRects[8].iLeft = 407; gAmmoDescStatsRects[8].iTop = 12; gAmmoDescStatsRects[8].iRight = 465; gAmmoDescStatsRects[8].iBottom = 23; // Third Column - gAmmoDescStatsRects[9].iLeft = 407; gAmmoDescStatsRects[9].iTop = 24; gAmmoDescStatsRects[9].iRight = 465; gAmmoDescStatsRects[9].iBottom = 35; - gAmmoDescStatsRects[10].iLeft = 407; gAmmoDescStatsRects[10].iTop = 36; gAmmoDescStatsRects[10].iRight = 465; gAmmoDescStatsRects[10].iBottom = 47; - gAmmoDescStatsRects[11].iLeft = 407; gAmmoDescStatsRects[11].iTop = 48; gAmmoDescStatsRects[11].iRight = 465; gAmmoDescStatsRects[11].iBottom = 59; - gAmmoDescStatsRects[12].iLeft = 407; gAmmoDescStatsRects[12].iTop = 60; gAmmoDescStatsRects[12].iRight = 465; gAmmoDescStatsRects[12].iBottom = 71; - gAmmoDescStatsRects[13].iLeft = 407; gAmmoDescStatsRects[13].iTop = 72; gAmmoDescStatsRects[13].iRight = 465; gAmmoDescStatsRects[13].iBottom = 83; - gAmmoDescStatsRects[14].iLeft = 407; gAmmoDescStatsRects[14].iTop = 84; gAmmoDescStatsRects[14].iRight = 465; gAmmoDescStatsRects[14].iBottom = 95; // Placeholders - gAmmoDescStatsRects[15].iLeft = 0; gAmmoDescStatsRects[15].iTop = 0; gAmmoDescStatsRects[15].iRight = 1; gAmmoDescStatsRects[15].iBottom = 1; - gAmmoDescStatsRects[16].iLeft = 0; gAmmoDescStatsRects[16].iTop = 0; gAmmoDescStatsRects[16].iRight = 1; gAmmoDescStatsRects[16].iBottom = 1; - gAmmoDescStatsRects[17].iLeft = 0; gAmmoDescStatsRects[17].iTop = 0; gAmmoDescStatsRects[17].iRight = 1; gAmmoDescStatsRects[17].iBottom = 1; - gAmmoDescStatsRects[18].iLeft = 0; gAmmoDescStatsRects[18].iTop = 0; gAmmoDescStatsRects[18].iRight = 1; gAmmoDescStatsRects[18].iBottom = 1; - gAmmoDescStatsRects[19].iLeft = 0; gAmmoDescStatsRects[19].iTop = 0; gAmmoDescStatsRects[19].iRight = 1; gAmmoDescStatsRects[19].iBottom = 1; + ////////////////////////////////////////////////////////////////////// + // ODB has exactly four separate regions. Each has 8 sub-regions, which can be + // used to display data at irregular intervals. This allows ODB to function as + // smoothly as EDB does. + // In addition, ODB uses some of the UDB regions to display things like PROS/CONS + // and Description Text. This reduces the use of redundant arrays... - gArmorDescStatsRects[0].iLeft = 273; gArmorDescStatsRects[0].iTop = 12; gArmorDescStatsRects[0].iRight = 331; gArmorDescStatsRects[0].iBottom = 23; // First Column - gArmorDescStatsRects[1].iLeft = 273; gArmorDescStatsRects[1].iTop = 24; gArmorDescStatsRects[1].iRight = 331; gArmorDescStatsRects[1].iBottom = 35; - gArmorDescStatsRects[2].iLeft = 273; gArmorDescStatsRects[2].iTop = 36; gArmorDescStatsRects[2].iRight = 331; gArmorDescStatsRects[2].iBottom = 47; - gArmorDescStatsRects[3].iLeft = 340; gArmorDescStatsRects[3].iTop = 12; gArmorDescStatsRects[3].iRight = 398; gArmorDescStatsRects[3].iBottom = 23; // Second Column - gArmorDescStatsRects[4].iLeft = 340; gArmorDescStatsRects[4].iTop = 24; gArmorDescStatsRects[4].iRight = 398; gArmorDescStatsRects[4].iBottom = 35; - gArmorDescStatsRects[5].iLeft = 340; gArmorDescStatsRects[5].iTop = 36; gArmorDescStatsRects[5].iRight = 398; gArmorDescStatsRects[5].iBottom = 47; - gArmorDescStatsRects[6].iLeft = 340; gArmorDescStatsRects[6].iTop = 48; gArmorDescStatsRects[6].iRight = 398; gArmorDescStatsRects[6].iBottom = 59; - gArmorDescStatsRects[7].iLeft = 340; gArmorDescStatsRects[7].iTop = 50; gArmorDescStatsRects[7].iRight = 398; gArmorDescStatsRects[7].iBottom = 71; - gArmorDescStatsRects[8].iLeft = 340; gArmorDescStatsRects[8].iTop = 62; gArmorDescStatsRects[8].iRight = 398; gArmorDescStatsRects[8].iBottom = 83; - gArmorDescStatsRects[9].iLeft = 340; gArmorDescStatsRects[9].iTop = 74; gArmorDescStatsRects[9].iRight = 398; gArmorDescStatsRects[9].iBottom = 95; - gArmorDescStatsRects[10].iLeft = 407; gArmorDescStatsRects[10].iTop = 12; gArmorDescStatsRects[10].iRight = 465; gArmorDescStatsRects[10].iBottom = 23; // Third Column - gArmorDescStatsRects[11].iLeft = 407; gArmorDescStatsRects[11].iTop = 24; gArmorDescStatsRects[11].iRight = 465; gArmorDescStatsRects[11].iBottom = 35; - gArmorDescStatsRects[12].iLeft = 407; gArmorDescStatsRects[12].iTop = 36; gArmorDescStatsRects[12].iRight = 465; gArmorDescStatsRects[12].iBottom = 47; - gArmorDescStatsRects[13].iLeft = 407; gArmorDescStatsRects[13].iTop = 48; gArmorDescStatsRects[13].iRight = 465; gArmorDescStatsRects[13].iBottom = 59; - gArmorDescStatsRects[14].iLeft = 407; gArmorDescStatsRects[14].iTop = 60; gArmorDescStatsRects[14].iRight = 465; gArmorDescStatsRects[14].iBottom = 71; - gArmorDescStatsRects[15].iLeft = 407; gArmorDescStatsRects[15].iTop = 72; gArmorDescStatsRects[15].iRight = 465; gArmorDescStatsRects[15].iBottom = 83; - gArmorDescStatsRects[16].iLeft = 407; gArmorDescStatsRects[16].iTop = 84; gArmorDescStatsRects[16].iRight = 465; gArmorDescStatsRects[16].iBottom = 95; - gArmorDescStatsRects[17].iLeft = 0; gArmorDescStatsRects[17].iTop = 0; gArmorDescStatsRects[17].iRight = 1; gArmorDescStatsRects[17].iBottom = 1; // Placeholders - gArmorDescStatsRects[18].iLeft = 0; gArmorDescStatsRects[18].iTop = 0; gArmorDescStatsRects[18].iRight = 1; gArmorDescStatsRects[18].iBottom = 1; - gArmorDescStatsRects[19].iLeft = 0; gArmorDescStatsRects[19].iTop = 0; gArmorDescStatsRects[19].iRight = 1; gArmorDescStatsRects[19].iBottom = 1; + // First Data Row (Condition / Ammo label) + gODBItemDescRegions[0][0].sLeft = 270 + gsInvDescX; gODBItemDescRegions[0][0].sTop = 15 + gsInvDescY; gODBItemDescRegions[0][0].sRight = 418 + gsInvDescX; gODBItemDescRegions[0][0].sBottom = 23 + gsInvDescY; - gExplosiveDescStatsRects[0].iLeft = 273; gExplosiveDescStatsRects[0].iTop = 12; gExplosiveDescStatsRects[0].iRight = 331; gExplosiveDescStatsRects[0].iBottom = 23; // First Column - gExplosiveDescStatsRects[1].iLeft = 273; gExplosiveDescStatsRects[1].iTop = 24; gExplosiveDescStatsRects[1].iRight = 331; gExplosiveDescStatsRects[1].iBottom = 35; - gExplosiveDescStatsRects[2].iLeft = 273; gExplosiveDescStatsRects[2].iTop = 36; gExplosiveDescStatsRects[2].iRight = 331; gExplosiveDescStatsRects[2].iBottom = 47; - gExplosiveDescStatsRects[3].iLeft = 273; gExplosiveDescStatsRects[3].iTop = 48; gExplosiveDescStatsRects[3].iRight = 331; gExplosiveDescStatsRects[3].iBottom = 59; - gExplosiveDescStatsRects[4].iLeft = 358; gExplosiveDescStatsRects[4].iTop = 12; gExplosiveDescStatsRects[4].iRight = 374; gExplosiveDescStatsRects[4].iBottom = 47; // Second Column - gExplosiveDescStatsRects[5].iLeft = 342; gExplosiveDescStatsRects[5].iTop = 12; gExplosiveDescStatsRects[5].iRight = 358; gExplosiveDescStatsRects[5].iBottom = 47; - gExplosiveDescStatsRects[6].iLeft = 376; gExplosiveDescStatsRects[6].iTop = 12; gExplosiveDescStatsRects[6].iRight = 395; gExplosiveDescStatsRects[6].iBottom = 47; - gExplosiveDescStatsRects[7].iLeft = 341; gExplosiveDescStatsRects[7].iTop = 60; gExplosiveDescStatsRects[7].iRight = 465; gExplosiveDescStatsRects[7].iBottom = 71; - gExplosiveDescStatsRects[8].iLeft = 0; gExplosiveDescStatsRects[8].iTop = 0; gExplosiveDescStatsRects[8].iRight = 1; gExplosiveDescStatsRects[8].iBottom = 1; // Placeholders - gExplosiveDescStatsRects[9].iLeft = 0; gExplosiveDescStatsRects[9].iTop = 0; gExplosiveDescStatsRects[9].iRight = 1; gExplosiveDescStatsRects[9].iBottom = 1; - gExplosiveDescStatsRects[10].iLeft = 0; gExplosiveDescStatsRects[10].iTop = 0; gExplosiveDescStatsRects[10].iRight = 1; gExplosiveDescStatsRects[10].iBottom = 1; - gExplosiveDescStatsRects[11].iLeft = 0; gExplosiveDescStatsRects[11].iTop = 0; gExplosiveDescStatsRects[11].iRight = 1; gExplosiveDescStatsRects[11].iBottom = 1; - gExplosiveDescStatsRects[12].iLeft = 0; gExplosiveDescStatsRects[12].iTop = 0; gExplosiveDescStatsRects[12].iRight = 1; gExplosiveDescStatsRects[12].iBottom = 1; - gExplosiveDescStatsRects[13].iLeft = 0; gExplosiveDescStatsRects[13].iTop = 0; gExplosiveDescStatsRects[13].iRight = 1; gExplosiveDescStatsRects[13].iBottom = 1; - gExplosiveDescStatsRects[14].iLeft = 0; gExplosiveDescStatsRects[14].iTop = 0; gExplosiveDescStatsRects[14].iRight = 1; gExplosiveDescStatsRects[14].iBottom = 1; - gExplosiveDescStatsRects[15].iLeft = 0; gExplosiveDescStatsRects[15].iTop = 0; gExplosiveDescStatsRects[15].iRight = 1; gExplosiveDescStatsRects[15].iBottom = 1; - gExplosiveDescStatsRects[16].iLeft = 0; gExplosiveDescStatsRects[16].iTop = 0; gExplosiveDescStatsRects[16].iRight = 1; gExplosiveDescStatsRects[16].iBottom = 1; - gExplosiveDescStatsRects[17].iLeft = 0; gExplosiveDescStatsRects[17].iTop = 0; gExplosiveDescStatsRects[17].iRight = 1; gExplosiveDescStatsRects[17].iBottom = 1; - gExplosiveDescStatsRects[18].iLeft = 0; gExplosiveDescStatsRects[18].iTop = 0; gExplosiveDescStatsRects[18].iRight = 1; gExplosiveDescStatsRects[18].iBottom = 1; - gExplosiveDescStatsRects[19].iLeft = 0; gExplosiveDescStatsRects[19].iTop = 0; gExplosiveDescStatsRects[19].iRight = 1; gExplosiveDescStatsRects[19].iBottom = 1; + // Second Data Row (Weight) + gODBItemDescRegions[1][0].sLeft = 270 + gsInvDescX; gODBItemDescRegions[1][0].sTop = 25 + gsInvDescY; gODBItemDescRegions[1][0].sRight = 418 + gsInvDescX; gODBItemDescRegions[1][0].sBottom = 33 + gsInvDescY; - gMiscItemDescStatsRects[0].iLeft = 273; gMiscItemDescStatsRects[0].iTop = 12; gMiscItemDescStatsRects[0].iRight = 370; gMiscItemDescStatsRects[0].iBottom = 23; // Column 1 - gMiscItemDescStatsRects[1].iLeft = 273; gMiscItemDescStatsRects[1].iTop = 24; gMiscItemDescStatsRects[1].iRight = 370; gMiscItemDescStatsRects[1].iBottom = 35; - gMiscItemDescStatsRects[2].iLeft = 273; gMiscItemDescStatsRects[2].iTop = 36; gMiscItemDescStatsRects[2].iRight = 370; gMiscItemDescStatsRects[2].iBottom = 47; - gMiscItemDescStatsRects[3].iLeft = 273; gMiscItemDescStatsRects[3].iTop = 48; gMiscItemDescStatsRects[3].iRight = 370; gMiscItemDescStatsRects[3].iBottom = 59; - gMiscItemDescStatsRects[4].iLeft = 273; gMiscItemDescStatsRects[4].iTop = 60; gMiscItemDescStatsRects[4].iRight = 370; gMiscItemDescStatsRects[4].iBottom = 71; - gMiscItemDescStatsRects[5].iLeft = 273; gMiscItemDescStatsRects[5].iTop = 72; gMiscItemDescStatsRects[5].iRight = 370; gMiscItemDescStatsRects[5].iBottom = 83; - gMiscItemDescStatsRects[6].iLeft = 273; gMiscItemDescStatsRects[6].iTop = 84; gMiscItemDescStatsRects[6].iRight = 370; gMiscItemDescStatsRects[6].iBottom = 95; - gMiscItemDescStatsRects[7].iLeft = 374; gMiscItemDescStatsRects[7].iTop = 12; gMiscItemDescStatsRects[7].iRight = 471; gMiscItemDescStatsRects[7].iBottom = 23; // Column Two - gMiscItemDescStatsRects[8].iLeft = 374; gMiscItemDescStatsRects[8].iTop = 24; gMiscItemDescStatsRects[8].iRight = 471; gMiscItemDescStatsRects[8].iBottom = 35; - gMiscItemDescStatsRects[9].iLeft = 374; gMiscItemDescStatsRects[9].iTop = 36; gMiscItemDescStatsRects[9].iRight = 471; gMiscItemDescStatsRects[9].iBottom = 47; - gMiscItemDescStatsRects[10].iLeft = 374; gMiscItemDescStatsRects[10].iTop = 48; gMiscItemDescStatsRects[10].iRight = 471; gMiscItemDescStatsRects[10].iBottom = 59; - gMiscItemDescStatsRects[11].iLeft = 374; gMiscItemDescStatsRects[11].iTop = 60; gMiscItemDescStatsRects[11].iRight = 471; gMiscItemDescStatsRects[11].iBottom = 71; - gMiscItemDescStatsRects[12].iLeft = 0; gMiscItemDescStatsRects[12].iTop = 0; gMiscItemDescStatsRects[12].iRight = 1; gMiscItemDescStatsRects[12].iBottom = 1; // Placeholders - gMiscItemDescStatsRects[13].iLeft = 0; gMiscItemDescStatsRects[13].iTop = 0; gMiscItemDescStatsRects[13].iRight = 1; gMiscItemDescStatsRects[13].iBottom = 1; - gMiscItemDescStatsRects[14].iLeft = 0; gMiscItemDescStatsRects[14].iTop = 0; gMiscItemDescStatsRects[14].iRight = 1; gMiscItemDescStatsRects[14].iBottom = 1; - gMiscItemDescStatsRects[15].iLeft = 0; gMiscItemDescStatsRects[15].iTop = 0; gMiscItemDescStatsRects[15].iRight = 1; gMiscItemDescStatsRects[15].iBottom = 1; - gMiscItemDescStatsRects[16].iLeft = 0; gMiscItemDescStatsRects[16].iTop = 0; gMiscItemDescStatsRects[16].iRight = 1; gMiscItemDescStatsRects[16].iBottom = 1; - gMiscItemDescStatsRects[17].iLeft = 0; gMiscItemDescStatsRects[17].iTop = 0; gMiscItemDescStatsRects[17].iRight = 1; gMiscItemDescStatsRects[17].iBottom = 1; - gMiscItemDescStatsRects[18].iLeft = 0; gMiscItemDescStatsRects[18].iTop = 0; gMiscItemDescStatsRects[18].iRight = 1; gMiscItemDescStatsRects[18].iBottom = 1; - gMiscItemDescStatsRects[19].iLeft = 0; gMiscItemDescStatsRects[19].iTop = 0; gMiscItemDescStatsRects[19].iRight = 1; gMiscItemDescStatsRects[19].iBottom = 1; + // Third Data Row (Usually basic Gun Statistics) + // Left Side + gODBItemDescRegions[2][0].sLeft = 270 + gsInvDescX; gODBItemDescRegions[2][0].sTop = 40 + gsInvDescY; + gODBItemDescRegions[2][3].sLeft = 209 + gsInvDescX; gODBItemDescRegions[2][3].sTop = 40 + gsInvDescY; gODBItemDescRegions[2][3].sRight = 334 + gsInvDescX; gODBItemDescRegions[2][3].sBottom = 48 + gsInvDescY; + + // Right Side + gODBItemDescRegions[2][4].sLeft = 346 + gsInvDescX; gODBItemDescRegions[2][4].sTop = 40 + gsInvDescY; + gODBItemDescRegions[2][7].sLeft = 383 + gsInvDescX; gODBItemDescRegions[2][7].sTop = 40 + gsInvDescY; gODBItemDescRegions[2][7].sRight = 418 + gsInvDescX; gODBItemDescRegions[2][7].sBottom = 48 + gsInvDescY; + + // Fourth Data Row (Usually AP Costs) + // Left Side + gODBItemDescRegions[3][0].sLeft = 270 + gsInvDescX; gODBItemDescRegions[3][0].sTop = 50 + gsInvDescY; + gODBItemDescRegions[3][1].sLeft = 290 + gsInvDescX; gODBItemDescRegions[3][1].sTop = 49 + gsInvDescY; + gODBItemDescRegions[3][2].sLeft = 302 + gsInvDescX; gODBItemDescRegions[3][2].sTop = 50 + gsInvDescY; + gODBItemDescRegions[3][3].sLeft = 309 + gsInvDescX; gODBItemDescRegions[3][3].sTop = 50 + gsInvDescY; gODBItemDescRegions[3][3].sRight = 334 + gsInvDescX; gODBItemDescRegions[3][3].sBottom = 58 + gsInvDescY; + // Right Side + gODBItemDescRegions[3][4].sLeft = 344 + gsInvDescX; gODBItemDescRegions[3][4].sTop = 49 + gsInvDescY; + gODBItemDescRegions[3][6].sLeft = 372 + gsInvDescX; gODBItemDescRegions[3][6].sTop = 50 + gsInvDescY; + gODBItemDescRegions[3][7].sLeft = 383 + gsInvDescX; gODBItemDescRegions[3][7].sTop = 50 + gsInvDescY; gODBItemDescRegions[3][7].sRight = 418 + gsInvDescX; gODBItemDescRegions[3][7].sBottom = 58 + gsInvDescY; + + // Description Text Area + gItemDescTextRegions[0].sLeft = 265 + gsInvDescX; gItemDescTextRegions[0].sTop = 70 + gsInvDescY; gItemDescTextRegions[0].sRight = 415 + gsInvDescX; + + // PROS/CONS areas + gItemDescTextRegions[3].sLeft = 265 + gsInvDescX; gItemDescTextRegions[3].sTop = 170 + gsInvDescY; gItemDescTextRegions[3].sRight = 415 + gsInvDescX; gItemDescTextRegions[3].sBottom = 188 + gsInvDescY; + gItemDescTextRegions[4].sLeft = 295 + gsInvDescX; gItemDescTextRegions[4].sTop = 170 + gsInvDescY; gItemDescTextRegions[4].sRight = 415 + gsInvDescX; gItemDescTextRegions[4].sBottom = 188 + gsInvDescY; + gItemDescTextRegions[5].sLeft = 265 + gsInvDescX; gItemDescTextRegions[5].sTop = 180 + gsInvDescY; gItemDescTextRegions[5].sRight = 415 + gsInvDescX; gItemDescTextRegions[5].sBottom = 200 + gsInvDescY; + gItemDescTextRegions[6].sLeft = 295 + gsInvDescX; gItemDescTextRegions[6].sTop = 180 + gsInvDescY; gItemDescTextRegions[6].sRight = 415 + gsInvDescX; gItemDescTextRegions[6].sBottom = 200 + gsInvDescY; + } + else + { + gItemDescLBEBackground[0].sLeft = 320 + gsInvDescX; gItemDescLBEBackground[0].sTop = 8 + gsInvDescY; + gItemDescLBEBackground[1].sLeft = 3 + gsInvDescX; gItemDescLBEBackground[1].sTop = 137 + gsInvDescY; + gItemDescLBEBackground[2].sLeft = 320 + gsInvDescX; gItemDescLBEBackground[2].sTop = 8 + gsInvDescY; + gItemDescLBEBackground[3].sLeft = 320 + gsInvDescX; gItemDescLBEBackground[3].sTop = 8 + gsInvDescY; + + ////////////////// MONEY TEXT COORDINATES + gMoneyStats[0].sX = 204 + gsInvDescX; gMoneyStats[0].sY = 14 + gsInvDescY; // Money + gMoneyStats[1].sX = 212 + gsInvDescX; gMoneyStats[1].sY = 24 + gsInvDescY; // Remaining + gMoneyStats[2].sX = 204 + gsInvDescX; gMoneyStats[2].sY = 41 + gsInvDescY; // Money + gMoneyStats[3].sX = 212 + gsInvDescX; gMoneyStats[3].sY = 51 + gsInvDescY; // Removing + gMoneyStats[4].sX = 282 + gsInvDescX; gMoneyStats[4].sY = 24 + gsInvDescY; // AMT remaining + gMoneyStats[5].sX = 282 + gsInvDescX; gMoneyStats[5].sY = 51 + gsInvDescY; // AMT removing + + ////////////////////////////////////////////////////////////////////// + // ODB has exactly four separate regions. Each has 8 sub-regions, which can be + // used to display data at irregular intervals. This allows ODB to function as + // smoothly as EDB does. + // In addition, ODB uses some of the UDB regions to display things like PROS/CONS + // and Description Text. This reduces the use of redundant arrays... + + // First Data Row (Condition / Ammo label) + gODBItemDescRegions[0][0].sLeft = 202 + gsInvDescX; gODBItemDescRegions[0][0].sTop = 15 + gsInvDescY; gODBItemDescRegions[0][0].sRight = 311 + gsInvDescX; gODBItemDescRegions[0][0].sBottom = 23 + gsInvDescY; + + // Second Data Row (Weight) + gODBItemDescRegions[1][0].sLeft = 202 + gsInvDescX; gODBItemDescRegions[1][0].sTop = 25 + gsInvDescY; gODBItemDescRegions[1][0].sRight = 311 + gsInvDescX; gODBItemDescRegions[1][0].sBottom = 33 + gsInvDescY; + + // Third Data Row (Usually basic Gun Statistics) + // Left Side + gODBItemDescRegions[2][0].sLeft = 202 + gsInvDescX; gODBItemDescRegions[2][0].sTop = 40 + gsInvDescY; + gODBItemDescRegions[2][3].sLeft = 141 + gsInvDescX; gODBItemDescRegions[2][3].sTop = 40 + gsInvDescY; gODBItemDescRegions[2][3].sRight = 260 + gsInvDescX; gODBItemDescRegions[2][3].sBottom = 48 + gsInvDescY; + + // Right Side + gODBItemDescRegions[2][4].sLeft = 265 + gsInvDescX; gODBItemDescRegions[2][4].sTop = 40 + gsInvDescY; + gODBItemDescRegions[2][7].sLeft = 302 + gsInvDescX; gODBItemDescRegions[2][7].sTop = 40 + gsInvDescY; gODBItemDescRegions[2][7].sRight = 311 + gsInvDescX; gODBItemDescRegions[2][7].sBottom = 48 + gsInvDescY; + + // Fourth Data Row (Usually AP Costs) + // Left Side + gODBItemDescRegions[3][0].sLeft = 202 + gsInvDescX; gODBItemDescRegions[3][0].sTop = 50 + gsInvDescY; + gODBItemDescRegions[3][1].sLeft = 222 + gsInvDescX; gODBItemDescRegions[3][1].sTop = 49 + gsInvDescY; + gODBItemDescRegions[3][2].sLeft = 234 + gsInvDescX; gODBItemDescRegions[3][2].sTop = 50 + gsInvDescY; + gODBItemDescRegions[3][3].sLeft = 241 + gsInvDescX; gODBItemDescRegions[3][3].sTop = 50 + gsInvDescY; gODBItemDescRegions[3][3].sRight = 260 + gsInvDescX; gODBItemDescRegions[3][3].sBottom = 58 + gsInvDescY; + // Right Side + gODBItemDescRegions[3][4].sLeft = 263 + gsInvDescX; gODBItemDescRegions[3][4].sTop = 49 + gsInvDescY; + gODBItemDescRegions[3][6].sLeft = 291 + gsInvDescX; gODBItemDescRegions[3][6].sTop = 50 + gsInvDescY; + gODBItemDescRegions[3][7].sLeft = 302 + gsInvDescX; gODBItemDescRegions[3][7].sTop = 50 + gsInvDescY; gODBItemDescRegions[3][7].sRight = 311 + gsInvDescX; gODBItemDescRegions[3][7].sBottom = 58 + gsInvDescY; + + // Description Text Area + gItemDescTextRegions[0].sLeft = 11 + gsInvDescX; gItemDescTextRegions[0].sTop = 80 + gsInvDescY; gItemDescTextRegions[0].sRight = 300 + gsInvDescX; + + // PROS/CONS areas + gItemDescTextRegions[3].sLeft = 11 + gsInvDescX; gItemDescTextRegions[3].sTop = 110 + gsInvDescY; gItemDescTextRegions[3].sRight = 300 + gsInvDescX; gItemDescTextRegions[3].sBottom = 118 + gsInvDescY; + gItemDescTextRegions[4].sLeft = 47 + gsInvDescX; gItemDescTextRegions[4].sTop = 110 + gsInvDescY; gItemDescTextRegions[4].sRight = 300 + gsInvDescX; gItemDescTextRegions[4].sBottom = 118 + gsInvDescY; + gItemDescTextRegions[5].sLeft = 11 + gsInvDescX; gItemDescTextRegions[5].sTop = 120 + gsInvDescY; gItemDescTextRegions[5].sRight = 300 + gsInvDescX; gItemDescTextRegions[5].sBottom = 130 + gsInvDescY; + gItemDescTextRegions[6].sLeft = 47 + gsInvDescX; gItemDescTextRegions[6].sTop = 120 + gsInvDescY; gItemDescTextRegions[6].sRight = 300 + gsInvDescX; gItemDescTextRegions[6].sBottom = 130 + gsInvDescY; + } } + } } @@ -748,339 +704,57 @@ void SetupItemDescAttachmentsXY(UINT8 ID, INT16 sX, INT16 sY, INT16 sHeight, INT gItemDescAttachmentsXY[ID].sBarDy = sBarDy; } -void InitDescStatCoords() -{ +void InitDescStatCoords(OBJECTTYPE *pObject) +{ + std::vector usAttachmentSlotIndexVector = GetItemSlots(pObject); + memset(gItemDescAttachmentsXY, 0, MAX_ATTACHMENTS); if( guiCurrentScreen == MAP_SCREEN ) - { - SetupItemDescAttachmentsXY(0, 175, 9, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); - SetupItemDescAttachmentsXY(1, 213, 9, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); - SetupItemDescAttachmentsXY(2, 175, 37, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); - SetupItemDescAttachmentsXY(3, 213, 37, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + { + //WarmSteel - If we're using the new attachment system and the item in question does not have an empty attachment list. + if(UsingNewAttachmentSystem()==true && !usAttachmentSlotIndexVector.empty() && UseNASDesc(pObject)) + { + //Loop throught the attachments and get their slot id's + for (UINT8 x = 0; x < usAttachmentSlotIndexVector.size(); x++){ + //WarmSteel - Tell this slot where it's supposed to be. + if(AttachmentSlots[usAttachmentSlotIndexVector[x]].fBigSlot){ + SetupItemDescAttachmentsXY(x, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosX, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosY, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_BIG_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + } else { + SetupItemDescAttachmentsXY(x, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosX, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosY, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + } + } + } + //Not a valid item for NAS, use default + else + { + SetupItemDescAttachmentsXY(0, 175, 9, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + SetupItemDescAttachmentsXY(1, 213, 9, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + SetupItemDescAttachmentsXY(2, 175, 37, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + SetupItemDescAttachmentsXY(3, 213, 37, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + } + } else { - SetupItemDescAttachmentsXY(0, 133, 11, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); - SetupItemDescAttachmentsXY(1, 167, 11, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); - SetupItemDescAttachmentsXY(2, 133, 38, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); - SetupItemDescAttachmentsXY(3, 167, 38, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); - } - - if(UsingEDBSystem() > 0) - { - if( guiCurrentScreen == MAP_SCREEN ) + //WarmSteel - If we're using the new attachment system and the item in question does not have an empty attachment list. + if(UsingNewAttachmentSystem()==true && !usAttachmentSlotIndexVector.empty() && UseNASDesc(pObject)) { - gWeaponStats[0].sX = 52; gWeaponStats[0].sY = 98; gWeaponStats[0].sValDx = 76; // 0) STATUS - gWeaponStats[1].sX = 52; gWeaponStats[1].sY = 108; gWeaponStats[1].sValDx = 76; // 1) WEIGHT - // Labels and Values - gWeaponStats[2].sX = 47; gWeaponStats[2].sY = 124; gWeaponStats[2].sValDx = 30; // 2) COL 1; ROW 1 - gWeaponStats[3].sX = 47; gWeaponStats[3].sY = 136; gWeaponStats[3].sValDx = 30; // 3) COL 1; ROW 2 - gWeaponStats[4].sX = 47; gWeaponStats[4].sY = 148; gWeaponStats[4].sValDx = 30; // 4) COL 1; ROW 3 - gWeaponStats[5].sX = 47; gWeaponStats[5].sY = 160; gWeaponStats[5].sValDx = 30; // 5) COL 1; ROW 4 - gWeaponStats[6].sX = 47; gWeaponStats[6].sY = 172; gWeaponStats[6].sValDx = 30; // 6) COL 1; ROW 5 - gWeaponStats[7].sX = 47; gWeaponStats[7].sY = 184; gWeaponStats[7].sValDx = 30; // 7) COL 1; ROW 6 - gWeaponStats[8].sX = 47; gWeaponStats[8].sY = 196; gWeaponStats[8].sValDx = 30; // 8) COL 1; ROW 7 - gWeaponStats[9].sX = 112; gWeaponStats[9].sY = 124; gWeaponStats[9].sValDx = 29; // 9) COL 2; ROW 1 - gWeaponStats[10].sX = 112; gWeaponStats[10].sY = 136; gWeaponStats[10].sValDx = 29; // 10) COL 2; ROW 2 - gWeaponStats[11].sX = 112; gWeaponStats[11].sY = 148; gWeaponStats[11].sValDx = 29; // 11) COL 2; ROW 3 - gWeaponStats[12].sX = 112; gWeaponStats[12].sY = 160; gWeaponStats[12].sValDx = 29; // 12) COL 2; ROW 4 - gWeaponStats[13].sX = 112; gWeaponStats[13].sY = 172; gWeaponStats[13].sValDx = 29; // 13) COL 2; ROW 5 - gWeaponStats[14].sX = 112; gWeaponStats[14].sY = 184; gWeaponStats[14].sValDx = 29; // 14) COL 2; ROW 6 - gWeaponStats[15].sX = 112; gWeaponStats[15].sY = 196; gWeaponStats[15].sValDx = 29; // 15) COL 2; ROW 7 - gWeaponStats[16].sX = 174; gWeaponStats[16].sY = 124; gWeaponStats[16].sValDx = 30; // 16) COL 3; ROW 1 - gWeaponStats[17].sX = 174; gWeaponStats[17].sY = 136; gWeaponStats[17].sValDx = 30; // 17) COL 3; ROW 2 - gWeaponStats[18].sX = 174; gWeaponStats[18].sY = 148; gWeaponStats[18].sValDx = 30; // 18) COL 3; ROW 3 - gWeaponStats[19].sX = 174; gWeaponStats[19].sY = 160; gWeaponStats[19].sValDx = 30; // 19) COL 3; ROW 4 - gWeaponStats[20].sX = 174; gWeaponStats[20].sY = 172; gWeaponStats[20].sValDx = 30; // 20) COL 3; ROW 5 - gWeaponStats[21].sX = 174; gWeaponStats[21].sY = 184; gWeaponStats[21].sValDx = 30; // 21) COL 3; ROW 6 - gWeaponStats[22].sX = 174; gWeaponStats[22].sY = 196; gWeaponStats[22].sValDx = 30; // 22) COL 3; ROW 7 - // EQUALS signs - gWeaponStats[23].sX = 79; gWeaponStats[23].sY = 124; gWeaponStats[23].sValDx = 0; // 23) COL 1; ROW 1 - gWeaponStats[24].sX = 79; gWeaponStats[24].sY = 136; gWeaponStats[24].sValDx = 0; // 24) COL 1; ROW 2 - gWeaponStats[25].sX = 79; gWeaponStats[25].sY = 148; gWeaponStats[25].sValDx = 0; // 25) COL 1; ROW 3 - gWeaponStats[26].sX = 79; gWeaponStats[26].sY = 160; gWeaponStats[26].sValDx = 0; // 26) COL 1; ROW 4 - gWeaponStats[27].sX = 79; gWeaponStats[27].sY = 172; gWeaponStats[27].sValDx = 0; // 27) COL 1; ROW 5 - gWeaponStats[28].sX = 79; gWeaponStats[28].sY = 184; gWeaponStats[28].sValDx = 0; // 28) COL 1; ROW 6 - gWeaponStats[29].sX = 79; gWeaponStats[29].sY = 196; gWeaponStats[29].sValDx = 0; // 29) COL 1; ROW 7 - gWeaponStats[30].sX = 145; gWeaponStats[30].sY = 124; gWeaponStats[30].sValDx = 0; // 30) COL 2; ROW 1 - gWeaponStats[31].sX = 145; gWeaponStats[31].sY = 136; gWeaponStats[31].sValDx = 0; // 31) COL 2; ROW 2 - gWeaponStats[32].sX = 145; gWeaponStats[32].sY = 148; gWeaponStats[32].sValDx = 0; // 32) COL 2; ROW 3 - gWeaponStats[33].sX = 145; gWeaponStats[33].sY = 160; gWeaponStats[33].sValDx = 0; // 33) COL 2; ROW 4 - gWeaponStats[34].sX = 145; gWeaponStats[34].sY = 172; gWeaponStats[34].sValDx = 0; // 34) COL 2; ROW 5 - gWeaponStats[35].sX = 145; gWeaponStats[35].sY = 184; gWeaponStats[35].sValDx = 0; // 35) COL 2; ROW 6 - gWeaponStats[36].sX = 145; gWeaponStats[36].sY = 196; gWeaponStats[36].sValDx = 0; // 36) COL 2; ROW 7 - gWeaponStats[37].sX = 206; gWeaponStats[37].sY = 124; gWeaponStats[37].sValDx = 0; // 37) COL 3; ROW 1 - gWeaponStats[38].sX = 206; gWeaponStats[38].sY = 136; gWeaponStats[38].sValDx = 0; // 38) COL 3; ROW 2 - gWeaponStats[39].sX = 206; gWeaponStats[39].sY = 148; gWeaponStats[39].sValDx = 0; // 39) COL 3; ROW 3 - gWeaponStats[40].sX = 206; gWeaponStats[40].sY = 160; gWeaponStats[40].sValDx = 0; // 40) COL 3; ROW 4 - gWeaponStats[41].sX = 206; gWeaponStats[41].sY = 172; gWeaponStats[41].sValDx = 0; // 41) COL 3; ROW 5 - gWeaponStats[42].sX = 206; gWeaponStats[42].sY = 184; gWeaponStats[42].sValDx = 0; // 42) COL 3; ROW 6 - gWeaponStats[43].sX = 206; gWeaponStats[43].sY = 196; gWeaponStats[43].sValDx = 0; // 43) COL 3; ROW 7 - // Nonregular locations for explosive data (COL 2; ROW 3) - gWeaponStats[44].sX = 116; gWeaponStats[44].sY = 148; gWeaponStats[44].sValDx = 0; // 44) COL 2; ROW 3; LOC 1 - gWeaponStats[45].sX = 134; gWeaponStats[45].sY = 148; gWeaponStats[45].sValDx = 0; // 45) COL 2; ROW 3; LOC 2 - gWeaponStats[46].sX = 150; gWeaponStats[46].sY = 148; gWeaponStats[46].sValDx = 0; // 46) COL 2; ROW 3; LOC 3 - - gMoneyStats[0].sX = 51; gMoneyStats[0].sY = 124; gMoneyStats[0].sValDx = 45; // Money - gMoneyStats[1].sX = 61; gMoneyStats[1].sY = 136; gMoneyStats[1].sValDx = 65; // Remaining - gMoneyStats[2].sX = 51; gMoneyStats[2].sY = 172; gMoneyStats[2].sValDx = 45; // Money - gMoneyStats[3].sX = 61; gMoneyStats[3].sY = 184; gMoneyStats[3].sValDx = 65; // Removing - gMoneyStats[4].sX = 47; gMoneyStats[4].sY = 148; gMoneyStats[4].sValDx = 62; // AMT remaining - gMoneyStats[5].sX = 47; gMoneyStats[5].sY = 196; gMoneyStats[5].sValDx = 62; // AMT removing - - gItemDescProsConsRects[0].iLeft = 14; gItemDescProsConsRects[0].iTop = 291; gItemDescProsConsRects[0].iRight = 250; gItemDescProsConsRects[0].iBottom = 298; - gItemDescProsConsRects[1].iLeft = 14; gItemDescProsConsRects[1].iTop = 299; gItemDescProsConsRects[1].iRight = 250; gItemDescProsConsRects[1].iBottom = 306; - } - else - { - if (UsingEDBSystem() == 1) // NIV EDB - { - gWeaponStats[0].sX = 205; gWeaponStats[0].sY = 14; gWeaponStats[0].sValDx = 91; // 0) STATUS - gWeaponStats[1].sX = 205; gWeaponStats[1].sY = 24; gWeaponStats[1].sValDx = 91; // 1) WEIGHT - // Labels and Values - gWeaponStats[2].sX = 203; gWeaponStats[2].sY = 44; gWeaponStats[2].sValDx = 30; // 2) COL 1; ROW 1 - gWeaponStats[3].sX = 203; gWeaponStats[3].sY = 56; gWeaponStats[3].sValDx = 30; // 3) COL 1; ROW 2 - gWeaponStats[4].sX = 203; gWeaponStats[4].sY = 68; gWeaponStats[4].sValDx = 30; // 4) COL 1; ROW 3 - gWeaponStats[5].sX = 203; gWeaponStats[5].sY = 80; gWeaponStats[5].sValDx = 30; // 5) COL 1; ROW 4 - gWeaponStats[6].sX = 203; gWeaponStats[6].sY = 92; gWeaponStats[6].sValDx = 30; // 6) COL 1; ROW 5 - gWeaponStats[7].sX = 203; gWeaponStats[7].sY = 104; gWeaponStats[7].sValDx = 30; // 7) COL 1; ROW 6 - gWeaponStats[8].sX = 203; gWeaponStats[8].sY = 116; gWeaponStats[8].sValDx = 30; // 8) COL 1; ROW 7 - gWeaponStats[9].sX = 268; gWeaponStats[9].sY = 44; gWeaponStats[9].sValDx = 30; // 9) COL 2; ROW 1 - gWeaponStats[10].sX = 268; gWeaponStats[10].sY = 56; gWeaponStats[10].sValDx = 30; // 10) COL 2; ROW 2 - gWeaponStats[11].sX = 268; gWeaponStats[11].sY = 68; gWeaponStats[11].sValDx = 30; // 11) COL 2; ROW 3 - gWeaponStats[12].sX = 268; gWeaponStats[12].sY = 80; gWeaponStats[12].sValDx = 30; // 12) COL 2; ROW 4 - gWeaponStats[13].sX = 268; gWeaponStats[13].sY = 92; gWeaponStats[13].sValDx = 30; // 13) COL 2; ROW 5 - gWeaponStats[14].sX = 268; gWeaponStats[14].sY = 104; gWeaponStats[14].sValDx = 30; // 14) COL 2; ROW 6 - gWeaponStats[15].sX = 268; gWeaponStats[15].sY = 116; gWeaponStats[15].sValDx = 30; // 15) COL 2; ROW 7 - gWeaponStats[16].sX = 203; gWeaponStats[16].sY = 136; gWeaponStats[16].sValDx = 30; // 16) COL 3; ROW 1 - gWeaponStats[17].sX = 203; gWeaponStats[17].sY = 160; gWeaponStats[17].sValDx = 30; // 17) COL 3; ROW 3 - gWeaponStats[18].sX = 268; gWeaponStats[18].sY = 136; gWeaponStats[18].sValDx = 30; // 18) COL 4; ROW 1 - gWeaponStats[19].sX = 268; gWeaponStats[19].sY = 148; gWeaponStats[19].sValDx = 30; // 19) COL 4; ROW 2 - gWeaponStats[20].sX = 268; gWeaponStats[20].sY = 160; gWeaponStats[20].sValDx = 30; // 20) COL 4; ROW 3 - gWeaponStats[21].sX = 268; gWeaponStats[21].sY = 172; gWeaponStats[21].sValDx = 30; // 21) COL 4; ROW 4 - gWeaponStats[22].sX = 203; gWeaponStats[22].sY = 172; gWeaponStats[22].sValDx = 30; // 22) COL 3; ROW 4 - // EQUALS signs - gWeaponStats[23].sX = 235; gWeaponStats[23].sY = 44; gWeaponStats[23].sValDx = 0; // 23) COL 1; ROW 1 - gWeaponStats[24].sX = 235; gWeaponStats[24].sY = 56; gWeaponStats[24].sValDx = 0; // 24) COL 1; ROW 2 - gWeaponStats[25].sX = 235; gWeaponStats[25].sY = 68; gWeaponStats[25].sValDx = 0; // 25) COL 1; ROW 3 - gWeaponStats[26].sX = 235; gWeaponStats[26].sY = 80; gWeaponStats[26].sValDx = 0; // 26) COL 1; ROW 4 - gWeaponStats[27].sX = 235; gWeaponStats[27].sY = 92; gWeaponStats[27].sValDx = 0; // 27) COL 1; ROW 5 - gWeaponStats[28].sX = 235; gWeaponStats[28].sY = 104; gWeaponStats[28].sValDx = 0; // 28) COL 1; ROW 6 - gWeaponStats[29].sX = 235; gWeaponStats[29].sY = 116; gWeaponStats[29].sValDx = 0; // 29) COL 1; ROW 7 - gWeaponStats[30].sX = 300; gWeaponStats[30].sY = 44; gWeaponStats[30].sValDx = 0; // 30) COL 2; ROW 1 - gWeaponStats[31].sX = 300; gWeaponStats[31].sY = 56; gWeaponStats[31].sValDx = 0; // 31) COL 2; ROW 2 - gWeaponStats[32].sX = 300; gWeaponStats[32].sY = 68; gWeaponStats[32].sValDx = 0; // 32) COL 2; ROW 3 - gWeaponStats[33].sX = 300; gWeaponStats[33].sY = 80; gWeaponStats[33].sValDx = 0; // 33) COL 2; ROW 4 - gWeaponStats[34].sX = 300; gWeaponStats[34].sY = 92; gWeaponStats[34].sValDx = 0; // 34) COL 2; ROW 5 - gWeaponStats[35].sX = 300; gWeaponStats[35].sY = 104; gWeaponStats[35].sValDx = 0; // 35) COL 2; ROW 6 - gWeaponStats[36].sX = 300; gWeaponStats[36].sY = 116; gWeaponStats[36].sValDx = 0; // 36) COL 2; ROW 7 - gWeaponStats[37].sX = 235; gWeaponStats[37].sY = 136; gWeaponStats[37].sValDx = 0; // 37) COL 3; ROW 1 - gWeaponStats[38].sX = 235; gWeaponStats[38].sY = 160; gWeaponStats[38].sValDx = 0; // 38) COL 3; ROW 3 - gWeaponStats[39].sX = 300; gWeaponStats[39].sY = 136; gWeaponStats[39].sValDx = 0; // 39) COL 4; ROW 1 - gWeaponStats[40].sX = 300; gWeaponStats[40].sY = 148; gWeaponStats[40].sValDx = 0; // 40) COL 4; ROW 2 - gWeaponStats[41].sX = 300; gWeaponStats[41].sY = 160; gWeaponStats[41].sValDx = 0; // 41) COL 4; ROW 3 - gWeaponStats[42].sX = 300; gWeaponStats[42].sY = 172; gWeaponStats[42].sValDx = 0; // 42) COL 4; ROW 4 - gWeaponStats[43].sX = 235; gWeaponStats[43].sY = 172; gWeaponStats[43].sValDx = 0; // 43) COL 3; ROW 4 - // Nonregular locations for explosive radius values (COL 2; ROW 3) - gWeaponStats[44].sX = 273; gWeaponStats[44].sY = 68; gWeaponStats[44].sValDx = 0; // 44) COL 2; ROW 3; LOC 1 - Starting Radius - gWeaponStats[45].sX = 291; gWeaponStats[45].sY = 68; gWeaponStats[45].sValDx = 0; // 45) COL 2; ROW 3; LOC 2 - Single Radius - gWeaponStats[46].sX = 307; gWeaponStats[46].sY = 68; gWeaponStats[46].sValDx = 0; // 46) COL 2; ROW 3; LOC 3 - Final Radius - - gMoneyStats[0].sX = 203; gMoneyStats[0].sY = 44; gMoneyStats[0].sValDx = 45; // Money - gMoneyStats[1].sX = 213; gMoneyStats[1].sY = 56; gMoneyStats[1].sValDx = 65; // Remaining - gMoneyStats[2].sX = 203; gMoneyStats[2].sY = 92; gMoneyStats[2].sValDx = 45; // Money - gMoneyStats[3].sX = 213; gMoneyStats[3].sY = 104; gMoneyStats[3].sValDx = 65; // Removing - gMoneyStats[4].sX = 203; gMoneyStats[4].sY = 56; gMoneyStats[4].sValDx = 100; // AMT remaining - gMoneyStats[5].sX = 203; gMoneyStats[5].sY = 104; gMoneyStats[5].sValDx = 100; // AMT removing - - gItemDescProsConsRects[0].iLeft = 14; gItemDescProsConsRects[0].iTop = 169; gItemDescProsConsRects[0].iRight = 188; gItemDescProsConsRects[0].iBottom = 176; - gItemDescProsConsRects[1].iLeft = 14; gItemDescProsConsRects[1].iTop = 177; gItemDescProsConsRects[1].iRight = 188; gItemDescProsConsRects[1].iBottom = 184; - } - if (UsingEDBSystem() == 2) // OIV EDB - { - gWeaponStats[0].sX = 202; gWeaponStats[0].sY = 16; gWeaponStats[0].sValDx = 36; // 0) STATUS - gWeaponStats[1].sX = 202; gWeaponStats[1].sY = 64; gWeaponStats[1].sValDx = 36; // 1) WEIGHT - // Labels and Values - gWeaponStats[2].sX = 274; gWeaponStats[2].sY = 14; gWeaponStats[2].sValDx = 30; // 2) COL 1; ROW 1 - gWeaponStats[3].sX = 274; gWeaponStats[3].sY = 26; gWeaponStats[3].sValDx = 30; // 3) COL 1; ROW 2 - gWeaponStats[4].sX = 274; gWeaponStats[4].sY = 38; gWeaponStats[4].sValDx = 30; // 4) COL 1; ROW 3 - gWeaponStats[5].sX = 274; gWeaponStats[5].sY = 50; gWeaponStats[5].sValDx = 30; // 5) COL 1; ROW 4 - gWeaponStats[6].sX = 274; gWeaponStats[6].sY = 62; gWeaponStats[6].sValDx = 30; // 6) COL 1; ROW 5 - gWeaponStats[7].sX = 274; gWeaponStats[7].sY = 74; gWeaponStats[7].sValDx = 30; // 7) COL 1; ROW 6 - gWeaponStats[8].sX = 274; gWeaponStats[8].sY = 86; gWeaponStats[8].sValDx = 30; // 8) COL 1; ROW 7 - gWeaponStats[9].sX = 341; gWeaponStats[9].sY = 14; gWeaponStats[9].sValDx = 30; // 9) COL 2; ROW 1 - gWeaponStats[10].sX = 341; gWeaponStats[10].sY = 26; gWeaponStats[10].sValDx = 30; // 10) COL 2; ROW 2 - gWeaponStats[11].sX = 341; gWeaponStats[11].sY = 38; gWeaponStats[11].sValDx = 30; // 11) COL 2; ROW 3 - gWeaponStats[12].sX = 341; gWeaponStats[12].sY = 50; gWeaponStats[12].sValDx = 30; // 12) COL 2; ROW 4 - gWeaponStats[13].sX = 341; gWeaponStats[13].sY = 62; gWeaponStats[13].sValDx = 30; // 13) COL 2; ROW 5 - gWeaponStats[14].sX = 341; gWeaponStats[14].sY = 74; gWeaponStats[14].sValDx = 30; // 14) COL 2; ROW 6 - gWeaponStats[15].sX = 341; gWeaponStats[15].sY = 86; gWeaponStats[15].sValDx = 30; // 15) COL 2; ROW 7 - gWeaponStats[16].sX = 408; gWeaponStats[16].sY = 14; gWeaponStats[16].sValDx = 30; // 16) COL 3; ROW 1 - gWeaponStats[17].sX = 408; gWeaponStats[17].sY = 26; gWeaponStats[17].sValDx = 30; // 17) COL 3; ROW 2 - gWeaponStats[18].sX = 408; gWeaponStats[18].sY = 38; gWeaponStats[18].sValDx = 30; // 18) COL 3; ROW 3 - gWeaponStats[19].sX = 408; gWeaponStats[19].sY = 50; gWeaponStats[19].sValDx = 30; // 19) COL 3; ROW 4 - gWeaponStats[20].sX = 408; gWeaponStats[20].sY = 62; gWeaponStats[20].sValDx = 30; // 20) COL 3; ROW 5 - gWeaponStats[21].sX = 408; gWeaponStats[21].sY = 74; gWeaponStats[21].sValDx = 30; // 21) COL 3; ROW 6 - gWeaponStats[22].sX = 408; gWeaponStats[22].sY = 86; gWeaponStats[22].sValDx = 30; // 22) COL 3; ROW 7 - // EQUALS signs - gWeaponStats[23].sX = 306; gWeaponStats[23].sY = 14; gWeaponStats[23].sValDx = 0; // 23) COL 1; ROW 1 - gWeaponStats[24].sX = 306; gWeaponStats[24].sY = 26; gWeaponStats[24].sValDx = 0; // 24) COL 1; ROW 2 - gWeaponStats[25].sX = 306; gWeaponStats[25].sY = 38; gWeaponStats[25].sValDx = 0; // 25) COL 1; ROW 3 - gWeaponStats[26].sX = 306; gWeaponStats[26].sY = 50; gWeaponStats[26].sValDx = 0; // 26) COL 1; ROW 4 - gWeaponStats[27].sX = 306; gWeaponStats[27].sY = 62; gWeaponStats[27].sValDx = 0; // 27) COL 1; ROW 5 - gWeaponStats[28].sX = 306; gWeaponStats[28].sY = 74; gWeaponStats[28].sValDx = 0; // 28) COL 1; ROW 6 - gWeaponStats[29].sX = 306; gWeaponStats[29].sY = 86; gWeaponStats[29].sValDx = 0; // 39) COL 1; ROW 7 - gWeaponStats[30].sX = 373; gWeaponStats[30].sY = 14; gWeaponStats[30].sValDx = 0; // 30) COL 2; ROW 1 - gWeaponStats[31].sX = 373; gWeaponStats[31].sY = 26; gWeaponStats[31].sValDx = 0; // 31) COL 2; ROW 2 - gWeaponStats[32].sX = 373; gWeaponStats[32].sY = 38; gWeaponStats[32].sValDx = 0; // 32) COL 2; ROW 3 - gWeaponStats[33].sX = 373; gWeaponStats[33].sY = 50; gWeaponStats[33].sValDx = 0; // 33) COL 2; ROW 4 - gWeaponStats[34].sX = 373; gWeaponStats[34].sY = 62; gWeaponStats[34].sValDx = 0; // 34) COL 2; ROW 5 - gWeaponStats[35].sX = 373; gWeaponStats[35].sY = 74; gWeaponStats[35].sValDx = 0; // 35) COL 2; ROW 6 - gWeaponStats[36].sX = 373; gWeaponStats[36].sY = 86; gWeaponStats[36].sValDx = 0; // 36) COL 2; ROW 7 - gWeaponStats[37].sX = 440; gWeaponStats[37].sY = 14; gWeaponStats[37].sValDx = 0; // 37) COL 3; ROW 1 - gWeaponStats[38].sX = 440; gWeaponStats[38].sY = 26; gWeaponStats[38].sValDx = 0; // 48) COL 3; ROW 2 - gWeaponStats[39].sX = 440; gWeaponStats[39].sY = 38; gWeaponStats[39].sValDx = 0; // 49) COL 3; ROW 3 - gWeaponStats[40].sX = 440; gWeaponStats[40].sY = 50; gWeaponStats[40].sValDx = 0; // 40) COL 3; ROW 4 - gWeaponStats[41].sX = 440; gWeaponStats[41].sY = 62; gWeaponStats[41].sValDx = 0; // 41) COL 3; ROW 5 - gWeaponStats[42].sX = 440; gWeaponStats[42].sY = 74; gWeaponStats[42].sValDx = 0; // 42) COL 3; ROW 6 - gWeaponStats[43].sX = 440; gWeaponStats[43].sY = 86; gWeaponStats[43].sValDx = 0; // 43) COL 3; ROW 7 - // Nonregular locations for explosive radius values (COL 2; ROW 3) - gWeaponStats[44].sX = 345; gWeaponStats[44].sY = 38; gWeaponStats[44].sValDx = 0; // 44) COL 2; ROW 3; LOC 1 - Starting Radius - gWeaponStats[45].sX = 362; gWeaponStats[45].sY = 38; gWeaponStats[45].sValDx = 0; // 45) COL 2; ROW 3; LOC 2 - Single Radius - gWeaponStats[46].sX = 381; gWeaponStats[46].sY = 38; gWeaponStats[46].sValDx = 0; // 46) COL 2; ROW 3; LOC 3 - Final Radius - - gMoneyStats[0].sX = 202; gMoneyStats[0].sY = 14; gMoneyStats[0].sValDx = 45; // Money - gMoneyStats[1].sX = 202; gMoneyStats[1].sY = 26; gMoneyStats[1].sValDx = 65; // Remaining - gMoneyStats[2].sX = 202; gMoneyStats[2].sY = 62; gMoneyStats[2].sValDx = 45; // Money - gMoneyStats[3].sX = 202; gMoneyStats[3].sY = 74; gMoneyStats[3].sValDx = 65; // Removing - gMoneyStats[4].sX = 202; gMoneyStats[4].sY = 38; gMoneyStats[4].sValDx = 100; // AMT remaining - gMoneyStats[5].sX = 202; gMoneyStats[5].sY = 86; gMoneyStats[5].sValDx = 100; // AMT removing - - gItemDescProsConsRects[0].iLeft = 433; gItemDescProsConsRects[0].iTop = 104; gItemDescProsConsRects[0].iRight = 467; gItemDescProsConsRects[0].iBottom = 115; - gItemDescProsConsRects[1].iLeft = 433; gItemDescProsConsRects[1].iTop = 116; gItemDescProsConsRects[1].iRight = 467; gItemDescProsConsRects[1].iBottom = 127; + for (UINT8 x = 0; x < usAttachmentSlotIndexVector.size(); x++){ + //WarmSteel - Tell this slot where it's supposed to be. + if(AttachmentSlots[usAttachmentSlotIndexVector[x]].fBigSlot){ + SetupItemDescAttachmentsXY(x, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosX, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosY, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_BIG_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + } else { + SetupItemDescAttachmentsXY(x, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosX, AttachmentSlots[usAttachmentSlotIndexVector[x]].usDescPanelPosY, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-9, INV_BAR_DY); + } } } - } - else - { - if(guiCurrentScreen ==MAP_SCREEN) - { - gWeaponStats[0].sX = 52; gWeaponStats[0].sY = 98; gWeaponStats[0].sValDx = 89; // 0) STATUS - gWeaponStats[1].sX = 52; gWeaponStats[1].sY = 108; gWeaponStats[1].sValDx = 89; // 1) WEIGHT - gWeaponStats[2].sX = 117; gWeaponStats[2].sY = 124; gWeaponStats[2].sValDx = 21; // 2) RANGE - gWeaponStats[3].sX = 52; gWeaponStats[3].sY = 124; gWeaponStats[3].sValDx = 30; // 3) DAMAGE - gWeaponStats[4].sX = 52; gWeaponStats[4].sY = 98; gWeaponStats[4].sValDx = 80; - gWeaponStats[5].sX = 52; gWeaponStats[5].sY = 135; gWeaponStats[5].sValDx = 30; // 5) AP - gWeaponStats[6].sX = 117; gWeaponStats[6].sY = 135; gWeaponStats[6].sValDx = 25; - gWeaponStats[7].sX = 86; gWeaponStats[7].sY = 135; gWeaponStats[7].sValDx = 0; // 7) = - gWeaponStats[8].sX = 145; gWeaponStats[8].sY = 135; gWeaponStats[8].sValDx = 0; // 8) = - gWeaponStats[9].sX = 0; gWeaponStats[9].sY = 0; gWeaponStats[9].sValDx = 0; - gWeaponStats[10].sX = 0; gWeaponStats[10].sY = 0; gWeaponStats[10].sValDx = 0; - gWeaponStats[11].sX = 0; gWeaponStats[11].sY = 0; gWeaponStats[11].sValDx = 0; - gWeaponStats[12].sX = 0; gWeaponStats[12].sY = 0; gWeaponStats[12].sValDx = 0; - gWeaponStats[13].sX = 0; gWeaponStats[13].sY = 0; gWeaponStats[13].sValDx = 0; - gWeaponStats[14].sX = 0; gWeaponStats[14].sY = 0; gWeaponStats[14].sValDx = 0; - gWeaponStats[15].sX = 0; gWeaponStats[15].sY = 0; gWeaponStats[15].sValDx = 0; - gWeaponStats[16].sX = 0; gWeaponStats[16].sY = 0; gWeaponStats[16].sValDx = 0; - gWeaponStats[17].sX = 0; gWeaponStats[17].sY = 0; gWeaponStats[17].sValDx = 0; - gWeaponStats[18].sX = 0; gWeaponStats[18].sY = 0; gWeaponStats[18].sValDx = 0; - gWeaponStats[19].sX = 0; gWeaponStats[19].sY = 0; gWeaponStats[19].sValDx = 0; - gWeaponStats[20].sX = 0; gWeaponStats[20].sY = 0; gWeaponStats[20].sValDx = 0; - gWeaponStats[21].sX = 0; gWeaponStats[21].sY = 0; gWeaponStats[21].sValDx = 0; - gWeaponStats[22].sX = 0; gWeaponStats[22].sY = 0; gWeaponStats[22].sValDx = 0; - gWeaponStats[23].sX = 0; gWeaponStats[23].sY = 0; gWeaponStats[23].sValDx = 0; - gWeaponStats[24].sX = 0; gWeaponStats[24].sY = 0; gWeaponStats[24].sValDx = 0; - gWeaponStats[25].sX = 0; gWeaponStats[25].sY = 0; gWeaponStats[25].sValDx = 0; - gWeaponStats[26].sX = 0; gWeaponStats[26].sY = 0; gWeaponStats[26].sValDx = 0; - gWeaponStats[27].sX = 0; gWeaponStats[27].sY = 0; gWeaponStats[27].sValDx = 0; - gWeaponStats[28].sX = 0; gWeaponStats[28].sY = 0; gWeaponStats[28].sValDx = 0; - gWeaponStats[29].sX = 0; gWeaponStats[29].sY = 0; gWeaponStats[29].sValDx = 0; - gWeaponStats[30].sX = 0; gWeaponStats[30].sY = 0; gWeaponStats[30].sValDx = 0; - gWeaponStats[31].sX = 0; gWeaponStats[31].sY = 0; gWeaponStats[31].sValDx = 0; - gWeaponStats[32].sX = 0; gWeaponStats[32].sY = 0; gWeaponStats[32].sValDx = 0; - gWeaponStats[33].sX = 0; gWeaponStats[33].sY = 0; gWeaponStats[33].sValDx = 0; - gWeaponStats[34].sX = 0; gWeaponStats[34].sY = 0; gWeaponStats[34].sValDx = 0; - gWeaponStats[35].sX = 0; gWeaponStats[35].sY = 0; gWeaponStats[35].sValDx = 0; - gWeaponStats[36].sX = 0; gWeaponStats[36].sY = 0; gWeaponStats[36].sValDx = 0; - gWeaponStats[37].sX = 0; gWeaponStats[37].sY = 0; gWeaponStats[37].sValDx = 0; - gWeaponStats[38].sX = 0; gWeaponStats[38].sY = 0; gWeaponStats[38].sValDx = 0; - gWeaponStats[39].sX = 0; gWeaponStats[39].sY = 0; gWeaponStats[39].sValDx = 0; - gWeaponStats[40].sX = 0; gWeaponStats[40].sY = 0; gWeaponStats[40].sValDx = 0; - gWeaponStats[41].sX = 0; gWeaponStats[41].sY = 0; gWeaponStats[41].sValDx = 0; - gWeaponStats[42].sX = 0; gWeaponStats[42].sY = 0; gWeaponStats[42].sValDx = 0; - gWeaponStats[43].sX = 0; gWeaponStats[43].sY = 0; gWeaponStats[43].sValDx = 0; - gWeaponStats[44].sX = 0; gWeaponStats[44].sY = 0; gWeaponStats[44].sValDx = 0; - gWeaponStats[45].sX = 0; gWeaponStats[45].sY = 0; gWeaponStats[45].sValDx = 0; - gWeaponStats[46].sX = 0; gWeaponStats[46].sY = 0; gWeaponStats[46].sValDx = 0; - - gMoneyStats[0].sX = 51; gMoneyStats[0].sY = 97; gMoneyStats[0].sValDx = 45; - gMoneyStats[1].sX = 61; gMoneyStats[1].sY = 107; gMoneyStats[1].sValDx = 75; - gMoneyStats[2].sX = 51; gMoneyStats[2].sY = 125; gMoneyStats[2].sValDx = 45; - gMoneyStats[3].sX = 61; gMoneyStats[3].sY = 135; gMoneyStats[3].sValDx = 70; - gMoneyStats[4].sX = 0; gMoneyStats[4].sY = 0; gMoneyStats[4].sValDx = 0; - gMoneyStats[5].sX = 0; gMoneyStats[5].sY = 0; gMoneyStats[5].sValDx = 0; - - gItemDescProsConsRects[0].iLeft = 14; gItemDescProsConsRects[0].iTop = 231; gItemDescProsConsRects[0].iRight = 240; gItemDescProsConsRects[0].iBottom = 238; - gItemDescProsConsRects[1].iLeft = 14; gItemDescProsConsRects[1].iTop = 239; gItemDescProsConsRects[1].iRight = 240; gItemDescProsConsRects[1].iBottom = 246; - } + //Not a valid item for NAS, use default else { - gWeaponStats[0].sX = 202; gWeaponStats[0].sY = 15; gWeaponStats[0].sValDx = 83; // 0) STATUS - gWeaponStats[1].sX = 202; gWeaponStats[1].sY = 25; gWeaponStats[1].sValDx = 83; // 1) WEIGHT - gWeaponStats[2].sX = 265; gWeaponStats[2].sY = 40; gWeaponStats[2].sValDx = 20; // 2) RANGE - gWeaponStats[3].sX = 202; gWeaponStats[3].sY = 40; gWeaponStats[3].sValDx = 32; // 3) DAMAGE - gWeaponStats[4].sX = 202; gWeaponStats[4].sY = 15; gWeaponStats[4].sValDx = 83; // 4) KEY - gWeaponStats[5].sX = 202; gWeaponStats[5].sY = 50; gWeaponStats[5].sValDx = 32; // 5) AP - gWeaponStats[6].sX = 265; gWeaponStats[6].sY = 50; gWeaponStats[6].sValDx = 20; - gWeaponStats[7].sX = 234; gWeaponStats[7].sY = 50; gWeaponStats[7].sValDx = 0; // 7) = - gWeaponStats[8].sX = 290; gWeaponStats[8].sY = 50; gWeaponStats[8].sValDx = 0; // 8) = - gWeaponStats[9].sX = 0; gWeaponStats[9].sY = 0; gWeaponStats[9].sValDx = 0; - gWeaponStats[10].sX = 0; gWeaponStats[10].sY = 0; gWeaponStats[10].sValDx = 0; - gWeaponStats[11].sX = 0; gWeaponStats[11].sY = 0; gWeaponStats[11].sValDx = 0; - gWeaponStats[12].sX = 0; gWeaponStats[12].sY = 0; gWeaponStats[12].sValDx = 0; - gWeaponStats[13].sX = 0; gWeaponStats[13].sY = 0; gWeaponStats[13].sValDx = 0; - gWeaponStats[14].sX = 0; gWeaponStats[14].sY = 0; gWeaponStats[14].sValDx = 0; - gWeaponStats[15].sX = 0; gWeaponStats[15].sY = 0; gWeaponStats[15].sValDx = 0; - gWeaponStats[16].sX = 0; gWeaponStats[16].sY = 0; gWeaponStats[16].sValDx = 0; - gWeaponStats[17].sX = 0; gWeaponStats[17].sY = 0; gWeaponStats[17].sValDx = 0; - gWeaponStats[18].sX = 0; gWeaponStats[18].sY = 0; gWeaponStats[18].sValDx = 0; - gWeaponStats[19].sX = 0; gWeaponStats[19].sY = 0; gWeaponStats[19].sValDx = 0; - gWeaponStats[20].sX = 0; gWeaponStats[20].sY = 0; gWeaponStats[20].sValDx = 0; - gWeaponStats[21].sX = 0; gWeaponStats[21].sY = 0; gWeaponStats[21].sValDx = 0; - gWeaponStats[22].sX = 0; gWeaponStats[22].sY = 0; gWeaponStats[22].sValDx = 0; - gWeaponStats[23].sX = 0; gWeaponStats[23].sY = 0; gWeaponStats[23].sValDx = 0; - gWeaponStats[24].sX = 0; gWeaponStats[24].sY = 0; gWeaponStats[24].sValDx = 0; - gWeaponStats[25].sX = 0; gWeaponStats[25].sY = 0; gWeaponStats[25].sValDx = 0; - gWeaponStats[26].sX = 0; gWeaponStats[26].sY = 0; gWeaponStats[26].sValDx = 0; - gWeaponStats[27].sX = 0; gWeaponStats[27].sY = 0; gWeaponStats[27].sValDx = 0; - gWeaponStats[28].sX = 0; gWeaponStats[28].sY = 0; gWeaponStats[28].sValDx = 0; - gWeaponStats[29].sX = 0; gWeaponStats[29].sY = 0; gWeaponStats[29].sValDx = 0; - gWeaponStats[30].sX = 0; gWeaponStats[30].sY = 0; gWeaponStats[30].sValDx = 0; - gWeaponStats[31].sX = 0; gWeaponStats[31].sY = 0; gWeaponStats[31].sValDx = 0; - gWeaponStats[32].sX = 0; gWeaponStats[32].sY = 0; gWeaponStats[32].sValDx = 0; - gWeaponStats[33].sX = 0; gWeaponStats[33].sY = 0; gWeaponStats[33].sValDx = 0; - gWeaponStats[34].sX = 0; gWeaponStats[34].sY = 0; gWeaponStats[34].sValDx = 0; - gWeaponStats[35].sX = 0; gWeaponStats[35].sY = 0; gWeaponStats[35].sValDx = 0; - gWeaponStats[36].sX = 0; gWeaponStats[36].sY = 0; gWeaponStats[36].sValDx = 0; - gWeaponStats[37].sX = 0; gWeaponStats[37].sY = 0; gWeaponStats[37].sValDx = 0; - gWeaponStats[38].sX = 0; gWeaponStats[38].sY = 0; gWeaponStats[38].sValDx = 0; - gWeaponStats[39].sX = 0; gWeaponStats[39].sY = 0; gWeaponStats[39].sValDx = 0; - gWeaponStats[40].sX = 0; gWeaponStats[40].sY = 0; gWeaponStats[40].sValDx = 0; - gWeaponStats[41].sX = 0; gWeaponStats[41].sY = 0; gWeaponStats[41].sValDx = 0; - gWeaponStats[42].sX = 0; gWeaponStats[42].sY = 0; gWeaponStats[42].sValDx = 0; - gWeaponStats[43].sX = 0; gWeaponStats[43].sY = 0; gWeaponStats[43].sValDx = 0; - gWeaponStats[44].sX = 0; gWeaponStats[44].sY = 0; gWeaponStats[44].sValDx = 0; - gWeaponStats[45].sX = 0; gWeaponStats[45].sY = 0; gWeaponStats[45].sValDx = 0; - gWeaponStats[46].sX = 0; gWeaponStats[46].sY = 0; gWeaponStats[46].sValDx = 0; - - gMoneyStats[0].sX = 202; gMoneyStats[0].sY = 14; gMoneyStats[0].sValDx = 78; - gMoneyStats[1].sX = 212; gMoneyStats[1].sY = 25; gMoneyStats[1].sValDx = 78; - gMoneyStats[2].sX = 203; gMoneyStats[2].sY = 40; gMoneyStats[2].sValDx = 78; - gMoneyStats[3].sX = 212; gMoneyStats[3].sY = 51; gMoneyStats[3].sValDx = 78; - gMoneyStats[4].sX = 0; gMoneyStats[4].sY = 0; gMoneyStats[4].sValDx = 0; - gMoneyStats[5].sX = 0; gMoneyStats[5].sY = 0; gMoneyStats[5].sValDx = 0; - - gItemDescProsConsRects[0].iLeft = 7; gItemDescProsConsRects[0].iTop = 111; gItemDescProsConsRects[0].iRight = 313; gItemDescProsConsRects[0].iBottom = 118; - gItemDescProsConsRects[1].iLeft = 7; gItemDescProsConsRects[1].iTop = 119; gItemDescProsConsRects[1].iRight = 313; gItemDescProsConsRects[1].iBottom = 126; + //default setup + SetupItemDescAttachmentsXY(0, 133, 11, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); + SetupItemDescAttachmentsXY(1, 167, 11, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); + SetupItemDescAttachmentsXY(2, 133, 38, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); + SetupItemDescAttachmentsXY(3, 167, 38, SM_INV_SLOT_HEIGHT, ATTACH_SLOT_WIDTH, INV_BAR_DX-8, INV_BAR_DY+1); } } } @@ -1196,11 +870,11 @@ void InitLBECoords() { if(UsingEDBSystem() > 0) { - gLBEStats[0].sX = 456; gLBEStats[0].sY = 10; gLBEStats[0].sValDx = 0; //Thigh 1 - gLBEStats[1].sX = 492; gLBEStats[1].sY = 10; gLBEStats[1].sValDx = 0; //Thigh 2 - gLBEStats[2].sX = 456; gLBEStats[2].sY = 34; gLBEStats[2].sValDx = 0; //Thigh 3 - gLBEStats[3].sX = 492; gLBEStats[3].sY = 34; gLBEStats[3].sValDx = 0; //Thigh 4 - gLBEStats[4].sX = 467; gLBEStats[4].sY = 58; gLBEStats[4].sValDx = 0; //Thigh 5 + gLBEStats[0].sX = 597; gLBEStats[0].sY = 9; gLBEStats[0].sValDx = 0; //Thigh 1 + gLBEStats[1].sX = 633; gLBEStats[1].sY = 9; gLBEStats[1].sValDx = 0; //Thigh 2 + gLBEStats[2].sX = 597; gLBEStats[2].sY = 33; gLBEStats[2].sValDx = 0; //Thigh 3 + gLBEStats[3].sX = 633; gLBEStats[3].sY = 33; gLBEStats[3].sValDx = 0; //Thigh 4 + gLBEStats[4].sX = 608; gLBEStats[4].sY = 57; gLBEStats[4].sValDx = 0; //Thigh 5 gLBEStats[5].sX = 0; gLBEStats[5].sY = 0; gLBEStats[5].sValDx = 0; //Thigh 6 gLBEStats[6].sX = 0; gLBEStats[6].sY = 0; gLBEStats[6].sValDx = 0; //Thigh 7 gLBEStats[7].sX = 0; gLBEStats[7].sY = 0; gLBEStats[7].sValDx = 0; //Thigh 8 @@ -1208,50 +882,50 @@ void InitLBECoords() gLBEStats[9].sX = 0; gLBEStats[9].sY = 0; gLBEStats[9].sValDx = 0; //Thigh 10 gLBEStats[10].sX = 0; gLBEStats[10].sY = 0; gLBEStats[10].sValDx = 0; //Thigh 11 gLBEStats[11].sX = 0; gLBEStats[11].sY = 0; gLBEStats[11].sValDx = 0; //Thigh 12 - gLBEStats[12].sX = 456; gLBEStats[12].sY = 10; gLBEStats[12].sValDx = 0; //Vest 1 - gLBEStats[13].sX = 492; gLBEStats[13].sY = 10; gLBEStats[13].sValDx = 0; //Vest 2 - gLBEStats[14].sX = 528; gLBEStats[14].sY = 10; gLBEStats[14].sValDx = 0; //Vest 3 - gLBEStats[15].sX = 564; gLBEStats[15].sY = 10; gLBEStats[15].sValDx = 0; //Vest 4 - gLBEStats[16].sX = 600; gLBEStats[16].sY = 10; gLBEStats[16].sValDx = 0; //Vest 5 - gLBEStats[17].sX = 456; gLBEStats[17].sY = 34; gLBEStats[17].sValDx = 0; //Vest 6 - gLBEStats[18].sX = 492; gLBEStats[18].sY = 34; gLBEStats[18].sValDx = 0; //Vest 7 - gLBEStats[19].sX = 528; gLBEStats[19].sY = 34; gLBEStats[19].sValDx = 0; //Vest 8 - gLBEStats[20].sX = 564; gLBEStats[20].sY = 34; gLBEStats[20].sValDx = 0; //Vest 9 - gLBEStats[21].sX = 600; gLBEStats[21].sY = 34; gLBEStats[21].sValDx = 0; //Vest 10 - gLBEStats[22].sX = 636; gLBEStats[22].sY = 10; gLBEStats[22].sValDx = 0; //Vest 11 - gLBEStats[23].sX = 636; gLBEStats[23].sY = 34; gLBEStats[23].sValDx = 0; //Vest 12 - gLBEStats[24].sX = 456; gLBEStats[24].sY = 10; gLBEStats[24].sValDx = 0; //CPack 1 - gLBEStats[25].sX = 492; gLBEStats[25].sY = 10; gLBEStats[25].sValDx = 0; //CPack 2 - gLBEStats[26].sX = 456; gLBEStats[26].sY = 34; gLBEStats[26].sValDx = 0; //CPack 3 - gLBEStats[27].sX = 492; gLBEStats[27].sY = 34; gLBEStats[27].sValDx = 0; //CPack 4 - gLBEStats[28].sX = 528; gLBEStats[28].sY = 10; gLBEStats[28].sValDx = 0; //CPack 5 - gLBEStats[29].sX = 528; gLBEStats[29].sY = 34; gLBEStats[29].sValDx = 0; //CPack 6 - gLBEStats[30].sX = 528; gLBEStats[30].sY = 58; gLBEStats[30].sValDx = 0; //CPack 7 + gLBEStats[12].sX = 597; gLBEStats[12].sY = 9; gLBEStats[12].sValDx = 0; //Vest 1 + gLBEStats[13].sX = 633; gLBEStats[13].sY = 9; gLBEStats[13].sValDx = 0; //Vest 2 + gLBEStats[14].sX = 669; gLBEStats[14].sY = 9; gLBEStats[14].sValDx = 0; //Vest 3 + gLBEStats[15].sX = 705; gLBEStats[15].sY = 9; gLBEStats[15].sValDx = 0; //Vest 4 + gLBEStats[16].sX = 741; gLBEStats[16].sY = 9; gLBEStats[16].sValDx = 0; //Vest 5 + gLBEStats[17].sX = 597; gLBEStats[17].sY = 33; gLBEStats[17].sValDx = 0; //Vest 6 + gLBEStats[18].sX = 633; gLBEStats[18].sY = 33; gLBEStats[18].sValDx = 0; //Vest 7 + gLBEStats[19].sX = 669; gLBEStats[19].sY = 33; gLBEStats[19].sValDx = 0; //Vest 8 + gLBEStats[20].sX = 705; gLBEStats[20].sY = 33; gLBEStats[20].sValDx = 0; //Vest 9 + gLBEStats[21].sX = 741; gLBEStats[21].sY = 33; gLBEStats[21].sValDx = 0; //Vest 10 + gLBEStats[22].sX = 663; gLBEStats[22].sY = 57; gLBEStats[22].sValDx = 0; //Vest 11 + gLBEStats[23].sX = 663; gLBEStats[23].sY = 81; gLBEStats[23].sValDx = 0; //Vest 12 + gLBEStats[24].sX = 597; gLBEStats[24].sY = 10; gLBEStats[24].sValDx = 0; //CPack 1 + gLBEStats[25].sX = 633; gLBEStats[25].sY = 10; gLBEStats[25].sValDx = 0; //CPack 2 + gLBEStats[26].sX = 597; gLBEStats[26].sY = 34; gLBEStats[26].sValDx = 0; //CPack 3 + gLBEStats[27].sX = 633; gLBEStats[27].sY = 34; gLBEStats[27].sValDx = 0; //CPack 4 + gLBEStats[28].sX = 669; gLBEStats[28].sY = 10; gLBEStats[28].sValDx = 0; //CPack 5 + gLBEStats[29].sX = 669; gLBEStats[29].sY = 34; gLBEStats[29].sValDx = 0; //CPack 6 + gLBEStats[30].sX = 669; gLBEStats[30].sY = 58; gLBEStats[30].sValDx = 0; //CPack 7 gLBEStats[31].sX = 0; gLBEStats[31].sY = 0; gLBEStats[31].sValDx = 0; //CPack 8 gLBEStats[32].sX = 0; gLBEStats[32].sY = 0; gLBEStats[32].sValDx = 0; //CPack 9 gLBEStats[33].sX = 0; gLBEStats[33].sY = 0; gLBEStats[33].sValDx = 0; //CPack 10 gLBEStats[34].sX = 0; gLBEStats[34].sY = 0; gLBEStats[34].sValDx = 0; //CPack 11 gLBEStats[35].sX = 0; gLBEStats[35].sY = 0; gLBEStats[35].sValDx = 0; //CPack 12 - gLBEStats[36].sX = 456; gLBEStats[36].sY = 10; gLBEStats[36].sValDx = 0; //BPack 1 - gLBEStats[37].sX = 456; gLBEStats[37].sY = 34; gLBEStats[37].sValDx = 0; //BPack 2 - gLBEStats[38].sX = 456; gLBEStats[38].sY = 58; gLBEStats[38].sValDx = 0; //BPack 3 - gLBEStats[39].sX = 456; gLBEStats[39].sY = 82; gLBEStats[39].sValDx = 0; //BPack 4 - gLBEStats[40].sX = 492; gLBEStats[40].sY = 10; gLBEStats[40].sValDx = 0; //BPack 5 - gLBEStats[41].sX = 492; gLBEStats[41].sY = 34; gLBEStats[41].sValDx = 0; //BPack 6 - gLBEStats[42].sX = 492; gLBEStats[42].sY = 58; gLBEStats[42].sValDx = 0; //BPack 7 - gLBEStats[43].sX = 492; gLBEStats[43].sY = 82; gLBEStats[43].sValDx = 0; //BPack 8 - gLBEStats[44].sX = 528; gLBEStats[44].sY = 10; gLBEStats[44].sValDx = 0; //BPack 9 - gLBEStats[45].sX = 528; gLBEStats[45].sY = 34; gLBEStats[45].sValDx = 0; //BPack 10 - gLBEStats[46].sX = 528; gLBEStats[46].sY = 58; gLBEStats[46].sValDx = 0; //BPack 11 - gLBEStats[47].sX = 528; gLBEStats[47].sY = 82; gLBEStats[47].sValDx = 0; //BPack 12 + gLBEStats[36].sX = 597; gLBEStats[36].sY = 9; gLBEStats[36].sValDx = 0; //BPack 1 + gLBEStats[37].sX = 597; gLBEStats[37].sY = 33; gLBEStats[37].sValDx = 0; //BPack 2 + gLBEStats[38].sX = 597; gLBEStats[38].sY = 57; gLBEStats[38].sValDx = 0; //BPack 3 + gLBEStats[39].sX = 597; gLBEStats[39].sY = 81; gLBEStats[39].sValDx = 0; //BPack 4 + gLBEStats[40].sX = 633; gLBEStats[40].sY = 9; gLBEStats[40].sValDx = 0; //BPack 5 + gLBEStats[41].sX = 633; gLBEStats[41].sY = 33; gLBEStats[41].sValDx = 0; //BPack 6 + gLBEStats[42].sX = 633; gLBEStats[42].sY = 57; gLBEStats[42].sValDx = 0; //BPack 7 + gLBEStats[43].sX = 633; gLBEStats[43].sY = 81; gLBEStats[43].sValDx = 0; //BPack 8 + gLBEStats[44].sX = 669; gLBEStats[44].sY = 9; gLBEStats[44].sValDx = 0; //BPack 9 + gLBEStats[45].sX = 669; gLBEStats[45].sY = 33; gLBEStats[45].sValDx = 0; //BPack 10 + gLBEStats[46].sX = 669; gLBEStats[46].sY = 57; gLBEStats[46].sValDx = 0; //BPack 11 + gLBEStats[47].sX = 669; gLBEStats[47].sY = 81; gLBEStats[47].sValDx = 0; //BPack 12 } else { - gLBEStats[0].sX = 586; gLBEStats[0].sY = 10; gLBEStats[0].sValDx = 0; //Thigh 1 - gLBEStats[1].sX = 622; gLBEStats[1].sY = 10; gLBEStats[1].sValDx = 0; //Thigh 2 - gLBEStats[2].sX = 586; gLBEStats[2].sY = 34; gLBEStats[2].sValDx = 0; //Thigh 3 - gLBEStats[3].sX = 622; gLBEStats[3].sY = 34; gLBEStats[3].sValDx = 0; //Thigh 4 - gLBEStats[4].sX = 597; gLBEStats[4].sY = 58; gLBEStats[4].sValDx = 0; //Thigh 5 + gLBEStats[0].sX = 442; gLBEStats[0].sY = 10; gLBEStats[0].sValDx = 0; //Thigh 1 + gLBEStats[1].sX = 478; gLBEStats[1].sY = 10; gLBEStats[1].sValDx = 0; //Thigh 2 + gLBEStats[2].sX = 442; gLBEStats[2].sY = 34; gLBEStats[2].sValDx = 0; //Thigh 3 + gLBEStats[3].sX = 478; gLBEStats[3].sY = 34; gLBEStats[3].sValDx = 0; //Thigh 4 + gLBEStats[4].sX = 453; gLBEStats[4].sY = 58; gLBEStats[4].sValDx = 0; //Thigh 5 gLBEStats[5].sX = 0; gLBEStats[5].sY = 0; gLBEStats[5].sValDx = 0; //Thigh 6 gLBEStats[6].sX = 0; gLBEStats[6].sY = 0; gLBEStats[6].sValDx = 0; //Thigh 7 gLBEStats[7].sX = 0; gLBEStats[7].sY = 0; gLBEStats[7].sValDx = 0; //Thigh 8 @@ -1259,635 +933,267 @@ void InitLBECoords() gLBEStats[9].sX = 0; gLBEStats[9].sY = 0; gLBEStats[9].sValDx = 0; //Thigh 10 gLBEStats[10].sX = 0; gLBEStats[10].sY = 0; gLBEStats[10].sValDx = 0; //Thigh 11 gLBEStats[11].sX = 0; gLBEStats[11].sY = 0; gLBEStats[11].sValDx = 0; //Thigh 12 - gLBEStats[12].sX = 269; gLBEStats[12].sY = 139; gLBEStats[12].sValDx = 0; //Vest 1 - gLBEStats[13].sX = 305; gLBEStats[13].sY = 139; gLBEStats[13].sValDx = 0; //Vest 2 - gLBEStats[14].sX = 341; gLBEStats[14].sY = 139; gLBEStats[14].sValDx = 0; //Vest 3 - gLBEStats[15].sX = 377; gLBEStats[15].sY = 139; gLBEStats[15].sValDx = 0; //Vest 4 - gLBEStats[16].sX = 413; gLBEStats[16].sY = 139; gLBEStats[16].sValDx = 0; //Vest 5 - gLBEStats[17].sX = 269; gLBEStats[17].sY = 163; gLBEStats[17].sValDx = 0; //Vest 6 - gLBEStats[18].sX = 305; gLBEStats[18].sY = 163; gLBEStats[18].sValDx = 0; //Vest 7 - gLBEStats[19].sX = 341; gLBEStats[19].sY = 163; gLBEStats[19].sValDx = 0; //Vest 8 - gLBEStats[20].sX = 377; gLBEStats[20].sY = 163; gLBEStats[20].sValDx = 0; //Vest 9 - gLBEStats[21].sX = 413; gLBEStats[21].sY = 163; gLBEStats[21].sValDx = 0; //Vest 10 - gLBEStats[22].sX = 449; gLBEStats[22].sY = 139; gLBEStats[22].sValDx = 0; //Vest 11 - gLBEStats[23].sX = 449; gLBEStats[23].sY = 163; gLBEStats[23].sValDx = 0; //Vest 12 - gLBEStats[24].sX = 585; gLBEStats[24].sY = 10; gLBEStats[24].sValDx = 0; //CPack 1 - gLBEStats[25].sX = 621; gLBEStats[25].sY = 10; gLBEStats[25].sValDx = 0; //CPack 2 - gLBEStats[26].sX = 585; gLBEStats[26].sY = 34; gLBEStats[26].sValDx = 0; //CPack 3 - gLBEStats[27].sX = 621; gLBEStats[27].sY = 34; gLBEStats[27].sValDx = 0; //CPack 4 - gLBEStats[28].sX = 657; gLBEStats[28].sY = 10; gLBEStats[28].sValDx = 0; //CPack 5 - gLBEStats[29].sX = 657; gLBEStats[29].sY = 34; gLBEStats[29].sValDx = 0; //CPack 6 - gLBEStats[30].sX = 657; gLBEStats[30].sY = 58; gLBEStats[30].sValDx = 0; //CPack 7 + gLBEStats[12].sX = 125; gLBEStats[12].sY = 139; gLBEStats[12].sValDx = 0; //Vest 1 + gLBEStats[13].sX = 161; gLBEStats[13].sY = 139; gLBEStats[13].sValDx = 0; //Vest 2 + gLBEStats[14].sX = 197; gLBEStats[14].sY = 139; gLBEStats[14].sValDx = 0; //Vest 3 + gLBEStats[15].sX = 233; gLBEStats[15].sY = 139; gLBEStats[15].sValDx = 0; //Vest 4 + gLBEStats[16].sX = 269; gLBEStats[16].sY = 139; gLBEStats[16].sValDx = 0; //Vest 5 + gLBEStats[17].sX = 125; gLBEStats[17].sY = 163; gLBEStats[17].sValDx = 0; //Vest 6 + gLBEStats[18].sX = 161; gLBEStats[18].sY = 163; gLBEStats[18].sValDx = 0; //Vest 7 + gLBEStats[19].sX = 197; gLBEStats[19].sY = 163; gLBEStats[19].sValDx = 0; //Vest 8 + gLBEStats[20].sX = 233; gLBEStats[20].sY = 163; gLBEStats[20].sValDx = 0; //Vest 9 + gLBEStats[21].sX = 269; gLBEStats[21].sY = 163; gLBEStats[21].sValDx = 0; //Vest 10 + gLBEStats[22].sX = 305; gLBEStats[22].sY = 139; gLBEStats[22].sValDx = 0; //Vest 11 + gLBEStats[23].sX = 305; gLBEStats[23].sY = 163; gLBEStats[23].sValDx = 0; //Vest 12 + gLBEStats[24].sX = 442; gLBEStats[24].sY = 10; gLBEStats[24].sValDx = 0; //CPack 1 + gLBEStats[25].sX = 478; gLBEStats[25].sY = 10; gLBEStats[25].sValDx = 0; //CPack 2 + gLBEStats[26].sX = 442; gLBEStats[26].sY = 34; gLBEStats[26].sValDx = 0; //CPack 3 + gLBEStats[27].sX = 478; gLBEStats[27].sY = 34; gLBEStats[27].sValDx = 0; //CPack 4 + gLBEStats[28].sX = 514; gLBEStats[28].sY = 10; gLBEStats[28].sValDx = 0; //CPack 5 + gLBEStats[29].sX = 514; gLBEStats[29].sY = 34; gLBEStats[29].sValDx = 0; //CPack 6 + gLBEStats[30].sX = 514; gLBEStats[30].sY = 58; gLBEStats[30].sValDx = 0; //CPack 7 gLBEStats[31].sX = 0; gLBEStats[31].sY = 0; gLBEStats[31].sValDx = 0; //CPack 8 gLBEStats[32].sX = 0; gLBEStats[32].sY = 0; gLBEStats[32].sValDx = 0; //CPack 9 gLBEStats[33].sX = 0; gLBEStats[33].sY = 0; gLBEStats[33].sValDx = 0; //CPack 10 gLBEStats[34].sX = 0; gLBEStats[34].sY = 0; gLBEStats[34].sValDx = 0; //CPack 11 gLBEStats[35].sX = 0; gLBEStats[35].sY = 0; gLBEStats[35].sValDx = 0; //CPack 12 - gLBEStats[36].sX = 585; gLBEStats[36].sY = 10; gLBEStats[36].sValDx = 0; //BPack 1 - gLBEStats[37].sX = 585; gLBEStats[37].sY = 34; gLBEStats[37].sValDx = 0; //BPack 2 - gLBEStats[38].sX = 585; gLBEStats[38].sY = 58; gLBEStats[38].sValDx = 0; //BPack 3 - gLBEStats[39].sX = 585; gLBEStats[39].sY = 82; gLBEStats[39].sValDx = 0; //BPack 4 - gLBEStats[40].sX = 621; gLBEStats[40].sY = 10; gLBEStats[40].sValDx = 0; //BPack 5 - gLBEStats[41].sX = 621; gLBEStats[41].sY = 34; gLBEStats[41].sValDx = 0; //BPack 6 - gLBEStats[42].sX = 621; gLBEStats[42].sY = 58; gLBEStats[42].sValDx = 0; //BPack 7 - gLBEStats[43].sX = 621; gLBEStats[43].sY = 82; gLBEStats[43].sValDx = 0; //BPack 8 - gLBEStats[44].sX = 657; gLBEStats[44].sY = 10; gLBEStats[44].sValDx = 0; //BPack 9 - gLBEStats[45].sX = 657; gLBEStats[45].sY = 34; gLBEStats[45].sValDx = 0; //BPack 10 - gLBEStats[46].sX = 657; gLBEStats[46].sY = 58; gLBEStats[46].sValDx = 0; //BPack 11 - gLBEStats[47].sX = 657; gLBEStats[47].sY = 82; gLBEStats[47].sValDx = 0; //BPack 12 + gLBEStats[36].sX = 442; gLBEStats[36].sY = 10; gLBEStats[36].sValDx = 0; //BPack 1 + gLBEStats[37].sX = 442; gLBEStats[37].sY = 34; gLBEStats[37].sValDx = 0; //BPack 2 + gLBEStats[38].sX = 442; gLBEStats[38].sY = 58; gLBEStats[38].sValDx = 0; //BPack 3 + gLBEStats[39].sX = 442; gLBEStats[39].sY = 82; gLBEStats[39].sValDx = 0; //BPack 4 + gLBEStats[40].sX = 478; gLBEStats[40].sY = 10; gLBEStats[40].sValDx = 0; //BPack 5 + gLBEStats[41].sX = 478; gLBEStats[41].sY = 34; gLBEStats[41].sValDx = 0; //BPack 6 + gLBEStats[42].sX = 478; gLBEStats[42].sY = 58; gLBEStats[42].sValDx = 0; //BPack 7 + gLBEStats[43].sX = 478; gLBEStats[43].sY = 82; gLBEStats[43].sValDx = 0; //BPack 8 + gLBEStats[44].sX = 514; gLBEStats[44].sY = 10; gLBEStats[44].sValDx = 0; //BPack 9 + gLBEStats[45].sX = 514; gLBEStats[45].sY = 34; gLBEStats[45].sValDx = 0; //BPack 10 + gLBEStats[46].sX = 514; gLBEStats[46].sY = 58; gLBEStats[46].sValDx = 0; //BPack 11 + gLBEStats[47].sX = 514; gLBEStats[47].sY = 82; gLBEStats[47].sValDx = 0; //BPack 12 } } } -void InitItemDescriptionBoxOffsets() +void InitItemDescriptionBoxOffsets(OBJECTTYPE * pObject) { - // Initiate variables for Enhanced Item Description Box system - if(guiCurrentScreen ==MAP_SCREEN) //Strategic - { - if(UsingEDBSystem() > 0) + if(UsingNewAttachmentSystem()==true){ + INT16 sY = gsInvDescY + sNASYCorrection(pObject); + INT16 sX = gsInvDescX + sNASXCorrection(pObject); + + // Initiate variables for Enhanced Item Description Box system + if(guiCurrentScreen ==MAP_SCREEN) //Strategic { - // STRATEGIC Description Box Icons - BULLET_DRAW_X = (112 + gsInvDescX); - BULLET_DRAW_Y = (136 + gsInvDescY); - BULLET_SING_X = (112 + gsInvDescX); - BULLET_SING_Y = (148 + gsInvDescY); - BULLET_BURST_X = (112 + gsInvDescX); - BULLET_BURST_Y = (160 + gsInvDescY); - BULLET_AUTO_X = (112 + gsInvDescX); - BULLET_AUTO_Y = (172 + gsInvDescY); - BULLET_RELOAD_X = (112 + gsInvDescX); - BULLET_RELOAD_Y = (184 + gsInvDescY); - BULLET_MRELOAD_X = (112 + gsInvDescX); - BULLET_MRELOAD_Y = (196 + gsInvDescY); - BULLET_RANGE_X = (47 + gsInvDescX); - BULLET_RANGE_Y = (124 + gsInvDescY); - BULLET_DAMAGE_X = (47 + gsInvDescX); - BULLET_DAMAGE_Y = (136 + gsInvDescY); - BULLET_AUTOPEN_X = (47 + gsInvDescX); - BULLET_AUTOPEN_Y = (148 + gsInvDescY); - BULLET_AUTO5AP_X = (47 + gsInvDescX); - BULLET_AUTO5AP_Y = (160 + gsInvDescY); - BULLET_ACC_X = (47 + gsInvDescX); - BULLET_ACC_Y = (172 + gsInvDescY); - BULLET_RELIABILITY_X = (47 + gsInvDescX); - BULLET_RELIABILITY_Y = (184 + gsInvDescY); - BULLET_REPAIR_X = (47 + gsInvDescX); - BULLET_REPAIR_Y = (196 + gsInvDescY); - BULLET_LOUDNESS_X = (174 + gsInvDescX); - BULLET_LOUDNESS_Y = (136 + gsInvDescY); - BULLET_FLASH_X = (198 + gsInvDescX); - BULLET_FLASH_Y = (124 + gsInvDescY); - BULLET_TOHIT_X = (174 + gsInvDescX); - BULLET_TOHIT_Y = (148 + gsInvDescY); - BULLET_BESTLASERRANGE_X = (174 + gsInvDescX); - BULLET_BESTLASERRANGE_Y = (160 + gsInvDescY); - BULLET_AIMBONUS_X = (174 + gsInvDescX); - BULLET_AIMBONUS_Y = (172 + gsInvDescY); - BULLET_MINRANGEAIMBONUS_X = (174 + gsInvDescX); - BULLET_MINRANGEAIMBONUS_Y = (184 + gsInvDescY); - BULLET_BIPOD_X = (174 + gsInvDescX); - BULLET_BIPOD_Y = (196 + gsInvDescY); + if(UsingEDBSystem() > 0) + { + //WarmSteel - LBE and money do not get a NAS discription box. + if(!UseNASDesc(pObject)){ + ITEMDESC_CALIBER_X = (105 + sX); + ITEMDESC_CALIBER_Y = ( 66 + sY); + ITEMDESC_CALIBER_WIDTH = 149; + ITEMDESC_NAME_X = ( 7 + sX); + ITEMDESC_NAME_Y = ( 65 + sY); + ITEMDESC_ITEM_X = ( 25 + sX); + ITEMDESC_ITEM_Y = ( 6 + sY); + ITEMDESC_ITEM_STATUS_X = ( 18 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 53 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = (28 + sX); + ITEMDESC_AMMO_Y = (44 + sY); + ITEMDESC_DONE_X = (199 + sX); + ITEMDESC_DONE_Y = (334 + sY); - // Icon Locations for AMMO stats - BULLET_ARMORPEN_X = (47 + gsInvDescX); - BULLET_ARMORPEN_Y = (124 + gsInvDescY); - BULLET_TUMBLE_X = (47 + gsInvDescX); - BULLET_TUMBLE_Y = (136 + gsInvDescY); - BULLET_PREARMOR_X = (47 + gsInvDescX); - BULLET_PREARMOR_Y = (148 + gsInvDescY); - BULLET_TRACER_X = (115 + gsInvDescX); - BULLET_TRACER_Y = (124 + gsInvDescY); - BULLET_ANTITANK_X = (140 + gsInvDescX); - BULLET_ANTITANK_Y = (124 + gsInvDescY); - BULLET_LOCKBUSTER_X = (115 + gsInvDescX); - BULLET_LOCKBUSTER_Y = (148 + gsInvDescY); - BULLET_IGNOREARMOR_X = (140 + gsInvDescX); - BULLET_IGNOREARMOR_Y = (148 + gsInvDescY); - BULLET_ACIDIC_X = (115 + gsInvDescX); - BULLET_ACIDIC_Y = (172 + gsInvDescY); - BULLET_AMMORANGEBON_X = (174 + gsInvDescX); - BULLET_AMMORANGEBON_Y = (124 + gsInvDescY); - BULLET_AMMODAMAGEBON_X = (174 + gsInvDescX); - BULLET_AMMODAMAGEBON_Y = (136 + gsInvDescY); - BULLET_AMMOTOHITBON_X = (174 + gsInvDescX); - BULLET_AMMOTOHITBON_Y = (148 + gsInvDescY); - BULLET_AMMOAUTOBON_X = (174 + gsInvDescX); - BULLET_AMMOAUTOBON_Y = (160 + gsInvDescY); - BULLET_AMMOBURSTBON_X = (174 + gsInvDescX); - BULLET_AMMOBURSTBON_Y = (172 + gsInvDescY); - BULLET_AMMORELIABILITYBON_X = (174 + gsInvDescX); - BULLET_AMMORELIABILITYBON_Y = (184 + gsInvDescY); - BULLET_AMMONOISESUPP_X = (174 + gsInvDescX); - BULLET_AMMONOISESUPP_Y = (196 + gsInvDescY); + } else { - // Icon Locations for EXPLOSIVES stats - BULLET_EXPLOSIVEDAMAGE_X = (47 + gsInvDescX); - BULLET_EXPLOSIVEDAMAGE_Y = (124 + gsInvDescY); - BULLET_EXPLOSIVESTUNDAMAGE_X = (47 + gsInvDescX); - BULLET_EXPLOSIVESTUNDAMAGE_Y = (136 + gsInvDescY); - BULLET_EXPLOSIVELOUDNESS_X = (47 + gsInvDescX); - BULLET_EXPLOSIVELOUDNESS_Y = (148 + gsInvDescY); - BULLET_EXPLOSIVEVOLATILITY_X = (47 + gsInvDescX); - BULLET_EXPLOSIVEVOLATILITY_Y = (160 + gsInvDescY); - BULLET_EXPLOSIVERADIUS_X = (131 + gsInvDescX); - BULLET_EXPLOSIVERADIUS_Y = (124 + gsInvDescY); - BULLET_EXPLOSIVESTARTRADIUS_X = (113 + gsInvDescX); - BULLET_EXPLOSIVESTARTRADIUS_Y = (124 + gsInvDescY); - BULLET_EXPLOSIVEARROW_X = (131 + gsInvDescX); - BULLET_EXPLOSIVEARROW_Y = (130 + gsInvDescY); - BULLET_EXPLOSIVEENDRADIUS_X = (146 + gsInvDescX); - BULLET_EXPLOSIVEENDRADIUS_Y = (124 + gsInvDescY); - BULLET_EXPLOSIVEDURATION_X = (112 + gsInvDescX); - BULLET_EXPLOSIVEDURATION_Y = (172 + gsInvDescY); - - // Icon Locations for ARMOR stats - BULLET_ARMOR_X = (47 + gsInvDescX); - BULLET_ARMOR_Y = (124 + gsInvDescY); - BULLET_ARMORCOVERAGE_X = (47 + gsInvDescX); - BULLET_ARMORCOVERAGE_Y = (136 + gsInvDescY); - BULLET_ARMORDEGRADE_X = (47 + gsInvDescX); - BULLET_ARMORDEGRADE_Y = (148 + gsInvDescY); - BULLET_ARMORAPBONUS_X = (112 + gsInvDescX); - BULLET_ARMORAPBONUS_Y = (124 + gsInvDescY); - BULLET_ARMORAIMBONUS_X = (112 + gsInvDescX); - BULLET_ARMORAIMBONUS_Y = (136 + gsInvDescY); - BULLET_ARMORWOODCAMO_X = (112 + gsInvDescX); - BULLET_ARMORWOODCAMO_Y = (148 + gsInvDescY); - BULLET_ARMORURBANCAMO_X = (112 + gsInvDescX); - BULLET_ARMORURBANCAMO_Y = (160 + gsInvDescY); - BULLET_ARMORDESERTCAMO_X = (112 + gsInvDescX); - BULLET_ARMORDESERTCAMO_Y = (172 + gsInvDescY); - BULLET_ARMORSNOWCAMO_X = (112 + gsInvDescX); - BULLET_ARMORSNOWCAMO_Y = (184 + gsInvDescY); - BULLET_ARMORSTEALTH_X = (112 + gsInvDescX); - BULLET_ARMORSTEALTH_Y = (196 + gsInvDescY); - BULLET_ARMORVISIONRANGEBONUS_X = (174 + gsInvDescX); - BULLET_ARMORVISIONRANGEBONUS_Y = (124 + gsInvDescY); - BULLET_ARMORDAYVISIONRANGEBONUS_X = (175 + gsInvDescX); - BULLET_ARMORDAYVISIONRANGEBONUS_Y = (136 + gsInvDescY); - BULLET_ARMORNIGHTVISIONRANGEBONUS_X = (175 + gsInvDescX); - BULLET_ARMORNIGHTVISIONRANGEBONUS_Y = (148 + gsInvDescY); - BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_X = (175 + gsInvDescX); - BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_Y = (160 + gsInvDescY); - BULLET_ARMORCAVEVISIONRANGEBONUS_X = (175 + gsInvDescX); - BULLET_ARMORCAVEVISIONRANGEBONUS_Y = (172 + gsInvDescY); - BULLET_ARMORPERCENTTUNNELVISION_X = (175 + gsInvDescX); - BULLET_ARMORPERCENTTUNNELVISION_Y = (184 + gsInvDescY); - BULLET_ARMORHEARINGRANGEBONUS_X = (174 + gsInvDescX); - BULLET_ARMORHEARINGRANGEBONUS_Y = (196 + gsInvDescY); - - // Generic Icon Locations for MISC Item Stats - BULLET_COL1ROW1_X = (47 + gsInvDescX); - BULLET_COL1ROW1_Y = (124 + gsInvDescY); - BULLET_COL1ROW2_X = (47 + gsInvDescX); - BULLET_COL1ROW2_Y = (136 + gsInvDescY); - BULLET_COL1ROW3_X = (47 + gsInvDescX); - BULLET_COL1ROW3_Y = (148 + gsInvDescY); - BULLET_COL1ROW4_X = (47 + gsInvDescX); - BULLET_COL1ROW4_Y = (160 + gsInvDescY); - BULLET_COL1ROW5_X = (47 + gsInvDescX); - BULLET_COL1ROW5_Y = (172 + gsInvDescY); - BULLET_COL1ROW6_X = (47 + gsInvDescX); - BULLET_COL1ROW6_Y = (184 + gsInvDescY); - BULLET_COL1ROW7_X = (47 + gsInvDescX); - BULLET_COL1ROW7_Y = (196 + gsInvDescY); - BULLET_COL2ROW1_X = (144 + gsInvDescX); - BULLET_COL2ROW1_Y = (124 + gsInvDescY); - BULLET_COL2ROW2_X = (144 + gsInvDescX); - BULLET_COL2ROW2_Y = (136 + gsInvDescY); - BULLET_COL2ROW3_X = (144 + gsInvDescX); - BULLET_COL2ROW3_Y = (148 + gsInvDescY); - BULLET_COL2ROW4_X = (144 + gsInvDescX); - BULLET_COL2ROW4_Y = (160 + gsInvDescY); - BULLET_COL2ROW5_X = (144 + gsInvDescX); - BULLET_COL2ROW5_Y = (172 + gsInvDescY); - BULLET_COL2ROW6_X = (144 + gsInvDescX); - BULLET_COL2ROW6_Y = (184 + gsInvDescY); - BULLET_COL2ROW7_X = (144 + gsInvDescX); - BULLET_COL2ROW7_Y = (196 + gsInvDescY); - - ITEMDESC_CALIBER_X = (105 + gsInvDescX); - ITEMDESC_CALIBER_Y = ( 66 + gsInvDescY); - ITEMDESC_CALIBER_WIDTH = 149; - ITEMDESC_NAME_X = ( 7 + gsInvDescX); - ITEMDESC_NAME_Y = ( 65 + gsInvDescY); - ITEMDESC_ITEM_X = ( 25 + gsInvDescX); - ITEMDESC_ITEM_Y = ( 6 + gsInvDescY); - // END ICONS SEGMENT - ITEMDESC_DESC_START_X = ( 23 + gsInvDescX ); - ITEMDESC_DESC_START_Y = (230 + gsInvDescY); - ITEMDESC_PROS_START_X = ( 23 + gsInvDescX ); - ITEMDESC_PROS_START_Y = (290 + gsInvDescY); - ITEMDESC_CONS_START_X = ( 23 + gsInvDescX ); - ITEMDESC_CONS_START_Y = (300 + gsInvDescY); - ITEMDESC_DESC_WIDTH = 220; - ITEMDESC_ITEM_STATUS_X = ( 18 + gsInvDescX ); - ITEMDESC_ITEM_STATUS_Y = ( 53 + gsInvDescY ); - ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_CALIBER_X = (105 + sX); + ITEMDESC_CALIBER_Y = ( 66 + sY); + ITEMDESC_CALIBER_WIDTH = 149; + ITEMDESC_NAME_X = ( 7 + sX); + ITEMDESC_NAME_Y = ( 65 + sY); + ITEMDESC_ITEM_X = ( 54 +sX); + ITEMDESC_ITEM_Y = ( -51 +sY); + ITEMDESC_ITEM_STATUS_X = ( 47 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( -4 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = (55 + sX); + ITEMDESC_AMMO_Y = (-14 + sY); + ITEMDESC_DONE_X = (199 + sX); + ITEMDESC_DONE_Y = (334 + sY); + } + } + else + { + //WarmSteel - LBE and money do not get a NAS discription box. + if(!UseNASDesc(pObject)){ + ITEMDESC_CALIBER_X = (105 + sX); + ITEMDESC_CALIBER_Y = ( 66 + sY); + ITEMDESC_CALIBER_WIDTH = 149; + ITEMDESC_NAME_X = ( 7 + sX); + ITEMDESC_NAME_Y = ( 65 + sY); + ITEMDESC_ITEM_X = ( 25 + sX); + ITEMDESC_ITEM_Y = ( 6 + sY); + ITEMDESC_ITEM_STATUS_X = ( 18 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 53 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = (28 + sX); + ITEMDESC_AMMO_Y = (44 + sY); + ITEMDESC_DONE_X = (204 + sX); + ITEMDESC_DONE_Y = (107 + sY); + } else { + ITEMDESC_CALIBER_X = (105 + sX); + ITEMDESC_CALIBER_Y = ( 65 + sY); + ITEMDESC_CALIBER_WIDTH = 149; + ITEMDESC_NAME_X = ( 7 + sX); + ITEMDESC_NAME_Y = ( 65 + sY); + ITEMDESC_ITEM_X = ( 54 + sX); + ITEMDESC_ITEM_Y = ( -51 + sY); + ITEMDESC_ITEM_STATUS_X = ( 47 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( -4 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = (54 + sX); + ITEMDESC_AMMO_Y = (-15 + sY); + ITEMDESC_DONE_X = (204 + sX); + ITEMDESC_DONE_Y = (107 + sY); + } + } } - else + else //Tactical { - // STRATEGIC Description Box Icon locations - BULLET_SING_X = ( 77 + gsInvDescX); - BULLET_SING_Y = (135 + gsInvDescY); - BULLET_BURST_X = (117 + gsInvDescX); - BULLET_BURST_Y = (135 + gsInvDescY); - ITEMDESC_CALIBER_X = (105 + gsInvDescX); - ITEMDESC_CALIBER_Y = ( 66 + gsInvDescY); - ITEMDESC_CALIBER_WIDTH = 149; - ITEMDESC_NAME_X = ( 7 + gsInvDescX); - ITEMDESC_NAME_Y = ( 65 + gsInvDescY); - ITEMDESC_ITEM_X = ( 25 + gsInvDescX); - ITEMDESC_ITEM_Y = ( 6 + gsInvDescY); - // END ICONS SEGMENT - ITEMDESC_DESC_START_X = ( 23 + gsInvDescX ); // Description Text Box, Strategic - ITEMDESC_DESC_START_Y = (170 + gsInvDescY); - ITEMDESC_PROS_START_X = ( 23 + gsInvDescX ); // Pros, Strategic - ITEMDESC_PROS_START_Y = (230 + gsInvDescY); - ITEMDESC_CONS_START_X = ( 23 + gsInvDescX ); // Cons, Strategic - ITEMDESC_CONS_START_Y = (240 + gsInvDescY); - ITEMDESC_DESC_WIDTH = 220; - ITEMDESC_ITEM_STATUS_X = ( 18 + gsInvDescX ); - ITEMDESC_ITEM_STATUS_Y = ( 53 + gsInvDescY ); - ITEMDESC_ITEM_STATUS_HEIGHT = 40; + if(UsingEDBSystem() == 1) // NIV EDB + { + //WarmSteel - LBE and money do not get a NAS discription box. + if(!UseNASDesc(pObject)){ + // Icon locations, Tactical + ITEMDESC_CALIBER_X = (50 + sX); + ITEMDESC_CALIBER_Y = (78 + sY); + ITEMDESC_CALIBER_WIDTH = 240; + ITEMDESC_NAME_X = (16 + sX); + ITEMDESC_NAME_Y = (67 + sY); + ITEMDESC_ITEM_X = ( 15 + sX); + ITEMDESC_ITEM_Y = ( 8 + sY); + ITEMDESC_ITEM_STATUS_X = ( 6 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 53 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = (15 + sX); + ITEMDESC_AMMO_Y = (43 + sY); + } else { + ITEMDESC_CALIBER_X = (-180 + sX); + ITEMDESC_CALIBER_Y = (180 + sY); + ITEMDESC_CALIBER_WIDTH = 240; + ITEMDESC_NAME_X = (-180 + sX); + ITEMDESC_NAME_Y = (180 + sY); + ITEMDESC_ITEM_X = ( -133 + sX); + ITEMDESC_ITEM_Y = ( 63 + sY); + ITEMDESC_ITEM_STATUS_X = ( -143 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 109 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = (-135 + sX); + ITEMDESC_AMMO_Y = (99 + sY); + } + } else { + + //WarmSteel - LBE and money do not get a NAS discription box. + if(!UseNASDesc(pObject)){ + ITEMDESC_CALIBER_X = (16 + sX); // Gun Caliber string location, Tactical, money or LBE + ITEMDESC_CALIBER_Y = (67 + sY); + ITEMDESC_CALIBER_WIDTH = 240;//142; + ITEMDESC_NAME_X = (16 + sX); + ITEMDESC_NAME_Y = (67 + sY); + ITEMDESC_ITEM_X = ( 15 + sX); + ITEMDESC_ITEM_Y = ( 8 + sY); + ITEMDESC_ITEM_STATUS_X = ( 6 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 53 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = 15 + sX; + ITEMDESC_AMMO_Y = 43 + sY; + } else { + // Icon locations, TACTICAL + ITEMDESC_CALIBER_X = (-80 + sX); // Gun Caliber string location, Tactical + ITEMDESC_CALIBER_Y = (180 + sY); + ITEMDESC_CALIBER_WIDTH = 240;//142; + ITEMDESC_NAME_X = (-80 + sX); + ITEMDESC_NAME_Y = (180 + sY); + ITEMDESC_ITEM_X = ( -33 + sX); + ITEMDESC_ITEM_Y = ( 64 + sY); + ITEMDESC_ITEM_STATUS_X = ( -42 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 109 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = -33 + sX; + ITEMDESC_AMMO_Y = 99 + sY; + } + } } - } - else //Tactical - { - if(UsingEDBSystem() == 1) // NIV EDB + } else { + INT16 sY = gsInvDescY; + INT16 sX = gsInvDescX; + + // Initiate variables for Enhanced Item Description Box system + if(guiCurrentScreen ==MAP_SCREEN) //Strategic { - // Icon locations, Tactical - BULLET_DRAW_X = (268 + gsInvDescX); - BULLET_DRAW_Y = (56 + gsInvDescY); - BULLET_SING_X = (268 + gsInvDescX); - BULLET_SING_Y = (68 + gsInvDescY); - BULLET_BURST_X = (268 + gsInvDescX); - BULLET_BURST_Y = (80 + gsInvDescY); - BULLET_AUTO_X = (268 + gsInvDescX); - BULLET_AUTO_Y = (92 + gsInvDescY); - BULLET_RELOAD_X = (268 + gsInvDescX); - BULLET_RELOAD_Y = (104 + gsInvDescY); - BULLET_MRELOAD_X = (268 + gsInvDescX); - BULLET_MRELOAD_Y = (116 + gsInvDescY); - BULLET_RANGE_X = (203 + gsInvDescX); - BULLET_RANGE_Y = (44 + gsInvDescY); - BULLET_DAMAGE_X = (203 + gsInvDescX); - BULLET_DAMAGE_Y = (56 + gsInvDescY); - BULLET_AUTOPEN_X = (203 + gsInvDescX); - BULLET_AUTOPEN_Y = (68 + gsInvDescY); - BULLET_AUTO5AP_X = (203 + gsInvDescX); - BULLET_AUTO5AP_Y = (80 + gsInvDescY); - BULLET_ACC_X = (203 + gsInvDescX); - BULLET_ACC_Y = (92 + gsInvDescY); - BULLET_RELIABILITY_X = (203 + gsInvDescX); - BULLET_RELIABILITY_Y = (104 + gsInvDescY); - BULLET_REPAIR_X = (203 + gsInvDescX); - BULLET_REPAIR_Y = (116 + gsInvDescY); - BULLET_FLASH_X = (226 + gsInvDescX); //291 - BULLET_FLASH_Y = (136 + gsInvDescY); //136 - BULLET_LOUDNESS_X = (203 + gsInvDescX); //268 - BULLET_LOUDNESS_Y = (160 + gsInvDescY); //159 - BULLET_TOHIT_X = (268 + gsInvDescX); //203 - BULLET_TOHIT_Y = (136 + gsInvDescY); //136 - BULLET_BESTLASERRANGE_X = (268 + gsInvDescX); //203 - BULLET_BESTLASERRANGE_Y = (148 + gsInvDescY); //148 - BULLET_AIMBONUS_X = (268 + gsInvDescX); //203 - BULLET_AIMBONUS_Y = (160 + gsInvDescY); //160 - BULLET_MINRANGEAIMBONUS_X = (268 + gsInvDescX); //203 - BULLET_MINRANGEAIMBONUS_Y = (172 + gsInvDescY); //172 - BULLET_BIPOD_X = (203 + gsInvDescX); //268 - BULLET_BIPOD_Y = (172 + gsInvDescY); //171 - - // Icon Locations for AMMO stats - BULLET_ARMORPEN_X = (203 + gsInvDescX); - BULLET_ARMORPEN_Y = (44 + gsInvDescY); - BULLET_TUMBLE_X = (203 + gsInvDescX); - BULLET_TUMBLE_Y = (56 + gsInvDescY); - BULLET_PREARMOR_X = (203 + gsInvDescX); - BULLET_PREARMOR_Y = (68 + gsInvDescY); - BULLET_TRACER_X = (271 + gsInvDescX); - BULLET_TRACER_Y = (44 + gsInvDescY); - BULLET_ANTITANK_X = (296 + gsInvDescX); - BULLET_ANTITANK_Y = (44 + gsInvDescY); - BULLET_LOCKBUSTER_X = (271 + gsInvDescX); - BULLET_LOCKBUSTER_Y = (68 + gsInvDescY); - BULLET_IGNOREARMOR_X = (296 + gsInvDescX); - BULLET_IGNOREARMOR_Y = (68 + gsInvDescY); - BULLET_ACIDIC_X = (271 + gsInvDescX); - BULLET_ACIDIC_Y = (92 + gsInvDescY); - BULLET_AMMORANGEBON_X = (203 + gsInvDescX); - BULLET_AMMORANGEBON_Y = (136 + gsInvDescY); - BULLET_AMMODAMAGEBON_X = (203 + gsInvDescX); - BULLET_AMMODAMAGEBON_Y = (160 + gsInvDescY); - BULLET_AMMOTOHITBON_X = (268 + gsInvDescX); - BULLET_AMMOTOHITBON_Y = (136 + gsInvDescY); - BULLET_AMMORELIABILITYBON_X = (203 + gsInvDescX); - BULLET_AMMORELIABILITYBON_Y = (172 + gsInvDescY); - BULLET_AMMOAUTOBON_X = (268 + gsInvDescX); - BULLET_AMMOAUTOBON_Y = (148 + gsInvDescY); - BULLET_AMMOBURSTBON_X = (268 + gsInvDescX); - BULLET_AMMOBURSTBON_Y = (160 + gsInvDescY); - BULLET_AMMONOISESUPP_X = (268 + gsInvDescX); - BULLET_AMMONOISESUPP_Y = (172 + gsInvDescY); - - // Icon Locations for EXPLOSIVES stats - BULLET_EXPLOSIVEDAMAGE_X = (203 + gsInvDescX); - BULLET_EXPLOSIVEDAMAGE_Y = (44 + gsInvDescY); - BULLET_EXPLOSIVESTUNDAMAGE_X = (203 + gsInvDescX); - BULLET_EXPLOSIVESTUNDAMAGE_Y = (56 + gsInvDescY); - BULLET_EXPLOSIVELOUDNESS_X = (203 + gsInvDescX); - BULLET_EXPLOSIVELOUDNESS_Y = (68 + gsInvDescY); - BULLET_EXPLOSIVEVOLATILITY_X = (203 + gsInvDescX); - BULLET_EXPLOSIVEVOLATILITY_Y = (80 + gsInvDescY); - BULLET_EXPLOSIVERADIUS_X = (288 + gsInvDescX); - BULLET_EXPLOSIVERADIUS_Y = (44 + gsInvDescY); - BULLET_EXPLOSIVESTARTRADIUS_X = (270 + gsInvDescX); - BULLET_EXPLOSIVESTARTRADIUS_Y = (44 + gsInvDescY); - BULLET_EXPLOSIVEARROW_X = (287 + gsInvDescX); - BULLET_EXPLOSIVEARROW_Y = (50 + gsInvDescY); - BULLET_EXPLOSIVEENDRADIUS_X = (303 + gsInvDescX); - BULLET_EXPLOSIVEENDRADIUS_Y = (44 + gsInvDescY); - BULLET_EXPLOSIVEDURATION_X = (268 + gsInvDescX); - BULLET_EXPLOSIVEDURATION_Y = (92 + gsInvDescY); - - // Icon Locations for ARMOR stats - BULLET_ARMOR_X = (203 + gsInvDescX); - BULLET_ARMOR_Y = (44 + gsInvDescY); - BULLET_ARMORCOVERAGE_X = (203 + gsInvDescX); - BULLET_ARMORCOVERAGE_Y = (56 + gsInvDescY); - BULLET_ARMORDEGRADE_X = (203 + gsInvDescX); - BULLET_ARMORDEGRADE_Y = (68 + gsInvDescY); - BULLET_ARMORAPBONUS_X = (268 + gsInvDescX); - BULLET_ARMORAPBONUS_Y = (44 + gsInvDescY); - BULLET_ARMORAIMBONUS_X = (268 + gsInvDescX); - BULLET_ARMORAIMBONUS_Y = (56 + gsInvDescY); - BULLET_ARMORWOODCAMO_X = (268 + gsInvDescX); - BULLET_ARMORWOODCAMO_Y = (68 + gsInvDescY); - BULLET_ARMORURBANCAMO_X = (268 + gsInvDescX); - BULLET_ARMORURBANCAMO_Y = (80 + gsInvDescY); - BULLET_ARMORDESERTCAMO_X = (268 + gsInvDescX); - BULLET_ARMORDESERTCAMO_Y = (92 + gsInvDescY); - BULLET_ARMORSNOWCAMO_X = (268 + gsInvDescX); - BULLET_ARMORSNOWCAMO_Y = (104 + gsInvDescY); - BULLET_ARMORSTEALTH_X = (268 + gsInvDescX); - BULLET_ARMORSTEALTH_Y = (116 + gsInvDescY); - BULLET_ARMORVISIONRANGEBONUS_X = (203 + gsInvDescX); - BULLET_ARMORVISIONRANGEBONUS_Y = (136 + gsInvDescY); - BULLET_ARMORDAYVISIONRANGEBONUS_X = (203 + gsInvDescX); - BULLET_ARMORDAYVISIONRANGEBONUS_Y = (148 + gsInvDescY); - BULLET_ARMORNIGHTVISIONRANGEBONUS_X = (203 + gsInvDescX); - BULLET_ARMORNIGHTVISIONRANGEBONUS_Y = (160 + gsInvDescY); - BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_X = (203 + gsInvDescX); - BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_Y = (172 + gsInvDescY); - BULLET_ARMORCAVEVISIONRANGEBONUS_X = (268 + gsInvDescX); - BULLET_ARMORCAVEVISIONRANGEBONUS_Y = (136 + gsInvDescY); - BULLET_ARMORPERCENTTUNNELVISION_X = (268 + gsInvDescX); - BULLET_ARMORPERCENTTUNNELVISION_Y = (148 + gsInvDescY); - BULLET_ARMORHEARINGRANGEBONUS_X = (268 + gsInvDescX); - BULLET_ARMORHEARINGRANGEBONUS_Y = (160 + gsInvDescY); - - // Generic Icon Locations for MISC Item Stats - BULLET_COL1ROW1_X = (203 + gsInvDescX); - BULLET_COL1ROW1_Y = (44 + gsInvDescY); - BULLET_COL1ROW2_X = (203 + gsInvDescX); - BULLET_COL1ROW2_Y = (56 + gsInvDescY); - BULLET_COL1ROW3_X = (203 + gsInvDescX); - BULLET_COL1ROW3_Y = (68 + gsInvDescY); - BULLET_COL1ROW4_X = (203 + gsInvDescX); - BULLET_COL1ROW4_Y = (80 + gsInvDescY); - BULLET_COL1ROW5_X = (203 + gsInvDescX); - BULLET_COL1ROW5_Y = (92 + gsInvDescY); - BULLET_COL1ROW6_X = (203 + gsInvDescX); - BULLET_COL1ROW6_Y = (104 + gsInvDescY); - BULLET_COL1ROW7_X = (203 + gsInvDescX); - BULLET_COL1ROW7_Y = (116 + gsInvDescY); - BULLET_COL1ROW8_X = (203 + gsInvDescX); - BULLET_COL1ROW8_Y = (128 + gsInvDescY); - BULLET_COL1ROW9_X = (203 + gsInvDescX); - BULLET_COL1ROW9_Y = (140 + gsInvDescY); - BULLET_COL1ROW10_X = (203 + gsInvDescX); - BULLET_COL1ROW10_Y = (152 + gsInvDescY); - BULLET_COL1ROW11_X = (203 + gsInvDescX); - BULLET_COL1ROW11_Y = (164 + gsInvDescY); - BULLET_COL1ROW12_X = (203 + gsInvDescX); - BULLET_COL1ROW12_Y = (176 + gsInvDescY); - ITEMDESC_CALIBER_X = ( 50 + gsInvDescX); - ITEMDESC_CALIBER_Y = ( 78 + gsInvDescY); - ITEMDESC_CALIBER_WIDTH = 142; - ITEMDESC_NAME_X = ( 16 + gsInvDescX); - ITEMDESC_NAME_Y = ( 67 + gsInvDescY); - ITEMDESC_ITEM_X = ( 8 + gsInvDescX); - ITEMDESC_ITEM_Y = ( 11 + gsInvDescY); - ITEMDESC_DESC_START_X = ( 11 + gsInvDescX); - ITEMDESC_DESC_START_Y = ( 94 + gsInvDescY); - ITEMDESC_PROS_START_X = ( 11 + gsInvDescX ); - ITEMDESC_PROS_START_Y = (168 + gsInvDescY); - ITEMDESC_CONS_START_X = ( 11 + gsInvDescX ); - ITEMDESC_CONS_START_Y = (178 + gsInvDescY); - ITEMDESC_DESC_WIDTH = 180; - ITEMDESC_ITEM_STATUS_X = ( 6 + gsInvDescX ); - ITEMDESC_ITEM_STATUS_Y = ( 60 + gsInvDescY ); - ITEMDESC_ITEM_STATUS_HEIGHT = 50; + if(UsingEDBSystem() > 0) + { + // STRATEGIC Description Box Icons + ITEMDESC_CALIBER_X = (105 + sX); + ITEMDESC_CALIBER_Y = ( 66 + sY); + ITEMDESC_CALIBER_WIDTH = 149; + ITEMDESC_NAME_X = ( 7 + sX); + ITEMDESC_NAME_Y = ( 65 + sY); + ITEMDESC_ITEM_X = ( 25 + sX); + ITEMDESC_ITEM_Y = ( 6 + sY); + ITEMDESC_ITEM_STATUS_X = ( 18 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 53 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = 10 + 16 + sX; + ITEMDESC_AMMO_Y = 50 - 6 + sY; + ITEMDESC_DONE_X = 199 + sX; + ITEMDESC_DONE_Y = 334 + sY; + } + else + { + ITEMDESC_CALIBER_X = (105 + sX); + ITEMDESC_CALIBER_Y = ( 66 + sY); + ITEMDESC_CALIBER_WIDTH = 149; + ITEMDESC_NAME_X = ( 7 + sX); + ITEMDESC_NAME_Y = ( 65 + sY); + ITEMDESC_ITEM_X = ( 25 + sX); + ITEMDESC_ITEM_Y = ( 6 + sY); + ITEMDESC_ITEM_STATUS_X = ( 18 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 53 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 40; + ITEMDESC_AMMO_X = 10 + 18 + sX; + ITEMDESC_AMMO_Y = 50 - 6 + sY; + ITEMDESC_DONE_X = 204 + sX; + ITEMDESC_DONE_Y = 107 + sY; + } } - else if(UsingEDBSystem() == 2) // OIV EDB + else //Tactical { - // Icon locations, Tactical - BULLET_DRAW_X = (341 + gsInvDescX); - BULLET_DRAW_Y = (26 + gsInvDescY); - BULLET_SING_X = (341 + gsInvDescX); - BULLET_SING_Y = (38 + gsInvDescY); - BULLET_BURST_X = (341 + gsInvDescX); - BULLET_BURST_Y = (50 + gsInvDescY); - BULLET_AUTO_X = (341 + gsInvDescX); - BULLET_AUTO_Y = (62 + gsInvDescY); - BULLET_RELOAD_X = (341 + gsInvDescX); - BULLET_RELOAD_Y = (74 + gsInvDescY); - BULLET_MRELOAD_X = (341 + gsInvDescX); - BULLET_MRELOAD_Y = (86 + gsInvDescY); - BULLET_RANGE_X = (274 + gsInvDescX); - BULLET_RANGE_Y = (14 + gsInvDescY); - BULLET_DAMAGE_X = (274 + gsInvDescX); - BULLET_DAMAGE_Y = (26 + gsInvDescY); - BULLET_AUTOPEN_X = (274 + gsInvDescX); - BULLET_AUTOPEN_Y = (38 + gsInvDescY); - BULLET_AUTO5AP_X = (274 + gsInvDescX); - BULLET_AUTO5AP_Y = (50 + gsInvDescY); - BULLET_ACC_X = (274 + gsInvDescX); - BULLET_ACC_Y = (62 + gsInvDescY); - BULLET_RELIABILITY_X = (274 + gsInvDescX); - BULLET_RELIABILITY_Y = (74 + gsInvDescY); - BULLET_REPAIR_X = (274 + gsInvDescX); - BULLET_REPAIR_Y = (86 + gsInvDescY); - BULLET_FLASH_X = (431 + gsInvDescX); //291 - BULLET_FLASH_Y = (14 + gsInvDescY); //136 - BULLET_LOUDNESS_X = (408 + gsInvDescX); //268 - BULLET_LOUDNESS_Y = (26 + gsInvDescY); //159 - BULLET_TOHIT_X = (408 + gsInvDescX); //203 - BULLET_TOHIT_Y = (38 + gsInvDescY); //136 - BULLET_BESTLASERRANGE_X = (408 + gsInvDescX); //203 - BULLET_BESTLASERRANGE_Y = (50 + gsInvDescY); //148 - BULLET_AIMBONUS_X = (408 + gsInvDescX); //203 - BULLET_AIMBONUS_Y = (62 + gsInvDescY); //160 - BULLET_MINRANGEAIMBONUS_X = (408 + gsInvDescX); //203 - BULLET_MINRANGEAIMBONUS_Y = (74 + gsInvDescY); //172 - BULLET_BIPOD_X = (408 + gsInvDescX); //268 - BULLET_BIPOD_Y = (86 + gsInvDescY); //171 - - // Icon Locations for AMMO stats - BULLET_ARMORPEN_X = (274 + gsInvDescX); - BULLET_ARMORPEN_Y = (14 + gsInvDescY); - BULLET_TUMBLE_X = (274 + gsInvDescX); - BULLET_TUMBLE_Y = (26 + gsInvDescY); - BULLET_PREARMOR_X = (274 + gsInvDescX); - BULLET_PREARMOR_Y = (38 + gsInvDescY); - BULLET_TRACER_X = (344 + gsInvDescX); - BULLET_TRACER_Y = (14 + gsInvDescY); - BULLET_ANTITANK_X = (369 + gsInvDescX); - BULLET_ANTITANK_Y = (14 + gsInvDescY); - BULLET_LOCKBUSTER_X = (344 + gsInvDescX); - BULLET_LOCKBUSTER_Y = (38 + gsInvDescY); - BULLET_IGNOREARMOR_X = (369 + gsInvDescX); - BULLET_IGNOREARMOR_Y = (38 + gsInvDescY); - BULLET_ACIDIC_X = (344 + gsInvDescX); - BULLET_ACIDIC_Y = (62 + gsInvDescY); - BULLET_AMMORANGEBON_X = (408 + gsInvDescX); - BULLET_AMMORANGEBON_Y = (14 + gsInvDescY); - BULLET_AMMODAMAGEBON_X = (408 + gsInvDescX); - BULLET_AMMODAMAGEBON_Y = (26 + gsInvDescY); - BULLET_AMMOTOHITBON_X = (408 + gsInvDescX); - BULLET_AMMOTOHITBON_Y = (38 + gsInvDescY); - BULLET_AMMOAUTOBON_X = (408 + gsInvDescX); - BULLET_AMMOAUTOBON_Y = (50 + gsInvDescY); - BULLET_AMMOBURSTBON_X = (408 + gsInvDescX); - BULLET_AMMOBURSTBON_Y = (62 + gsInvDescY); - BULLET_AMMORELIABILITYBON_X = (408 + gsInvDescX); - BULLET_AMMORELIABILITYBON_Y = (74 + gsInvDescY); - BULLET_AMMONOISESUPP_X = (408 + gsInvDescX); - BULLET_AMMONOISESUPP_Y = (86 + gsInvDescY); - - // Icon Locations for EXPLOSIVES stats - BULLET_EXPLOSIVEDAMAGE_X = (274 + gsInvDescX); - BULLET_EXPLOSIVEDAMAGE_Y = (14 + gsInvDescY); - BULLET_EXPLOSIVESTUNDAMAGE_X = (274 + gsInvDescX); - BULLET_EXPLOSIVESTUNDAMAGE_Y = (26 + gsInvDescY); - BULLET_EXPLOSIVELOUDNESS_X = (274 + gsInvDescX); - BULLET_EXPLOSIVELOUDNESS_Y = (38 + gsInvDescY); - BULLET_EXPLOSIVEVOLATILITY_X = (274 + gsInvDescX); - BULLET_EXPLOSIVEVOLATILITY_Y = (50 + gsInvDescY); - BULLET_EXPLOSIVERADIUS_X = (359 + gsInvDescX); - BULLET_EXPLOSIVERADIUS_Y = (14 + gsInvDescY); - BULLET_EXPLOSIVESTARTRADIUS_X = (343 + gsInvDescX); - BULLET_EXPLOSIVESTARTRADIUS_Y = (14 + gsInvDescY); - BULLET_EXPLOSIVEARROW_X = (362 + gsInvDescX); - BULLET_EXPLOSIVEARROW_Y = (20 + gsInvDescY); - BULLET_EXPLOSIVEENDRADIUS_X = (378 + gsInvDescX); - BULLET_EXPLOSIVEENDRADIUS_Y = (14 + gsInvDescY); - BULLET_EXPLOSIVEDURATION_X = (341 + gsInvDescX); - BULLET_EXPLOSIVEDURATION_Y = (62 + gsInvDescY); - - // Icon Locations for ARMOR stats - BULLET_ARMOR_X = (274 + gsInvDescX); - BULLET_ARMOR_Y = (14 + gsInvDescY); - BULLET_ARMORCOVERAGE_X = (274 + gsInvDescX); - BULLET_ARMORCOVERAGE_Y = (26 + gsInvDescY); - BULLET_ARMORDEGRADE_X = (274 + gsInvDescX); - BULLET_ARMORDEGRADE_Y = (38 + gsInvDescY); - BULLET_ARMORAPBONUS_X = (341 + gsInvDescX); - BULLET_ARMORAPBONUS_Y = (14 + gsInvDescY); - BULLET_ARMORAIMBONUS_X = (341 + gsInvDescX); - BULLET_ARMORAIMBONUS_Y = (26 + gsInvDescY); - BULLET_ARMORWOODCAMO_X = (341 + gsInvDescX); - BULLET_ARMORWOODCAMO_Y = (38 + gsInvDescY); - BULLET_ARMORURBANCAMO_X = (341 + gsInvDescX); - BULLET_ARMORURBANCAMO_Y = (50 + gsInvDescY); - BULLET_ARMORDESERTCAMO_X = (341 + gsInvDescX); - BULLET_ARMORDESERTCAMO_Y = (62 + gsInvDescY); - BULLET_ARMORSNOWCAMO_X = (341 + gsInvDescX); - BULLET_ARMORSNOWCAMO_Y = (74 + gsInvDescY); - BULLET_ARMORSTEALTH_X = (341 + gsInvDescX); - BULLET_ARMORSTEALTH_Y = (86 + gsInvDescY); - BULLET_ARMORVISIONRANGEBONUS_X = (408 + gsInvDescX); - BULLET_ARMORVISIONRANGEBONUS_Y = (14 + gsInvDescY); - BULLET_ARMORDAYVISIONRANGEBONUS_X = (408 + gsInvDescX); - BULLET_ARMORDAYVISIONRANGEBONUS_Y = (26 + gsInvDescY); - BULLET_ARMORNIGHTVISIONRANGEBONUS_X = (408 + gsInvDescX); - BULLET_ARMORNIGHTVISIONRANGEBONUS_Y = (38 + gsInvDescY); - BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_X = (408 + gsInvDescX); - BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_Y = (50 + gsInvDescY); - BULLET_ARMORCAVEVISIONRANGEBONUS_X = (408 + gsInvDescX); - BULLET_ARMORCAVEVISIONRANGEBONUS_Y = (68 + gsInvDescY); - BULLET_ARMORPERCENTTUNNELVISION_X = (408 + gsInvDescX); - BULLET_ARMORPERCENTTUNNELVISION_Y = (72 + gsInvDescY); - BULLET_ARMORHEARINGRANGEBONUS_X = (408 + gsInvDescX); - BULLET_ARMORHEARINGRANGEBONUS_Y = (86 + gsInvDescY); - - // Generic Icon Locations for MISC Item Stats - BULLET_COL1ROW1_X = (274 + gsInvDescX); - BULLET_COL1ROW1_Y = (14 + gsInvDescY); - BULLET_COL1ROW2_X = (274 + gsInvDescX); - BULLET_COL1ROW2_Y = (26 + gsInvDescY); - BULLET_COL1ROW3_X = (274 + gsInvDescX); - BULLET_COL1ROW3_Y = (38 + gsInvDescY); - BULLET_COL1ROW4_X = (274 + gsInvDescX); - BULLET_COL1ROW4_Y = (50 + gsInvDescY); - BULLET_COL1ROW5_X = (274 + gsInvDescX); - BULLET_COL1ROW5_Y = (62 + gsInvDescY); - BULLET_COL1ROW6_X = (274 + gsInvDescX); - BULLET_COL1ROW6_Y = (74 + gsInvDescY); - BULLET_COL1ROW7_X = (274 + gsInvDescX); - BULLET_COL1ROW7_Y = (86 + gsInvDescY); - BULLET_COL1ROW8_X = (375 + gsInvDescX); - BULLET_COL1ROW8_Y = (14 + gsInvDescY); - BULLET_COL1ROW9_X = (375 + gsInvDescX); - BULLET_COL1ROW9_Y = (26 + gsInvDescY); - BULLET_COL1ROW10_X = (375 + gsInvDescX); - BULLET_COL1ROW10_Y = (38 + gsInvDescY); - BULLET_COL1ROW11_X = (375 + gsInvDescX); - BULLET_COL1ROW11_Y = (50 + gsInvDescY); - BULLET_COL1ROW12_X = (375 + gsInvDescX); - BULLET_COL1ROW12_Y = (62 + gsInvDescY); - ITEMDESC_CALIBER_X = ( 53 + gsInvDescX); // Caliber text moved two lines below item name, and pulled closer - ITEMDESC_CALIBER_Y = ( 78 + gsInvDescY); - ITEMDESC_CALIBER_WIDTH = 142; - ITEMDESC_NAME_X = ( 16 + gsInvDescX); - ITEMDESC_NAME_Y = ( 67 + gsInvDescY); - ITEMDESC_ITEM_X = ( 8 + gsInvDescX); - ITEMDESC_ITEM_Y = ( 11 + gsInvDescY); - ITEMDESC_DESC_START_X = (11 + gsInvDescX); // Description text Y moved downwards one line. - ITEMDESC_DESC_START_Y = (102 + gsInvDescY); - ITEMDESC_PROS_START_X = (438 + gsInvDescX ); // Pros and cons moved to the extreme right of the text box. They - ITEMDESC_PROS_START_Y = (106 + gsInvDescY); // now show just the words "PROS" and "CONS", and have a tooltip - ITEMDESC_CONS_START_X = (438 + gsInvDescX ); // region over them for expanded text. :D - ITEMDESC_CONS_START_Y = (118 + gsInvDescY); - ITEMDESC_DESC_WIDTH = 415; // Much wider in OIV tactical than other shapes - ITEMDESC_ITEM_STATUS_X = ( 6 + gsInvDescX ); - ITEMDESC_ITEM_STATUS_Y = ( 60 + gsInvDescY ); - ITEMDESC_ITEM_STATUS_HEIGHT = 50; - } - else - { - // Icon locations, TACTICAL - BULLET_SING_X = (222 + gsInvDescX); - BULLET_SING_Y = (49 + gsInvDescY); - BULLET_BURST_X = (263 + gsInvDescX); - BULLET_BURST_Y = (49 + gsInvDescY); - ITEMDESC_CALIBER_X = (162 + gsInvDescX); // Gun Caliber string location, Tactical - ITEMDESC_CALIBER_Y = ( 67 + gsInvDescY); - ITEMDESC_CALIBER_WIDTH = 142; - ITEMDESC_NAME_X = ( 16 + gsInvDescX); - ITEMDESC_NAME_Y = ( 67 + gsInvDescY); - ITEMDESC_ITEM_X = ( 8 + gsInvDescX); - ITEMDESC_ITEM_Y = ( 11 + gsInvDescY); - ITEMDESC_DESC_START_X = (11 + gsInvDescX); // Item Desc Box offset, tactical - ITEMDESC_DESC_START_Y = (80 + gsInvDescY); - ITEMDESC_PROS_START_X = ( 11 + gsInvDescX ); // Pros, tactical - ITEMDESC_PROS_START_Y = (110 + gsInvDescY); - ITEMDESC_CONS_START_X = ( 11 + gsInvDescX ); // Cons, Tactical - ITEMDESC_CONS_START_Y = (120 + gsInvDescY); - ITEMDESC_DESC_WIDTH = 301; // Text box width, Tactical - ITEMDESC_ITEM_STATUS_X = ( 6 + gsInvDescX ); - ITEMDESC_ITEM_STATUS_Y = ( 60 + gsInvDescY ); - ITEMDESC_ITEM_STATUS_HEIGHT = 50; + if(UsingEDBSystem() == 1) // NIV EDB + { + ITEMDESC_CALIBER_X = ( 50 + sX); + ITEMDESC_CALIBER_Y = ( 78 + sY); + ITEMDESC_CALIBER_WIDTH = 142; + ITEMDESC_NAME_X = ( 16 + sX); + ITEMDESC_NAME_Y = ( 67 + sY); + ITEMDESC_ITEM_X = ( 8 + sX); + ITEMDESC_ITEM_Y = ( 11 + sY); + ITEMDESC_ITEM_STATUS_X = ( 6 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 60 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 50; + ITEMDESC_AMMO_X = 10 + sX; + ITEMDESC_AMMO_Y = 50 + sY; + } else { + ITEMDESC_CALIBER_X = (162 + sX); // Gun Caliber string location, Tactical + ITEMDESC_CALIBER_Y = ( 67 + sY); + ITEMDESC_CALIBER_WIDTH = 142; + ITEMDESC_NAME_X = ( 16 + sX); + ITEMDESC_NAME_Y = ( 67 + sY); + ITEMDESC_ITEM_X = ( 8 + sX); + ITEMDESC_ITEM_Y = ( 11 + sY); + ITEMDESC_ITEM_STATUS_X = ( 6 + sX ); + ITEMDESC_ITEM_STATUS_Y = ( 60 + sY ); + ITEMDESC_ITEM_STATUS_HEIGHT = 50; + ITEMDESC_AMMO_X = 10 + sX; + ITEMDESC_AMMO_Y = 50 + sY; + } } } } @@ -1914,9 +1220,16 @@ BOOLEAN InternalInitEnhancedDescBox() strcpy( VObjectDesc.ImageFile, "INTERFACE\\ItemInfoArmorIcons.STI" ); CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoArmorIcon ) ); + // HEADROCK HAM 4: Secondary icons VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; - strcpy( VObjectDesc.ImageFile, "INTERFACE\\ItemInfoMiscIcons.STI" ); - CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoMiscIcon ) ); + strcpy( VObjectDesc.ImageFile, "INTERFACE\\ItemInfoSecondaryIcons.STI" ); + CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoSecondaryIcon ) ); + + // HEADROCK HAM 4: Advanced Icons + VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; + strcpy( VObjectDesc.ImageFile, "INTERFACE\\ItemInfoAdvancedIcons.STI" ); + CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoAdvancedIcon ) ); + } return (TRUE); @@ -1924,1604 +1237,2017 @@ BOOLEAN InternalInitEnhancedDescBox() void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurrentItemDescriptionScreen ) { - INT32 cnt; + INT32 cnt, cnt2; INT32 threshold; + INT32 iRegionsCreated = 0; + INT32 iFirstDataRegion = 0; - InitEDBCoords(); + InitEDBCoords( gpItemDescObject ); //start by deleting the currently defined regions if they exist - for ( cnt = 0; cnt < 20; cnt++ ) + for ( cnt = 0; cnt < NUM_UDB_FASTHELP_REGIONS; cnt++ ) { - if( gStatsFasthelpRegions[ cnt ].IDNumber != 0 ) - MSYS_RemoveRegion( &gStatsFasthelpRegions[ cnt ]); + if( gUDBFasthelpRegions[ cnt ].IDNumber != 0 ) + MSYS_RemoveRegion( &gUDBFasthelpRegions[ cnt ]); } if( guiCurrentScreen == MAP_SCREEN ) threshold = 13; else threshold = 11; - - // Strategic EDB - if ( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + + + ///////////////////////////////////////////////////////////////////////////////// + // WEAPONS + ///////////////////////////////////////////////////////////////////////////////// + if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON || Item[ gpItemDescObject->usItem ].usItemClass & IC_PUNCH ) { - /////////////////////////////////////////// - // Begin Weapon Item Tooltip Regions - - if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON || Item[ gpItemDescObject->usItem ].usItemClass & IC_PUNCH ) + if (gubDescBoxPage == 1) { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gWeaponDescStatsRects[ cnt ].iLeft), - (INT16)(gWeaponDescStatsRects[ cnt ].iTop), - (INT16)(gWeaponDescStatsRects[ cnt ].iRight), - (INT16)(gWeaponDescStatsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + /////////////////// HEADERS - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzWeaponStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); + for (cnt = 0; cnt < 3; cnt++) + { + /////////////////// HEADER #1: Primary Properties + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenHeaderRegions[cnt].sLeft), + (INT16)(gItemDescGenHeaderRegions[cnt].sTop), + (INT16)(gItemDescGenHeaderRegions[cnt].sRight), + (INT16)(gItemDescGenHeaderRegions[cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + if (cnt > 0) + { + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBHeaderTooltipText[ cnt+1 ] ); + } + else + { + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBHeaderTooltipText[ cnt ] ); + } + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - - // Enable regions one-by-one as necessary + + ////////////////// INDEXES + for (cnt = 0; cnt < 3; cnt++) + { + for (cnt2 = 0; cnt2 < 4; cnt2++) + { + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenIndexRegions[cnt][cnt2].sLeft), + (INT16)(gItemDescGenIndexRegions[cnt][cnt2].sTop), + (INT16)(gItemDescGenIndexRegions[cnt][cnt2].sRight), + (INT16)(gItemDescGenIndexRegions[cnt][cnt2].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - // Relevant to all weapons - - // RELIABILITY - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - - // REPAIR EASE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); - - ////////////////////////////////// - // BEGIN SINGLE ATTACK SEGMENT - - // Non-Launcher Guns and Grenade-Launchers only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER|IC_PUNCH) && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - - // SINGLE-SHOT AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - - if ( Weapon[gpItemDescObject->usItem].NoSemiAuto ) - { - // "NO SINGLE-SHOT" - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelp[ 23 ] ); + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBGenIndexTooltipText[ cnt2 ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } } - // Rocket-Launchers Only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && Item[gpItemDescObject->usItem].rocketlauncher ) + iFirstDataRegion = iRegionsCreated; + CHAR16 pStr[1000]; + + ///////////////// PRIMARY DATA - ICONS + for (cnt = 0; cnt < 12; cnt++) { - // SINGLE ROCKET-LAUNCH AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelp[ 21 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenRegions[cnt][0].sLeft), + (INT16)(gItemDescGenRegions[cnt][0].sTop), + (INT16)(gItemDescGenRegions[cnt][0].sRight), + (INT16)(gItemDescGenRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + if(UsingNewCTHSystem() == true) + swprintf( pStr, L"%s%s", szUDBGenWeaponsStatsTooltipText[ cnt ], szUDBGenWeaponsStatsExplanationsTooltipText[ cnt ]); + else + swprintf( pStr, L"%s", gzWeaponStatsFasthelpTactical[ cnt ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), pStr ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; } - // Throwing-Knives Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_THROWING_KNIFE ) + // HEADROCK HAM 4: TODO in the future: Add tooltips explaining how much bonus is given by EACH ATTACHMENT. + + ///////////////// AP COST DATA - ICONS + for (cnt = 13; cnt < 19; cnt++) { - // THROW KNIFE AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelp[ 20 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenRegions[cnt][0].sLeft), + (INT16)(gItemDescGenRegions[cnt][0].sTop), + (INT16)(gItemDescGenRegions[cnt][0].sRight), + (INT16)(gItemDescGenRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + if(UsingNewCTHSystem() == true) + swprintf( pStr, L"%s%s", szUDBGenWeaponsStatsTooltipText[ cnt ], szUDBGenWeaponsStatsExplanationsTooltipText[ cnt ]); + else + swprintf( pStr, L"%s", gzWeaponStatsFasthelpTactical[ cnt ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), pStr ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; } - // Blades Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_BLADE ) + ///////////////// BURST/AUTOFIRE DATA - ICONS + for (cnt = 19; cnt < 22; cnt++) { - // SLASH AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelp[ 22 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenRegions[cnt][0].sLeft), + (INT16)(gItemDescGenRegions[cnt][0].sTop), + (INT16)(gItemDescGenRegions[cnt][0].sRight), + (INT16)(gItemDescGenRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + if(UsingNewCTHSystem() == true) + swprintf( pStr, L"%s%s", szUDBGenWeaponsStatsTooltipText[ cnt ], szUDBGenWeaponsStatsExplanationsTooltipText[ cnt ]); + else + swprintf( pStr, L"%s", gzWeaponStatsFasthelpTactical[ cnt ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), pStr ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; } - // Blunts Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_PUNCH ) - { - // SLASH AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelp[ 26 ] ); - } + ///////////////////////////////////////////////////////// + // Now enable regions that fit this specific weapon's information. - // END SINGLE ATTACK SEGMENT - //////////////////////////////////// - - //////////////////////////////////// - // BEGIN BURST ATTACK SEGMENT - - // Non-Launcher Guns and Grenade-Launchers only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - // BURST - MSYS_EnableRegion( &gStatsFasthelpRegions[ 9 ] ); - - if (GetShotsPerBurst(gpItemDescObject) <= 0 ) - { - // "NO BURST" - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 9 ]), gzWeaponStatsFasthelp[ 24 ] ); - } - } - - // END BURST ATTACK SEGMENT - //////////////////////////////////// - - //////////////////////////////////// - // BEGIN AUTO ATTACK SEGMENT - - // Non-Launcher Guns Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 10 ] ); - - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) <= 0 ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 10 ]), gzWeaponStatsFasthelp[ 25 ] ); - } - } - - // END AUTO ATTACK SEGMENT - /////////////////////////////////// - - // Guns, Throwing knives and Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) - { - // RANGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); - } - - // Guns and Launchers Only + /////////////////// ACCURACY if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) { - // ACCURACY - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 0 ] ); } - // Guns and Multi-use Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // RELOAD AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 11 ] ); - - if ( Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) - { - // RELOAD MANUALLY AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 12 ] ); - } - } - - // Guns and Grenade Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_PUNCH) && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - // DRAW AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - } - - // Non-Launcher Guns, Blades, and Throwing Knives only + /////////////////// DAMAGE if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_BLADE|IC_PUNCH|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) { - // DAMAGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 1 ] ); } - // Non-Launcher Guns Only - if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher ) + /////////////////// RANGE + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) { - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 || GetShotsPerBurst(gpItemDescObject)> 0 ) - { - // BURST PENALTY - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - if ( GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 && GetShotsPerBurst(gpItemDescObject) <= 0 ) - { - // Change help text to "Autofire Penalty" (no burst) - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 2 ]), gzWeaponStatsFasthelp[ 27 ] ); - } - if ( GetShotsPerBurst(gpItemDescObject) > 0 && GetAutofireShotsPerFiveAPs(gpItemDescObject) <= 0 ) - { - // Change help text to "Burst Penalty" (no autofire) - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 2 ]), gzWeaponStatsFasthelp[ 28 ] ); - } - } - - if ( GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) - { - // AUTOFIRE SHOTS PER 5 AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); - } + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); } - ////////////////////////////////////////////////////////////////////// - // Begin non-type-specific icons. These are not type specific because they represent bonuses - // which may one day be added to various types of weapons by modders... - - if (Weapon[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubAttackVolume > 0 ) + /////////////////// AIMING LEVELS + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) { - // NOISE REDUCTION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 14 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] ); } - + + /////////////////// SCOPE MAGNIFICATION + if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_GUN ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 4 ] ); + } + + /////////////////// PROJECTION FACTOR + if ( GetProjectionFactor( gpItemDescObject ) > 1.0f ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 5 ] ); + } + /////////////////// FLASH SUPPRESSION if (IsFlashSuppressorAlt( gpItemDescObject ) == TRUE) { - // HIDE FLASH - MSYS_EnableRegion( &gStatsFasthelpRegions[ 13 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 6 ] ); } - if (GetFlatToHitBonus( gpItemDescObject ) != 0) + /////////////////// LOUDNESS + if (Weapon[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubAttackVolume > 0 ) { - // HIT BONUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 15 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 7 ] ); + } - if (GetFlatToHitBonus( gpItemDescObject ) > 0 && GetAverageBestLaserRange( gpItemDescObject ) / 10 > 0 ) + /////////////////// RELIABILITY + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 8 ] ); + } + + /////////////////// REPAIR EASE + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 9 ] ); + } + + /////////////////// MinRangeForAimBonus + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 10 ] ); + } + + /////////////////// ToHitBonus + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 11 ] ); + } + + /////////////////// AP TO DRAW + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_PUNCH) && !Item[ gpItemDescObject->usItem].rocketlauncher ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 12 ] ); + } + + /////////////////// AP TO SINGLE ATTACK + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 13 ] ); + } + + /////////////////// AP TO BURST + if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[gpItemDescObject->usItem].rocketlauncher ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 14 ] ); + } + + /////////////////// AP TO AUTOFIRE + if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 15 ] ); + } + + /////////////////// AP TO RELOAD + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 16 ] ); + } + + /////////////////// AP TO RELOAD MANUALLY + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher && Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 17 ] ); + } + + /////////////////// RECOIL X/Y + if( UsingNewCTHSystem() == true ) + { + if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher && (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 || GetShotsPerBurst(gpItemDescObject)> 0 ) ) { - // LASER RANGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 16 ] ); - } + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 18 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 19 ] ); + } + } + else /////////////////// BIPOD + { + if( GetBipodBonus(gpItemDescObject) > 0 ) + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 19 ] ); } - if (GetBipodBonus( gpItemDescObject ) != 0) + /////////////////// BULLETS PER 5 AP + if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher && GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) { - // BIPOD BONUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 19 ] ); - } - - if (IsScoped( gpItemDescObject )) - { - // SCOPE AIM BONUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 17 ] ); - if (GetMinRangeForAimBonus( gpItemDescObject ) > 0) - { - // LASER RANGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 18 ] ); - } - } - - } - - /////////////////////////////////////////////////// - // Begin Ammo Item Tooltip Section - - else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_AMMO ) - { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gAmmoDescStatsRects[ cnt ]. iLeft), - (INT16)(gAmmoDescStatsRects[ cnt ].iTop), - (INT16)(gAmmoDescStatsRects[ cnt ].iRight), - (INT16)(gAmmoDescStatsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzAmmoStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); - } - - // AMMO PENETRATION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); - - // AMMO TUMBLE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); - - // AMMO PRE-IMPACT EXPLOSION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - // TRACER - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].tracerEffect ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); - } - - // ANTI-TANK - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].antiTank ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); - } - - // LOCKBUSTER - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].lockBustingPower ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - } - - // IGNORE ARMOR - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].ignoreArmour ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); - } - - // ACIDIC ICON - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].acidic ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - } - - // RANGE BONUS - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - } - - // DAMAGE BONUS - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 9 ] ); - } - - // TO HIT BONUS - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 10 ] ); - } - - // AUTO BONUS - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 11 ] ); - } - - // BURST BONUS - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 12 ] ); - } - - // RELIABILITY BONUS - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 13 ] ); - } - - // NOISE SUPPRESSION - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 14 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 20 ] ); } } + } - /////////////////////////////////////////////////// - // Begin Armor Item Tooltip Section + ///////////////////////////////////////////////////////////////////////////////// + // ARMOR + ///////////////////////////////////////////////////////////////////////////////// - else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_ARMOUR ) + else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_ARMOUR ) + { + if (gubDescBoxPage == 1) { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gArmorDescStatsRects[ cnt ]. iLeft), - (INT16)(gArmorDescStatsRects[ cnt ].iTop), - (INT16)(gArmorDescStatsRects[ cnt ].iRight), - (INT16)(gArmorDescStatsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + /////////////////// HEADERS - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzArmorStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); + for (cnt = 0; cnt < 2; cnt++) + { + /////////////////// HEADER #1: Primary Properties + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenHeaderRegions[cnt].sLeft), + (INT16)(gItemDescGenHeaderRegions[cnt].sTop), + (INT16)(gItemDescGenHeaderRegions[cnt].sRight), + (INT16)(gItemDescGenHeaderRegions[cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBHeaderTooltipText[ cnt ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - // PROTECTION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); - - // COVERAGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); - - // ARMOR DEGRADE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - // AP BONUS - if ( GetAPBonus ( gpItemDescObject ) != 0 ) + ////////////////// INDEX + for (cnt = 0; cnt < 4; cnt++) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenIndexRegions[0][cnt].sLeft), + (INT16)(gItemDescGenIndexRegions[0][cnt].sTop), + (INT16)(gItemDescGenIndexRegions[0][cnt].sRight), + (INT16)(gItemDescGenIndexRegions[0][cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBGenIndexTooltipText[ cnt ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - // AIM BONUS - if ( GetFlatAimBonus( gpItemDescObject ) != 0 ) + iFirstDataRegion = iRegionsCreated; + CHAR16 pStr[1000]; + + ///////////////// PRIMARY DATA - ICONS + for (cnt = 0; cnt < 3; cnt++) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenRegions[cnt][0].sLeft), + (INT16)(gItemDescGenRegions[cnt][0].sTop), + (INT16)(gItemDescGenRegions[cnt][0].sRight), + (INT16)(gItemDescGenRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + swprintf( pStr, L"%s%s", szUDBGenArmorStatsTooltipText[ cnt ], szUDBGenArmorStatsExplanationsTooltipText[ cnt ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), pStr ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; } - // WOODLAND CAMO - if ( GetCamoBonus( gpItemDescObject ) > 0 ) + //////////////////// PROTECTION { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 0 ] ); } - // URBAN CAMO - if ( GetUrbanCamoBonus( gpItemDescObject ) > 0 ) + //////////////////// COVERAGE { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 1 ] ); } - // DESERT CAMO - if ( GetDesertCamoBonus( gpItemDescObject ) > 0 ) + //////////////////// DEGRADE RATE { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - } - - // SNOW CAMO - if ( GetSnowCamoBonus( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - } - - // STEALTH - if ( GetStealthBonus( gpItemDescObject ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 9 ] ); - } - - // VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 10 ] ); - } - - // DAY VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 1 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 11 ] ); - } - - // NIGHT VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 12 ] ); - } - - // BRIGHT LIGHT VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 13 ] ); - } - - // CAVE VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 14 ] ); - } - - // PERCENT TUNNEL VISION - if ( GetItemPercentTunnelVision( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 15 ] ); - } - - // HEARING RANGE BONUS - if ( GetItemHearingRangeBonus( gpItemDescObject ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 16 ] ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); } } + } - ////////////////////////////////////// - // Begin Explosive Item Tooltips Section - else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_EXPLOSV ) + else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_AMMO ) + { + if (gubDescBoxPage == 1) { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) + /////////////////// HEADERS + for (cnt = 0; cnt < 2; cnt++) { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gExplosiveDescStatsRects[ cnt ]. iLeft), - (INT16)(gExplosiveDescStatsRects[ cnt ].iTop), - (INT16)(gExplosiveDescStatsRects[ cnt ].iRight), - (INT16)(gExplosiveDescStatsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + /////////////////// HEADER #1: Primary Properties + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenHeaderRegions[cnt].sLeft), + (INT16)(gItemDescGenHeaderRegions[cnt].sTop), + (INT16)(gItemDescGenHeaderRegions[cnt].sRight), + (INT16)(gItemDescGenHeaderRegions[cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzExplosiveStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBHeaderTooltipText[ cnt ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - // DAMAGE - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage > 0 ) + ////////////////// INDEX + for (cnt = 0; cnt < 4; cnt++) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenIndexRegions[0][cnt].sLeft), + (INT16)(gItemDescGenIndexRegions[0][cnt].sTop), + (INT16)(gItemDescGenIndexRegions[0][cnt].sRight), + (INT16)(gItemDescGenIndexRegions[0][cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBGenIndexTooltipText[ cnt ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - // STUN DAMAGE - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage > 0 ) + iFirstDataRegion = iRegionsCreated; + CHAR16 pStr[1000]; + + ///////////////// PRIMARY DATA - ICONS + for (cnt = 0; cnt < 3; cnt++) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenRegions[cnt][0].sLeft), + (INT16)(gItemDescGenRegions[cnt][0].sTop), + (INT16)(gItemDescGenRegions[cnt][0].sRight), + (INT16)(gItemDescGenRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + swprintf( pStr, L"%s%s", szUDBGenAmmoStatsTooltipText[ cnt ], szUDBGenAmmoStatsExplanationsTooltipText[ cnt ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), pStr ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; + } + + //////////////////// ARMOR PIERCING + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 0 ] ); + } + + //////////////////// TUMBLE + { + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 1 ] ); } - // LOUDNESS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - // VOLATILITY - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility > 0 ) + //////////////////// PRE-ARMOR EXPLOSION { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); - } - - // SINGLE-EVENT EXPLOSION data - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 ) - { - // RADIUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); - - } - // PROLONGED EXPLOSION data - else if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) - { - - // DURATION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - - // STARTING RADIUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - - // FINAL RADIUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); - } - } - - ////////////////////////////////////////////////////////// - // The following is more complex - it sets up tooltip regions based not on predetermined order but on how much data there is on the chart. - // It begins with defining all regions, then goes on to set the helptext of each one based on each value encountered in the item's stats. - // At the very end, it enables as many tooltips as values encountered. - - else - { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gMiscItemDescStatsRects[ cnt ]. iLeft), - (INT16)(gMiscItemDescStatsRects[ cnt ].iTop), - (INT16)(gMiscItemDescStatsRects[ cnt ].iRight), - (INT16)(gMiscItemDescStatsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); - } - - cnt=0; - - // ITEM SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].itemsizebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 0 ] ); - cnt++; - } - - // RELIABILITY MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 1 ] ); - cnt++; - } - - // NOISE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 2 ] ); - cnt++; - } - - // HIDE MUZZLE FLASH ICON - if ( Item[ gpItemDescObject->usItem ].hidemuzzleflash > 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 3 ] ); - cnt++; - } - - // BIPOD ICON - if ( Item[ gpItemDescObject->usItem ].bipod != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 4 ] ); - cnt++; - } - - // RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 5 ] ); - cnt++; - } - - // TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 6 ] ); - cnt++; - } - - // LASER RANGE - if ( Item[ gpItemDescObject->usItem ].bestlaserrange > 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 7 ] ); - cnt++; - } - - // AIMING MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].aimbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 8 ] ); - cnt++; - } - - // MINIMUM RANGE FOR AIMING BONUS ICON - if ( Item[ gpItemDescObject->usItem ].minrangeforaimbonus > 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 33 ] ); - cnt++; - } - - // MAGAZINE SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].magsizebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 17 ] ); - cnt++; - } - - // BURST SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].burstsizebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 9 ] ); - cnt++; - } - - // BURST TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 10 ] ); - cnt++; - } - - // AUTO TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 11 ] ); - cnt++; - } - - // AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].APBonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 12 ] ); - cnt++; - } - - // BURST AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentburstfireapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 13 ] ); - cnt++; - } - - // AUTOFIRE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentautofireapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 14 ] ); - cnt++; - } - - // READY AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreadytimeapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 15 ] ); - cnt++; - } - - // RELOAD AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreloadtimeapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 16 ] ); - cnt++; - } - - // SINGLE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 18 ] ); - cnt++; - } - - // DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 19 ] ); - cnt++; - } - - // MELEE DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].meleedamagebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 20 ] ); - cnt++; - } - - // WOOD CAMO ICON - if ( Item[ gpItemDescObject->usItem ].camobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 21 ] ); - cnt++; - } - - // URBAN CAMO ICON - if ( Item[ gpItemDescObject->usItem ].urbanCamobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 22 ] ); - cnt++; - } - - // DESERT CAMO ICON - if ( Item[ gpItemDescObject->usItem ].desertCamobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 23 ] ); - cnt++; - } - - // SNOW CAMO ICON - if ( Item[ gpItemDescObject->usItem ].snowCamobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 24 ] ); - cnt++; - } - - // STEALTH MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].stealthbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 25 ] ); - cnt++; - } - - // HEARING RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].hearingrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 26 ] ); - cnt++; - } - - // VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].visionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 27 ] ); - cnt++; - } - - // DAY VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].dayvisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 28 ] ); - cnt++; - } - - // NIGHT VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].nightvisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 29 ] ); - cnt++; - } - - // BRIGHT LIGHT VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 30 ] ); - cnt++; - } - - // CAVE VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].cavevisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 31 ] ); - cnt++; - } - - // PERCENT TUNNEL VISION MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percenttunnelvision != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 32 ] ); - cnt++; - } - - UINT8 cntval = cnt; - - // Enable as many regions as required - for ( cnt = 0; cntusItem ].usItemClass & IC_EXPLOSV ) { - /////////////////////////////////////////// - // Begin Weapon Item Tooltip Regions - - if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON || Item[ gpItemDescObject->usItem ].usItemClass & IC_PUNCH ) + if (gubDescBoxPage == 1) { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gWeaponDescStatsRects[ cnt ].iLeft + gsInvDescX), - (INT16)(gWeaponDescStatsRects[ cnt ].iTop + gsInvDescY), - (INT16)(gWeaponDescStatsRects[ cnt ].iRight + gsInvDescX), - (INT16)(gWeaponDescStatsRects[ cnt ].iBottom + gsInvDescY), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + /////////////////// HEADERS - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzWeaponStatsFasthelpTactical[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); + for (cnt = 0; cnt < 2; cnt++) + { + /////////////////// HEADER #1: Primary Properties + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenHeaderRegions[cnt].sLeft), + (INT16)(gItemDescGenHeaderRegions[cnt].sTop), + (INT16)(gItemDescGenHeaderRegions[cnt].sRight), + (INT16)(gItemDescGenHeaderRegions[cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBHeaderTooltipText[ cnt ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - - // Enable regions one-by-one as necessary + + ////////////////// INDEX + for (cnt = 0; cnt < 4; cnt++) + { + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenIndexRegions[0][cnt].sLeft), + (INT16)(gItemDescGenIndexRegions[0][cnt].sTop), + (INT16)(gItemDescGenIndexRegions[0][cnt].sRight), + (INT16)(gItemDescGenIndexRegions[0][cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - // Relevant to all weapons - - // RELIABILITY - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - - // REPAIR EASE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); - - ////////////////////////////////// - // BEGIN SINGLE ATTACK SEGMENT - - // Non-Launcher Guns and Grenade-Launchers only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER|IC_PUNCH) && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - - // SINGLE-SHOT AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - - if ( Weapon[gpItemDescObject->usItem].NoSemiAuto ) - { - // "NO SINGLE-SHOT" - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelpTactical[ 23 ] ); - } + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBGenIndexTooltipText[ cnt ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + + iRegionsCreated++; } - // Rocket-Launchers Only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && Item[gpItemDescObject->usItem].rocketlauncher ) + iFirstDataRegion = iRegionsCreated; + CHAR16 pStr[1000]; + + ///////////////// PRIMARY DATA - ICONS + for (cnt = 0; cnt < 7; cnt++) { - // SINGLE ROCKET-LAUNCH AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelpTactical[ 21 ] ); + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenRegions[cnt][0].sLeft), + (INT16)(gItemDescGenRegions[cnt][0].sTop), + (INT16)(gItemDescGenRegions[cnt][0].sRight), + (INT16)(gItemDescGenRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; } - // Throwing-Knives Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_THROWING_KNIFE ) - { - // THROW KNIFE AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelpTactical[ 20 ] ); - } - - // Blades Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_BLADE ) - { - // SLASH AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelpTactical[ 22 ] ); - } - - // Blunts Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_PUNCH ) - { - // SLASH AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 8 ]), gzWeaponStatsFasthelpTactical[ 26 ] ); - } - - // END SINGLE ATTACK SEGMENT - //////////////////////////////////// - - //////////////////////////////////// - // BEGIN BURST ATTACK SEGMENT - - // Non-Launcher Guns and Grenade-Launchers only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - // BURST - MSYS_EnableRegion( &gStatsFasthelpRegions[ 9 ] ); - - if (GetShotsPerBurst(gpItemDescObject) <= 0 ) - { - // "NO BURST" - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 9 ]), gzWeaponStatsFasthelpTactical[ 24 ] ); - } - } - - // END BURST ATTACK SEGMENT - //////////////////////////////////// - - //////////////////////////////////// - // BEGIN AUTO ATTACK SEGMENT - - // Non-Launcher Guns Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 10 ] ); - - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) <= 0 ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 10 ]), gzWeaponStatsFasthelpTactical[ 25 ] ); - } - } - - // END AUTO ATTACK SEGMENT - /////////////////////////////////// - - // Guns, Throwing knives and Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) - { - // RANGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); - } - - // Guns and Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) - { - // ACCURACY - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); - } - - // Guns and Multi-use Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // RELOAD AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 11 ] ); - - if ( Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) - { - // RELOAD MANUALLY AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 12 ] ); - } - } - - // Guns and Grenade Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_PUNCH) && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - // DRAW AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - } - - // Non-Launcher Guns, Blades, and Throwing Knives only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_BLADE|IC_PUNCH|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // DAMAGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); - } - - // Non-Launcher Guns Only - if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 || GetShotsPerBurst(gpItemDescObject)> 0 ) - { - // BURST PENALTY - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - if ( GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 && GetShotsPerBurst(gpItemDescObject) <= 0 ) - { - // Change help text to "Autofire Penalty" (no burst) - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 2 ]), gzWeaponStatsFasthelp[ 27 ] ); - } - if ( GetShotsPerBurst(gpItemDescObject) > 0 && GetAutofireShotsPerFiveAPs(gpItemDescObject) <= 0 ) - { - // Change help text to "Burst Penalty" (no autofire) - SetRegionFastHelpText( &(gStatsFasthelpRegions[ 2 ]), gzWeaponStatsFasthelp[ 28 ] ); - } - } - - if ( GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) - { - // AUTOFIRE SHOTS PER 5 AP - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); - } - } - - ////////////////////////////////////////////////////////////////////// - // Begin non-type-specific icons. These are not type specific because they represent bonuses - // which may one day be added to various types of weapons by modders... - - if (Weapon[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubAttackVolume > 0 ) - { - // NOISE REDUCTION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 18 ] ); //14 - } - - if (IsFlashSuppressorAlt( gpItemDescObject ) == TRUE) - { - // HIDE FLASH - MSYS_EnableRegion( &gStatsFasthelpRegions[ 17 ] ); //13 - } - - if (GetFlatToHitBonus( gpItemDescObject ) != 0) - { - // HIT BONUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 13 ] ); //15 - - if (GetFlatToHitBonus( gpItemDescObject ) > 0 && GetAverageBestLaserRange( gpItemDescObject ) / 10 > 0 ) - { - // LASER RANGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 14 ] ); //16 - } - } - - if (GetBipodBonus( gpItemDescObject ) != 0) - { - // BIPOD BONUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 19 ] ); - } - - if (IsScoped( gpItemDescObject )) - { - // SCOPE AIM BONUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 15 ] ); //17 - if (GetMinRangeForAimBonus( gpItemDescObject ) / 10 > 0 ) - { - // LASER RANGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 16 ] ); //18 - } - } - - } - - /////////////////////////////////////////////////// - // Begin Ammo Item Tooltip Section - - else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_AMMO ) - { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gAmmoDescStatsRects[ cnt ]. iLeft + gsInvDescX), - (INT16)(gAmmoDescStatsRects[ cnt ].iTop + gsInvDescY), - (INT16)(gAmmoDescStatsRects[ cnt ].iRight + gsInvDescX), - (INT16)(gAmmoDescStatsRects[ cnt ].iBottom + gsInvDescY), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzAmmoStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); - } - - // AMMO PENETRATION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); - - // AMMO TUMBLE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); - - // AMMO PRE-IMPACT EXPLOSION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - // TRACER - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].tracerEffect ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); - } - - // ANTI-TANK - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].antiTank ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); - } - - // LOCKBUSTER - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].lockBustingPower ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - } - - // IGNORE ARMOR - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].ignoreArmour ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); - } - - // ACIDIC ICON - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].acidic ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - } - - // RANGE BONUS - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - } - - // DAMAGE BONUS - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 9 ] ); - } - - // TO HIT BONUS - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 10 ] ); - } - - // AUTO BONUS - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 11 ] ); - } - - // BURST BONUS - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 12 ] ); - } - - // RELIABILITY BONUS - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 13 ] ); - } - - // NOISE SUPPRESSION - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 14 ] ); - } - } - - /////////////////////////////////////////////////// - // Begin Armor Item Tooltip Section - - else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_ARMOUR ) - { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gArmorDescStatsRects[ cnt ]. iLeft + gsInvDescX), - (INT16)(gArmorDescStatsRects[ cnt ].iTop + gsInvDescY), - (INT16)(gArmorDescStatsRects[ cnt ].iRight + gsInvDescX), - (INT16)(gArmorDescStatsRects[ cnt ].iBottom + gsInvDescY), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzArmorStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); - } - - // PROTECTION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); - - // COVERAGE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); - - // ARMOR DEGRADE - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - - // AP BONUS - if ( GetAPBonus ( gpItemDescObject ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); - } - - // AIM BONUS - if ( GetFlatAimBonus( gpItemDescObject ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); - } - - // WOODLAND CAMO - if ( GetCamoBonus( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - } - - // URBAN CAMO - if ( GetUrbanCamoBonus( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); - } - - // DESERT CAMO - if ( GetDesertCamoBonus( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - } - - // SNOW CAMO - if ( GetSnowCamoBonus( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 8 ] ); - } - - // STEALTH - if ( GetStealthBonus( gpItemDescObject ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 9 ] ); - } - - // VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 10 ] ); - } - - // DAY VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 1 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 11 ] ); - } - - // NIGHT VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 12 ] ); - } - - // BRIGHT LIGHT VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 13 ] ); - } - - // CAVE VISION RANGE BONUS - if ( GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 14 ] ); - } - - // PERCENT TUNNEL VISION - if ( GetItemPercentTunnelVision( gpItemDescObject ) > 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 15 ] ); - } - - // HEARING RANGE BONUS - if ( GetItemHearingRangeBonus( gpItemDescObject ) != 0 ) - { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 16 ] ); - } - } - - ////////////////////////////////////// - // Begin Explosive Item Tooltips Section - else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_EXPLOSV ) - { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) - { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gExplosiveDescStatsRects[ cnt ]. iLeft + gsInvDescX), - (INT16)(gExplosiveDescStatsRects[ cnt ].iTop + gsInvDescY), - (INT16)(gExplosiveDescStatsRects[ cnt ].iRight + gsInvDescX), - (INT16)(gExplosiveDescStatsRects[ cnt ].iBottom + gsInvDescY), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzExplosiveStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); - } - - // DAMAGE + //////////////////// DAMAGE if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage > 0 ) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 0 ] ); + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 0 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 0 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 0 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 0 ] ); } - // STUN DAMAGE + //////////////////// STUN-DAMAGE if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage > 0 ) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 1 ] ); + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 1 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 1 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 1 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 1 ] ); } - - // LOUDNESS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 2 ] ); - // VOLATILITY + //////////////////// BLAST RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType != 5 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType != 1 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 2 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 2 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// STUN BLAST RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 1 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 3 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 3 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// NOISE BLAST RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 5 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 4 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 4 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// TEARGAS START RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 2 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 5 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 5 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// MUSTARD GAS START RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 3 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 6 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 6 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// LIGHT START RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 4 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 7 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 7 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// SMOKE START RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 6 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 8 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 8 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// INCENDIARY START RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 8 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 9 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 9 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 2 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 2 ] ); + } + + //////////////////// TEARGAS END RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 2 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 10 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 10 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 3 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] ); + } + + //////////////////// MUSTARD GAS END RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 3 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 11 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 11 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 3 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] ); + } + + //////////////////// LIGHT END RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 4 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 12 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 12 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 3 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] ); + } + + //////////////////// SMOKE END RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 6 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 13 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 13 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 3 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] ); + } + + //////////////////// NAPALM END RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 8 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 14 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 14 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 3 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] ); + } + + //////////////////// DURATION + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 15 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 15 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 4 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 4 ] ); + } + + //////////////////// LOUDNESS + { + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 16 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 16 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 5 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 5 ] ); + } + + //////////////////// VOLATILITY if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility > 0 ) { - MSYS_EnableRegion( &gStatsFasthelpRegions[ 3 ] ); + swprintf( pStr, L"%s%s", szUDBGenExplosiveStatsTooltipText[ 17 ], szUDBGenExplosiveStatsExplanationsTooltipText[ 17 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + 6 ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 6 ] ); } + } + } + + /////////////////////////////////////////////////////////////////////////////// + // SECONDARY PROPERTIES TOOLTIPS + // These are item-flags, shown as large icons on the right hand column of the General + // UDB page. They appear only for non-weapon items (no room in the weapon page). - // SINGLE-EVENT EXPLOSION data - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 ) + if (gubDescBoxPage == 1 && + !(Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON || Item[ gpItemDescObject->usItem ].usItemClass & IC_PUNCH ) ) + { + iFirstDataRegion = iRegionsCreated; + CHAR16 pStr[1000]; + + for (cnt = 0; cnt < 26; cnt++) + { + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescGenSecondaryRegions[cnt].sLeft), + (INT16)(gItemDescGenSecondaryRegions[cnt].sTop), + (INT16)(gItemDescGenSecondaryRegions[cnt].sRight), + (INT16)(gItemDescGenSecondaryRegions[cnt].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; + } + + cnt = 0; + + if (Item[ gpItemDescObject->usItem ].usItemClass & IC_ARMOUR) + { + //////////////////// EXPLOSIVE RESISTANCE + if (Item[ gpItemDescObject->usItem ].flakjacket) { - // RADIUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 4 ] ); - - } - // PROLONGED EXPLOSION data - else if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) - { - - // DURATION - MSYS_EnableRegion( &gStatsFasthelpRegions[ 7 ] ); - - // STARTING RADIUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 5 ] ); - - // FINAL RADIUS - MSYS_EnableRegion( &gStatsFasthelpRegions[ 6 ] ); + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 5 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 5 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; } } - ////////////////////////////////////////////////////////// - // The following is more complex - it sets up tooltip regions based not on predetermined order but on how much data there is on the chart. - // It begins with defining all regions, then goes on to set the helptext of each one based on each value encountered in the item's stats. - // At the very end, it enables as many tooltips as values encountered. - - else + if (Item[ gpItemDescObject->usItem ].usItemClass & IC_AMMO) { - // Create all regions - for (cnt = 0; cnt < 20; cnt++) + /////////////////// TRACER AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].tracerEffect ) { - MSYS_DefineRegion( &gStatsFasthelpRegions[ cnt ], - (INT16)(gMiscItemDescStatsRects[ cnt ].iLeft + gsInvDescX), - (INT16)(gMiscItemDescStatsRects[ cnt ].iTop + gsInvDescY), - (INT16)(gMiscItemDescStatsRects[ cnt ].iRight + gsInvDescX), - (INT16)(gMiscItemDescStatsRects[ cnt ].iBottom + gsInvDescY), + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 0 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 0 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + /////////////////// ANTI-TANK AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].antiTank ) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 1 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 1 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + /////////////////// IGNORE ARMOR AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].ignoreArmour ) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 2 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 2 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + /////////////////// ACIDIC AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].acidic ) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 3 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 3 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + /////////////////// LOCKBUSTING AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].lockBustingPower ) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 4 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 4 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + } + + if (Item[ gpItemDescObject->usItem ].usItemClass & IC_EXPLOSV) + { + ////////////////// LOCK BOMB + if (Item[ gpItemDescObject->usItem ].lockbomb) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 25 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 25 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + } + + ///////////////////////////////////////////////// + // Draw stats that can be had by any item. + + //////////////////// WATERPROOF + if (!Item[ gpItemDescObject->usItem ].waterdamages) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 6 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 6 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// ELECTRONIC + if (Item[ gpItemDescObject->usItem ].electronic) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 7 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 7 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// GAS MASK + if (Item[ gpItemDescObject->usItem ].gasmask) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 8 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 8 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// NEEDS BATTERIES + if (Item[ gpItemDescObject->usItem ].needsbatteries) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 9 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 9 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// LOCKSMITH'S KIT + if (Item[ gpItemDescObject->usItem ].locksmithkit) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 10 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 10 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// WIRE CUTTERS + if (Item[ gpItemDescObject->usItem ].wirecutters) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 11 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 11 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// CROWBAR + if (Item[ gpItemDescObject->usItem ].crowbar) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 12 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 12 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// CROWBAR + if (Item[ gpItemDescObject->usItem ].metaldetector) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 13 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 13 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// REMOTE TRIGGER + if (Item[ gpItemDescObject->usItem ].remotetrigger) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 14 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 14 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// REMOTE DETONATOR + if (Item[ gpItemDescObject->usItem ].remotedetonator) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 15 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 15 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// TIMER DETONATOR + if (Item[ gpItemDescObject->usItem ].detonator) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 16 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 16 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// GAS CAN + if (Item[ gpItemDescObject->usItem ].gascan) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 17 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 17 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// TOOLKIT + if (Item[ gpItemDescObject->usItem ].toolkit) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 18 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 18 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// THERMAL OPTICS + if (Item[ gpItemDescObject->usItem ].thermaloptics) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 19 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 19 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// X-RAY DEVICE + if (Item[ gpItemDescObject->usItem ].xray) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 20 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 20 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// CANTEEN + if (Item[ gpItemDescObject->usItem ].canteen) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 21 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 21 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// ALCOHOL + if (Item[ gpItemDescObject->usItem ].alcohol) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 22 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 22 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// FIRST-AID KIT + if (Item[ gpItemDescObject->usItem ].firstaidkit) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 23 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 23 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + + //////////////////// MEDICAL KIT + if (Item[ gpItemDescObject->usItem ].medicalkit) + { + swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 24 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 24 ]); + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] ); + cnt++; + } + } + + ////////////////////////////////////////////////////// + // ADVANCED PROPERTY TOOLTIPS + + if (gubDescBoxPage == 2) + { + INT16 sFirstLine = gubDescBoxLine; + INT16 sLastLine = gubDescBoxLine + NUM_UDB_ADV_LINES; + INT16 cnt = 0; + INT16 sOffsetX = 0; + INT16 sOffsetY = 0; + + //////////////////// INDEX + + for (cnt = 0; cnt < 4; cnt++) + { + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescAdvIndexRegions[0][cnt].sLeft), + (INT16)(gItemDescAdvIndexRegions[0][cnt].sTop), + (INT16)(gItemDescAdvIndexRegions[0][cnt].sRight), + (INT16)(gItemDescAdvIndexRegions[0][cnt].sBottom), MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - MSYS_AddRegion( &gStatsFasthelpRegions[ cnt ]); - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ cnt ] ); - SetRegionHelpEndCallback( &(gStatsFasthelpRegions[ cnt ]), HelpTextDoneCallback ); - MSYS_DisableRegion( &gStatsFasthelpRegions[ cnt ] ); - } - - cnt=0; - - // ITEM SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].itemsizebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 0 ] ); - cnt++; - } - - // RELIABILITY MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 1 ] ); - cnt++; - } - - // NOISE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 2 ] ); - cnt++; - } - - // HIDE MUZZLE FLASH ICON - if ( Item[ gpItemDescObject->usItem ].hidemuzzleflash > 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 3 ] ); - cnt++; - } - - // BIPOD ICON - if ( Item[ gpItemDescObject->usItem ].bipod != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 4 ] ); - cnt++; - } - - // RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 5 ] ); - cnt++; - } - - // TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 6 ] ); - cnt++; - } - - // LASER RANGE - if ( Item[ gpItemDescObject->usItem ].bestlaserrange > 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 7 ] ); - cnt++; - } - - // AIMING MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].aimbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 8 ] ); - cnt++; - } - - // MINIMUM RANGE FOR AIMING BONUS ICON - if ( Item[ gpItemDescObject->usItem ].minrangeforaimbonus > 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 33 ] ); - cnt++; - } - - // MAGAZINE SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].magsizebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 17 ] ); - cnt++; - } - - // BURST SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].burstsizebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 9 ] ); - cnt++; - } - - // BURST TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 10 ] ); - cnt++; - } - - // AUTO TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 11 ] ); - cnt++; - } - - // AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].APBonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 12 ] ); - cnt++; - } - - // BURST AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentburstfireapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 13 ] ); - cnt++; - } - - // AUTOFIRE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentautofireapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 14 ] ); - cnt++; - } - - // READY AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreadytimeapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 15 ] ); - cnt++; - } - - // RELOAD AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreloadtimeapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 16 ] ); - cnt++; - } - - // SINGLE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentapreduction != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 18 ] ); - cnt++; - } - - // DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 19 ] ); - cnt++; - } - - // MELEE DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].meleedamagebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 20 ] ); - cnt++; - } - - // WOOD CAMO ICON - if ( Item[ gpItemDescObject->usItem ].camobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 21 ] ); - cnt++; - } - - // URBAN CAMO ICON - if ( Item[ gpItemDescObject->usItem ].urbanCamobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 22 ] ); - cnt++; - } - - // DESERT CAMO ICON - if ( Item[ gpItemDescObject->usItem ].desertCamobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 23 ] ); - cnt++; - } - - // SNOW CAMO ICON - if ( Item[ gpItemDescObject->usItem ].snowCamobonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 24 ] ); - cnt++; - } - - // STEALTH MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].stealthbonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 25 ] ); - cnt++; - } - - // HEARING RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].hearingrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 26 ] ); - cnt++; - } - - // VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].visionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 27 ] ); - cnt++; - } - - // DAY VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].dayvisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 28 ] ); - cnt++; - } - - // NIGHT VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].nightvisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 29 ] ); - cnt++; - } - - // BRIGHT LIGHT VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 30 ] ); - cnt++; - } - - // CAVE VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].cavevisionrangebonus != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 31 ] ); - cnt++; - } - - // PERCENT TUNNEL VISION MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percenttunnelvision != 0 && cnt<=threshold ) - { - SetRegionFastHelpText( &(gStatsFasthelpRegions[ cnt ]), gzMiscItemStatsFasthelp[ 32 ] ); - cnt++; - } - - UINT8 cntval = cnt; - - // Enable as many regions as required - for ( cnt = 0; cnt 0 ) + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iRegionsCreated ]), gzUDBAdvIndexTooltipText[ 4 ] ); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + iRegionsCreated++; } + + /////////////////// DATA + + iFirstDataRegion = iRegionsCreated; + CHAR16 pStr[1000]; + + for (cnt = 0; cnt < NUM_UDB_ADV_LINES; cnt++) + { + MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ], + (INT16)(gItemDescAdvRegions[cnt][0].sLeft), + (INT16)(gItemDescAdvRegions[cnt][0].sTop), + (INT16)(gItemDescAdvRegions[cnt][0].sRight), + (INT16)(gItemDescAdvRegions[cnt][0].sBottom), + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gUDBFasthelpRegions[ iRegionsCreated ]); + SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iRegionsCreated ]), HelpTextDoneCallback ); + MSYS_DisableRegion( &gUDBFasthelpRegions[ iRegionsCreated ] ); + + iRegionsCreated++; + } + + cnt = 0; + + ///////////////////// ACCURACY MODIFIER + if (GetAccuracyModifier( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == true ) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 0 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 0 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 0 ], szUDBAdvStatsExplanationsTooltipText[ 0 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + ///////////////////// FLAT BASE MODIFIER + if (GetFlatBaseModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetFlatBaseModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetFlatBaseModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass& (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 1 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 1 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 1 ], szUDBAdvStatsExplanationsTooltipText[ 1 ]); + } + } + cnt++; + } + } + + ///////////////////// PERCENT BASE MODIFIER + if (GetPercentBaseModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentBaseModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentBaseModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 2 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 2 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 2 ], szUDBAdvStatsExplanationsTooltipText[ 2 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// FLAT AIM MODIFIER + if (GetFlatAimModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetFlatAimModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetFlatAimModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 3 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 3 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 3 ], szUDBAdvStatsExplanationsTooltipText[ 3 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// PERCENT AIM MODIFIER + if (GetPercentAimModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentAimModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentAimModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 4 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 4 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 4 ], szUDBAdvStatsExplanationsTooltipText[ 4 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// AIMING LEVELS MODIFIER + if (GetAimLevelsModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetAimLevelsModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetAimLevelsModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 5 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 5 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 5 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 5 ], szUDBAdvStatsExplanationsTooltipText[ 5 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// CTH CAP MODIFIER + if (GetPercentCapModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentCapModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentCapModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 6 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 6 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 6 ], szUDBAdvStatsExplanationsTooltipText[ 6 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// GUN HANDLING MODIFIER + if (GetPercentHandlingModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentHandlingModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentHandlingModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 7 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 7 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 7 ], szUDBAdvStatsExplanationsTooltipText[ 7 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// DROP COMPENSATION MODIFIER + if (GetDropCompensationModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetDropCompensationModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetDropCompensationModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 8 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 8 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 8 ], szUDBAdvStatsExplanationsTooltipText[ 8 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// TARGET TRACKING MODIFIER + if (GetTargetTrackingModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetTargetTrackingModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetTargetTrackingModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 9 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 9 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 9 ], szUDBAdvStatsExplanationsTooltipText[ 9 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// DAMAGE MODIFIER + if (GetDamageBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 10 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 10 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 10 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 10 ], szUDBAdvStatsExplanationsTooltipText[ 10 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// MELEE DAMAGE MODIFIER + if (GetMeleeDamageBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 11 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 11 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 11 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 11 ], szUDBAdvStatsExplanationsTooltipText[ 11 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// RANGE MODIFIER + if (GetRangeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 12 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 12 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 12 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 12 ], szUDBAdvStatsExplanationsTooltipText[ 12 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// SCOPE MAGNIFICATION + if (GetHighestScopeMagnificationFactor( gpItemDescObject ) > 1.0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 13 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 13 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 13 ], szUDBAdvStatsExplanationsTooltipText[ 13 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// PROJECTION FACTOR + if (GetProjectionFactor( gpItemDescObject ) > 1.0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 14 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 14 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 14 ], szUDBAdvStatsExplanationsTooltipText[ 14 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + INT8 bDummy; + INT8 bRecoilModifier; + GetFlatRecoilModifier( gpItemDescObject, &bRecoilModifier, &bDummy ); + ///////////////////// LATERAL RECOIL MODIFIER + if (bRecoilModifier != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 15 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 15 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 15 ], szUDBAdvStatsExplanationsTooltipText[ 15 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + GetFlatRecoilModifier( gpItemDescObject, &bDummy, &bRecoilModifier ); + ///////////////////// VERTICAL RECOIL MODIFIER + if (bRecoilModifier != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 16 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 16 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 16 ], szUDBAdvStatsExplanationsTooltipText[ 16 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// MAX COUNTER FORCE MODIFIER + if ((GetCounterForceMaxModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetCounterForceMaxModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetCounterForceMaxModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 17 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 17 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 17 ], szUDBAdvStatsExplanationsTooltipText[ 17 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// COUNTER FORCE ACCURACY MODIFIER + if (GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 18 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 18 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 18 ], szUDBAdvStatsExplanationsTooltipText[ 18 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// COUNTER FORCE FREQUENCY MODIFIER + if (GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 19 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 19 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 19 ], szUDBAdvStatsExplanationsTooltipText[ 19 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + } + + ///////////////////// AP MODIFIER + if (GetAPBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 20 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 20 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 20 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 20 ], szUDBAdvStatsExplanationsTooltipText[ 20 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// DRAW AP MODIFIER + if (GetPercentReadyTimeAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 21 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 21 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 21 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 21 ], szUDBAdvStatsExplanationsTooltipText[ 21 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// SINGLE-ATTACK AP MODIFIER + if (GetPercentAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 22 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 22 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 22 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 22 ], szUDBAdvStatsExplanationsTooltipText[ 22 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// BURST AP MODIFIER + if (GetPercentBurstFireAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 23 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 23 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 23 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 23 ], szUDBAdvStatsExplanationsTooltipText[ 23 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// AUTOFIRE AP MODIFIER + if (GetPercentAutofireAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 24 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 24 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 24 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 24 ], szUDBAdvStatsExplanationsTooltipText[ 24 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// RELOAD AP MODIFIER + if (GetPercentReloadTimeAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 25 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 25 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 25 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 25 ], szUDBAdvStatsExplanationsTooltipText[ 25 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// MAGAZINE SIZE MODIFIER + if (GetMagSizeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 26 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 26 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 26 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 26 ], szUDBAdvStatsExplanationsTooltipText[ 26 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// BURST SIZE MODIFIER + if (GetBurstSizeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 27 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 27 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 27 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 27 ], szUDBAdvStatsExplanationsTooltipText[ 27 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// HIDE MUZZLE FLASH + if (IsFlashSuppressorAlt( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 28 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 28 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 28 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 28 ], szUDBAdvStatsExplanationsTooltipText[ 28 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// LOUDNESS MODIFIER + if (GetPercentNoiseVolume( gpItemDescObject )-100 != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 29 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 29 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 29 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 29 ], szUDBAdvStatsExplanationsTooltipText[ 29 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// ALTER ITEM SIZE + if (CalculateItemSize( gpItemDescObject ) - Item[ gpItemDescObject->usItem ].ItemSize != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 30 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 30 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 30 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 30 ], szUDBAdvStatsExplanationsTooltipText[ 30 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// RELIABILITY MODIFIER + if (!(Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_PUNCH|IC_ARMOUR|IC_EXPLOSV)) && + GetReliability( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 31 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 31 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 31 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 31 ], szUDBAdvStatsExplanationsTooltipText[ 31 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// WOODLAND CAMO + if (GetCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 32 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 32 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 32 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 32 ], szUDBAdvStatsExplanationsTooltipText[ 32 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// URBAN CAMO + if (GetUrbanCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 33 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 33 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 33 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 33 ], szUDBAdvStatsExplanationsTooltipText[ 33 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// DESERT CAMO + if (GetDesertCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 34 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 34 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 34 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 34 ], szUDBAdvStatsExplanationsTooltipText[ 34 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// SNOW CAMO + if (GetSnowCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 35 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 35 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 35 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 35 ], szUDBAdvStatsExplanationsTooltipText[ 35 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// STEALTH MODIFIER + if (GetStealthBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 36 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 36 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 36 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 36 ], szUDBAdvStatsExplanationsTooltipText[ 36 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// HEARING RANGE MODIFIER + if (GetItemHearingRangeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 37 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 37 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 37 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 37 ], szUDBAdvStatsExplanationsTooltipText[ 37 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 38 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 38 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 38 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 38 ], szUDBAdvStatsExplanationsTooltipText[ 38 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// NIGHT VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 2 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 39 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 39 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 39 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 39 ], szUDBAdvStatsExplanationsTooltipText[ 39 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// DAY VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 1 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 40 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 40 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 40 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 40 ], szUDBAdvStatsExplanationsTooltipText[ 40 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// BRIGHT LIGHT VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 3 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 41 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 41 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 41 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 41 ], szUDBAdvStatsExplanationsTooltipText[ 41 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// CAVE VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 4 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 42 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 42 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 42 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 42 ], szUDBAdvStatsExplanationsTooltipText[ 42 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + ///////////////////// PERCENT TUNNEL VISION + if (GetItemPercentTunnelVision( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + if( UsingNewCTHSystem() == false ) + { + swprintf( pStr, L"%s", szUDBAdvStatsTooltipText[ 43 ]); + } + else if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 43 ], szUDBAdvStatsExplanationsTooltipTextForWeapons[ 43 ]); + } + else + { + swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 43 ], szUDBAdvStatsExplanationsTooltipText[ 43 ]); + } + SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr ); + MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] ); + } + cnt++; + } + + gubDescBoxTotalAdvLines = (UINT8)cnt; } } @@ -3533,25 +3259,19 @@ void DeleteEnhancedDescBox( UINT32 guiCurrentItemDescriptionScreen ) DeleteVideoObjectFromIndex( guiItemInfoAmmoIcon ); DeleteVideoObjectFromIndex( guiItemInfoArmorIcon ); DeleteVideoObjectFromIndex( guiItemInfoExplosiveIcon ); - DeleteVideoObjectFromIndex( guiItemInfoMiscIcon ); + // HEADROCK HAM 4: Delete new icons + DeleteVideoObjectFromIndex( guiItemInfoSecondaryIcon ); + DeleteVideoObjectFromIndex( guiItemInfoAdvancedIcon ); - if ( guiCurrentItemDescriptionScreen ==MAP_SCREEN && UsingEDBSystem() > 0 ) + if ( UsingEDBSystem() > 0 ) { - UINT16 RegionsToRemove = 20; - - for (cnt = 0; cnt < RegionsToRemove; cnt++) + // HEADROCK HAM 4: UDB fasthelp + for ( cnt = 0; cnt < NUM_UDB_FASTHELP_REGIONS; cnt++ ) { - MSYS_RemoveRegion( &gStatsFasthelpRegions[cnt] ); - } - } - - if ( guiCurrentItemDescriptionScreen !=MAP_SCREEN && UsingEDBSystem() > 0 ) - { - UINT16 RegionsToRemove = 20; - - for (cnt = 0; cnt < RegionsToRemove; cnt++) - { - MSYS_RemoveRegion( &gStatsFasthelpRegions[cnt] ); + if( gUDBFasthelpRegions[ cnt ].IDNumber != 0 ) + { + MSYS_RemoveRegion( &gUDBFasthelpRegions[ cnt ]); + } } } } @@ -3559,790 +3279,1188 @@ void DeleteEnhancedDescBox( UINT32 guiCurrentItemDescriptionScreen ) void DrawWeaponStats( OBJECTTYPE * gpItemDescObject ) { INT32 cnt; + INT16 sOffsetX = 2; + INT16 sOffsetY = 1; if( UsingEDBSystem() == 0 ) return; - // Start with icons relevant to all weapons - - // RELIABILITY ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 9, BULLET_RELIABILITY_X, BULLET_RELIABILITY_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // REPAIR EASE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 10, BULLET_REPAIR_X, BULLET_REPAIR_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - ////////////////////////////////// - // BEGIN SINGLE ATTACK SEGMENT - - // Non-Launcher Guns only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) + if (gubDescBoxPage == 1) { - // "NO SINGLE-SHOT" ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 19, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) + //////////////////// ACCURACY + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) { - // SINGLE SHOT AP ICON overwrites shadow - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 0, BULLET_SING_X+1, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 8, gItemDescGenRegions[0][0].sLeft+sOffsetX, gItemDescGenRegions[0][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } - } - // Rocket-Launchers Only - if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && Item[gpItemDescObject->usItem].rocketlauncher ) - { - // SINGLE ROCKET-LAUNCH AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 21, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // Grenade-Launchers Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_LAUNCHER && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) + //////////////////// DAMAGE + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_PUNCH|IC_BLADE|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) { - // SINGLE GRENADE-LAUNCH AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 24, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 5, gItemDescGenRegions[1][0].sLeft+sOffsetX, gItemDescGenRegions[1][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } - } - // Throwing-Knives Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_THROWING_KNIFE ) - { - // THROW KNIFE AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 22, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // Blades Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_BLADE ) - { - // SLASH AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 20, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // Blunts Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_PUNCH ) - { - // BASH AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 26, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // END SINGLE ATTACK SEGMENT - //////////////////////////////////// - - //////////////////////////////////// - // BEGIN BURST ATTACK SEGMENT - - // Non-Launcher Guns Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - // "NO BURST" ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 11, BULLET_BURST_X, BULLET_BURST_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - if (GetShotsPerBurst(gpItemDescObject)> 0) + //////////////////// RANGE + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) { - for ( cnt = 0; cnt < GetShotsPerBurst(gpItemDescObject); cnt++ ) + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 4, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// ALLOWED AIM LEVELS + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 33, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// SCOPE MAGNIFICATION + if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_GUN ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 15, gItemDescGenRegions[4][0].sLeft+sOffsetX, gItemDescGenRegions[4][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// PROJECTION FACTOR + if (GetProjectionFactor( gpItemDescObject ) > 1.0) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 14, gItemDescGenRegions[5][0].sLeft+sOffsetX, gItemDescGenRegions[5][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// FLASH SUPPRESSION + if (IsFlashSuppressorAlt( gpItemDescObject )) + { + // HIDE FLASH ICON + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 28, gItemDescGenRegions[6][0].sLeft+sOffsetX, gItemDescGenRegions[6][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// LOUDNESS + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 17, gItemDescGenRegions[7][0].sLeft+sOffsetX, gItemDescGenRegions[7][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// RELIABILITY + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 9, gItemDescGenRegions[8][0].sLeft+sOffsetX, gItemDescGenRegions[8][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// REPAIR EASE + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 10, gItemDescGenRegions[9][0].sLeft+sOffsetX, gItemDescGenRegions[9][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// MinRangeForAimBonus + if( UsingNewCTHSystem() == false ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 27, gItemDescGenRegions[10][0].sLeft+sOffsetX, gItemDescGenRegions[10][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// BestLaserRange + if( UsingNewCTHSystem() == false ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 13, gItemDescGenRegions[11][0].sLeft+sOffsetX, gItemDescGenRegions[11][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// DRAW COST + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem].rocketlauncher ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 1, gItemDescGenRegions[13][0].sLeft+sOffsetX, gItemDescGenRegions[13][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////////// SINGLE SHOT COST - GUN + if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) + { + // "NO SINGLE-SHOT" ICON + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 19, gItemDescGenRegions[14][0].sLeft+sOffsetX, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + + if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) { - // BURST FIRE ICON overwrites shadow - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 0, BULLET_BURST_X + cnt * (BULLET_WIDTH/2 + 1) +1, BULLET_BURST_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + // SINGLE SHOT AP ICON overwrites shadow + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 0, gItemDescGenRegions[14][0].sLeft+sOffsetX+1, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } } - } - // Grenade-Launchers Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_LAUNCHER && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - if (GetShotsPerBurst(gpItemDescObject)> 0) + /////////////////// SINGLE SHOT COST - ROCKET + if ( Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) && Item[gpItemDescObject->usItem].rocketlauncher ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 25, BULLET_BURST_X, BULLET_BURST_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + // SINGLE ROCKET-LAUNCH AP ICON + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 21, gItemDescGenRegions[14][0].sLeft+sOffsetX, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } - } - // END BURST ATTACK SEGMENT - //////////////////////////////////// - - //////////////////////////////////// - // BEGIN AUTO ATTACK SEGMENT - - // Non-Launcher Guns Only - if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) - { - // "NO-AUTO" ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 12, BULLET_AUTO_X, BULLET_AUTO_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) + /////////////////// SINGLE SHOT COST - GRENADE LAUNCHER + if ( Item[gpItemDescObject->usItem].usItemClass == IC_LAUNCHER && !Item[gpItemDescObject->usItem].rocketlauncher + && !Weapon[gpItemDescObject->usItem].NoSemiAuto ) { - for ( cnt = 0; cnt < 10; cnt++ ) + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 24, gItemDescGenRegions[14][0].sLeft+sOffsetX, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + /////////////////// SINGLE SHOT COST - THROWING KNIFE + if ( Item[gpItemDescObject->usItem].usItemClass == IC_THROWING_KNIFE ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 22, gItemDescGenRegions[14][0].sLeft+sOffsetX, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + /////////////////// SINGLE SHOT COST - STABBING KNIFE + if ( Item[gpItemDescObject->usItem].usItemClass == IC_BLADE ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 20, gItemDescGenRegions[14][0].sLeft+sOffsetX, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + /////////////////// SINGLE SHOT COST - BLUNT WEAPON + if ( Item[gpItemDescObject->usItem].usItemClass == IC_PUNCH ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 26, gItemDescGenRegions[14][0].sLeft+sOffsetX, gItemDescGenRegions[14][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + /////////////////// BURST COST - GUN + if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) + { + // "NO BURST" ICON + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 11, gItemDescGenRegions[15][0].sLeft+sOffsetX, gItemDescGenRegions[15][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + + if (GetShotsPerBurst(gpItemDescObject)> 0) { - // AUTO FIRE ICON overwrites shadow - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 0, BULLET_AUTO_X + cnt * (BULLET_WIDTH/2 + 1) +1, BULLET_AUTO_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + for ( cnt = 0; cnt < GetShotsPerBurst(gpItemDescObject); cnt++ ) + { + // BURST FIRE ICON overwrites shadow + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 0, gItemDescGenRegions[15][0].sLeft+sOffsetX + cnt * (BULLET_WIDTH/2 + 1) +1, gItemDescGenRegions[15][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } } } - } - // END AUTO ATTACK SEGMENT - /////////////////////////////////// + ////////////////// BURST COST - GRENADE LAUNCHER + if ( Item[gpItemDescObject->usItem].usItemClass == IC_LAUNCHER && !Item[gpItemDescObject->usItem].rocketlauncher + && GetShotsPerBurst(gpItemDescObject)> 0) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 25, gItemDescGenRegions[15][0].sLeft+sOffsetX, gItemDescGenRegions[15][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } - // Guns, Throwing knives and Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) - { - // RANGE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 4, BULLET_RANGE_X, BULLET_RANGE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } + ////////////////// AUTOFIRE COST + if ( Item[gpItemDescObject->usItem].usItemClass == IC_GUN && !Item[gpItemDescObject->usItem].rocketlauncher ) + { + // "NO-AUTO" ICON + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 12, gItemDescGenRegions[16][0].sLeft+sOffsetX, gItemDescGenRegions[16][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); - // Guns and Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) - { - // ACCURACY ICON (Always displayed for these items, even if accuracy is 0) - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 8, BULLET_ACC_X, BULLET_ACC_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) + { + for ( cnt = 0; cnt < 10; cnt++ ) + { + // AUTO FIRE ICON overwrites shadow + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 0, gItemDescGenRegions[16][0].sLeft+sOffsetX + cnt * (BULLET_WIDTH/2 + 1) +1, gItemDescGenRegions[16][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + } - // NOISE REDUCTION ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 17, BULLET_LOUDNESS_X, BULLET_LOUDNESS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // Guns and Multi-use Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // RELOAD AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 2, BULLET_RELOAD_X, BULLET_RELOAD_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + ////////////////// RELOAD COST + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 2, gItemDescGenRegions[17][0].sLeft+sOffsetX, gItemDescGenRegions[17][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } - if ( Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) + ////////////////// MANUAL RELOAD COST + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher + && Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) { - // AP to Reload Manually ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 3, BULLET_MRELOAD_X, BULLET_MRELOAD_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 3, gItemDescGenRegions[18][0].sLeft+sOffsetX, gItemDescGenRegions[18][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } - } - - // Guns and Grenade Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - // DRAW AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 1, BULLET_DRAW_X, BULLET_DRAW_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // Non-Launcher Guns, Blades, and Throwing Knives only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_PUNCH|IC_BLADE|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // DAMAGE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 5, BULLET_DAMAGE_X, BULLET_DAMAGE_Y-1, VO_BLT_SRCTRANSPARENCY, NULL ); - } - // Non-Launcher Guns Only - if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - if (GetShotsPerBurst(gpItemDescObject)> 0 && GetAutofireShotsPerFiveAPs(gpItemDescObject) <= 0 ) - // BURST PENALTY ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 30, BULLET_AUTOPEN_X, BULLET_AUTOPEN_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - else if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 && GetShotsPerBurst(gpItemDescObject) <= 0) - // AUTO PENALTY ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 6, BULLET_AUTOPEN_X, BULLET_AUTOPEN_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - else if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 && GetShotsPerBurst(gpItemDescObject) > 0 ) - // BURST/AUTO PENALTY ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 29, BULLET_AUTOPEN_X, BULLET_AUTOPEN_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 || GetShotsPerBurst(gpItemDescObject)> 0 ) + ///////////////// RECOIL X/Y + if( UsingNewCTHSystem() == true ) { - if ( Weapon[ gpItemDescObject->usItem ].bAutofireShotsPerFiveAP > 0 ) + if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher + && ( GetShotsPerBurst(gpItemDescObject)> 0 || GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) ) { - // AUTOFIRE SHOTS PER 5 AP ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 7, BULLET_AUTO5AP_X, BULLET_AUTO5AP_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 31, gItemDescGenRegions[19][0].sLeft+sOffsetX, gItemDescGenRegions[19][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 32, gItemDescGenRegions[20][0].sLeft+sOffsetX, gItemDescGenRegions[20][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + } + else ///////////////// BIPOD + { + if( GetBipodBonus(gpItemDescObject) > 0) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 16, gItemDescGenRegions[20][0].sLeft+sOffsetX, gItemDescGenRegions[20][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } } - - } - - ////////////////////////////////////////////////////////////////////// - // Begin non-type-specific icons. These are not type specific because they represent bonuses - // which may one day be added to various types of weapons by modders... - if (IsFlashSuppressorAlt( gpItemDescObject ) == TRUE) - { - UINT8 icon = 28; - if(guiCurrentScreen != MAP_SCREEN && UsingNewInventorySystem() == true) - icon = 18; - // HIDE FLASH ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, icon, BULLET_FLASH_X, BULLET_FLASH_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - if (GetFlatToHitBonus( gpItemDescObject ) != 0) - { - // HIT BONUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 13, BULLET_TOHIT_X, BULLET_TOHIT_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - if (GetFlatToHitBonus( gpItemDescObject ) > 0 && GetAverageBestLaserRange( gpItemDescObject ) / 10 > 0) + ///////////////// AUTOFIRE SHOTS PER 5 AP ICON + if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher + && GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) { - // LASER RANGE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 14, BULLET_BESTLASERRANGE_X, BULLET_BESTLASERRANGE_Y-1, VO_BLT_SRCTRANSPARENCY, NULL ); - } - } - - if (GetBipodBonus( gpItemDescObject ) != 0) - { - // BIPOD BONUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 16, BULLET_BIPOD_X, BULLET_BIPOD_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - if (IsScoped( gpItemDescObject )) - { - // SCOPE AIM BONUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 15, BULLET_AIMBONUS_X, BULLET_AIMBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - if (GetMinRangeForAimBonus( gpItemDescObject )) - { - // SCOPE MIN RANGE FOR AIM BONUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 27, BULLET_MINRANGEAIMBONUS_X, BULLET_MINRANGEAIMBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWeaponIcon, 7, gItemDescGenRegions[21][0].sLeft+sOffsetX, gItemDescGenRegions[21][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); } - } + } + else if(gubDescBoxPage == 2) + { + DrawAdvancedStats( gpItemDescObject ); + } } void DrawAmmoStats( OBJECTTYPE * gpItemDescObject ) { - // ARMOR PIERCING ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 0, BULLET_ARMORPEN_X, BULLET_ARMORPEN_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + INT16 sOffsetX = 2; + INT16 sOffsetY = 1; - // TUMBLE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 1, BULLET_TUMBLE_X, BULLET_TUMBLE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingEDBSystem() == 0 ) + return; - // PRE-ARMOR EXPLOSION ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 2, BULLET_PREARMOR_X, BULLET_PREARMOR_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - // ANTI-TANK ICON - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].antiTank ) + if (gubDescBoxPage == 1) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 3, BULLET_ANTITANK_X, BULLET_ANTITANK_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + //////////////// ARMOR PIERCING + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 0, gItemDescGenRegions[0][0].sLeft+sOffsetX, gItemDescGenRegions[0][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + //////////////// TUMBLING + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 1, gItemDescGenRegions[1][0].sLeft+sOffsetX, gItemDescGenRegions[1][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + //////////////// PRE-ARMOR EXPLOSION + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 2, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + DrawSecondaryStats( gpItemDescObject ); + } + else if (gubDescBoxPage == 2) + { + DrawAdvancedStats( gpItemDescObject ); } - // IGNORE ARMOR ICON - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].ignoreArmour ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 4, BULLET_IGNOREARMOR_X, BULLET_IGNOREARMOR_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // ACIDIC ICON - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].acidic ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 5, BULLET_ACIDIC_X, BULLET_ACIDIC_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // LOCKBUSTER ICON - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].lockBustingPower ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 6, BULLET_LOCKBUSTER_X, BULLET_LOCKBUSTER_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // TRACER - if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].tracerEffect ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 7, BULLET_TRACER_X, BULLET_TRACER_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // RANGE BONUS - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 8, BULLET_AMMORANGEBON_X, BULLET_AMMORANGEBON_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // DAMAGE BONUS - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 9, BULLET_AMMODAMAGEBON_X, BULLET_AMMODAMAGEBON_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // TO HIT BONUS - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 11, BULLET_AMMOTOHITBON_X, BULLET_AMMOTOHITBON_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // AUTO PENALTY BONUS - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus > 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 10, BULLET_AMMOAUTOBON_X, BULLET_AMMOAUTOBON_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - // BURST PENALTY BONUS - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus > 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 15, BULLET_AMMOBURSTBON_X, BULLET_AMMOBURSTBON_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // RELIABILITY BONUS - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 12, BULLET_AMMORELIABILITYBON_X, BULLET_AMMORELIABILITYBON_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // NOISE SUPPRESSION - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction > 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 13, BULLET_AMMONOISESUPP_X, BULLET_AMMONOISESUPP_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } } void DrawExplosiveStats( OBJECTTYPE * gpItemDescObject ) { + INT16 sOffsetX = 2; + INT16 sOffsetY = 1; + if( UsingEDBSystem() == 0 ) return; - // DAMAGE ICON - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage > 0 ) + if (gubDescBoxPage == 1) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 0, BULLET_EXPLOSIVEDAMAGE_X, BULLET_EXPLOSIVEDAMAGE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + ////////////////////// DAMAGE + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage > 0 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 0, gItemDescGenRegions[0][0].sLeft+sOffsetX, gItemDescGenRegions[0][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// STUN DAMAGE + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage > 0 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 1, gItemDescGenRegions[1][0].sLeft+sOffsetX, gItemDescGenRegions[1][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// SOUND BLAST + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 5 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 6, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// STUN BLAST + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 1 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 5, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// OTHER BLASTS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType != 1 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType != 5 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 4, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// START+END RADIUS: TEAR GAS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 2 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 9, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 10, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// START+END RADIUS: MUSTARD GAS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 3 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 13, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 14, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// START+END RADIUS: LIGHT + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 4 ) + { + // Note light is reversed (large to small) + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 18, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 17, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// START+END RADIUS: SMOKE + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 6 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 11, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 12, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// START+END RADIUS: NAPALM + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 + && Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 8 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 15, gItemDescGenRegions[2][0].sLeft+sOffsetX, gItemDescGenRegions[2][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 16, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// DURATION + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 7, gItemDescGenRegions[4][0].sLeft+sOffsetX, gItemDescGenRegions[4][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// LOUDNESS + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 2, gItemDescGenRegions[5][0].sLeft+sOffsetX, gItemDescGenRegions[5][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////////// VOLATILITY + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility > 0 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 3, gItemDescGenRegions[6][0].sLeft+sOffsetX, gItemDescGenRegions[6][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + DrawSecondaryStats( gpItemDescObject ); } - - // STUN DAMAGE ICON - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage > 0 ) + else if (gubDescBoxPage == 2) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 1, BULLET_EXPLOSIVESTUNDAMAGE_X, BULLET_EXPLOSIVESTUNDAMAGE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // LOUDNESS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 2, BULLET_EXPLOSIVELOUDNESS_X, BULLET_EXPLOSIVELOUDNESS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - // VOLATILITY ICON - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility > 0 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 3, BULLET_EXPLOSIVEVOLATILITY_X, BULLET_EXPLOSIVEVOLATILITY_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // SINGLE-EVENT EXPLOSION data - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 ) - { - // SOUND RADIUS ICON - if ( Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 5 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 6, BULLET_EXPLOSIVERADIUS_X, BULLET_EXPLOSIVERADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - else if ( Explosive[Item[ gpItemDescObject->usItem].ubClassIndex ].ubType == 1 ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 5, BULLET_EXPLOSIVERADIUS_X, BULLET_EXPLOSIVERADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - else - { - // RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 4, BULLET_EXPLOSIVERADIUS_X, BULLET_EXPLOSIVERADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - } - // PROLONGED EXPLOSION data - else if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) - { - // ARROW - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 8, BULLET_EXPLOSIVEARROW_X, BULLET_EXPLOSIVEARROW_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // DURATION ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 7, BULLET_EXPLOSIVEDURATION_X, BULLET_EXPLOSIVEDURATION_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 2) - { - // STARTING RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 9, BULLET_EXPLOSIVESTARTRADIUS_X, BULLET_EXPLOSIVESTARTRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // FINAL RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 10, BULLET_EXPLOSIVEENDRADIUS_X, BULLET_EXPLOSIVEENDRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // MUSTARD GAS - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 3) - { - // STARTING RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 13, BULLET_EXPLOSIVESTARTRADIUS_X, BULLET_EXPLOSIVESTARTRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // FINAL RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 14, BULLET_EXPLOSIVEENDRADIUS_X, BULLET_EXPLOSIVEENDRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // LIGHT - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 4) - { - // HEADROCK: Please note that these two are reversed for lights, as for some reason lights start - // at larger radius and decay to a smaller one. - - // STARTING RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 18, BULLET_EXPLOSIVESTARTRADIUS_X, BULLET_EXPLOSIVESTARTRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // FINAL RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 17, BULLET_EXPLOSIVEENDRADIUS_X, BULLET_EXPLOSIVEENDRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // SMOKE - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 6) - { - // STARTING RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 11, BULLET_EXPLOSIVESTARTRADIUS_X, BULLET_EXPLOSIVESTARTRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // FINAL RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 12, BULLET_EXPLOSIVEENDRADIUS_X, BULLET_EXPLOSIVEENDRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - - // NAPALM - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 8) - { - // STARTING RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 15, BULLET_EXPLOSIVESTARTRADIUS_X, BULLET_EXPLOSIVESTARTRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // FINAL RADIUS ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoExplosiveIcon, 16, BULLET_EXPLOSIVEENDRADIUS_X, BULLET_EXPLOSIVEENDRADIUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - } - + DrawAdvancedStats( gpItemDescObject ); } } void DrawArmorStats( OBJECTTYPE * gpItemDescObject ) { + INT16 sOffsetX = 2; + INT16 sOffsetY = 1; + if( UsingEDBSystem() == 0 ) return; - // HELMET - if ( Armour[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubArmourClass == 0 ) + if (gubDescBoxPage == 1) { - // ARMOR VALUE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 1, BULLET_ARMOR_X, BULLET_ARMOR_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // ARMOR COVERAGE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 4, BULLET_ARMORCOVERAGE_X, BULLET_ARMORCOVERAGE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + /////////////////// PROTECTION VALUE + { + // HELMET + if ( Armour[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubArmourClass == 0 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 1, gItemDescGenRegions[0][0].sLeft + sOffsetX, gItemDescGenRegions[0][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + // LEGGINGS + else if ( Armour[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubArmourClass == 2 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 2, gItemDescGenRegions[0][0].sLeft + sOffsetX, gItemDescGenRegions[0][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + // VEST and anything else + else + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 0, gItemDescGenRegions[0][0].sLeft + sOffsetX, gItemDescGenRegions[0][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + + /////////////////// COVERAGE VALUE + { + // HELMET + if ( Armour[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubArmourClass == 0 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 4, gItemDescGenRegions[1][0].sLeft + sOffsetX, gItemDescGenRegions[1][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + // LEGGINGS + else if ( Armour[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubArmourClass == 2 ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 5, gItemDescGenRegions[1][0].sLeft + sOffsetX, gItemDescGenRegions[1][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + // VEST and anything else + else + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 3, gItemDescGenRegions[1][0].sLeft + sOffsetX, gItemDescGenRegions[1][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + + ////////////////// ARMOR DEGRADE + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 6, gItemDescGenRegions[2][0].sLeft + sOffsetX, gItemDescGenRegions[2][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + ////////////////// SECONDARY ARMOR PROPERTIES + DrawSecondaryStats( gpItemDescObject ); } - // LEGGINGS - else if ( Armour[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubArmourClass == 2 ) + else if (gubDescBoxPage == 2) { - // ARMOR VALUE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 2, BULLET_ARMOR_X, BULLET_ARMOR_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // ARMOR COVERAGE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 5, BULLET_ARMORCOVERAGE_X, BULLET_ARMORCOVERAGE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + DrawAdvancedStats( gpItemDescObject ); } - // VEST and anything else - else +} + +void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject ) +{ + if (gubDescBoxPage != 2) { - // ARMOR VALUE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 0, BULLET_ARMOR_X, BULLET_ARMOR_Y, VO_BLT_SRCTRANSPARENCY, NULL ); - // ARMOR COVERAGE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 3, BULLET_ARMORCOVERAGE_X, BULLET_ARMORCOVERAGE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + return; } - // ARMOR DEGRADE ICON - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 6, BULLET_ARMORDEGRADE_X, BULLET_ARMORDEGRADE_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + INT16 sFirstLine = gubDescBoxLine; + INT16 sLastLine = gubDescBoxLine + NUM_UDB_ADV_LINES; + INT16 cnt = 0; // Counts number of properties encountered + INT16 sOffsetX = 0; + INT16 sOffsetY = 0; - // AP BONUS ICON - if ( GetAPBonus ( gpItemDescObject ) != 0 ) + ///////////////////// ACCURACY MODIFIER + if ( GetAccuracyModifier( gpItemDescObject )) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 11, BULLET_ARMORAPBONUS_X, BULLET_ARMORAPBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 0, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // AIM BONUS ICON - if ( GetFlatAimBonus( gpItemDescObject ) != 0 ) + ///////////////////// FLAT BASE MODIFIER + if (GetFlatBaseModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetFlatBaseModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetFlatBaseModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 12, BULLET_ARMORAIMBONUS_X, BULLET_ARMORAIMBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 1, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // WOODLAND CAMO ICON - if ( GetCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// PERCENT BASE MODIFIER + if (GetPercentBaseModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentBaseModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentBaseModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 7, BULLET_ARMORWOODCAMO_X, BULLET_ARMORWOODCAMO_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 2, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // URBAN CAMO ICON - if ( GetUrbanCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// FLAT AIM MODIFIER + if (GetFlatAimModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetFlatAimModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetFlatAimModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 8, BULLET_ARMORURBANCAMO_X, BULLET_ARMORURBANCAMO_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 3, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // DESERT CAMO ICON - if ( GetDesertCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// PERCENT AIM MODIFIER + if (GetPercentAimModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentAimModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentAimModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 9, BULLET_ARMORDESERTCAMO_X, BULLET_ARMORDESERTCAMO_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 4, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // SNOW CAMO ICON - if ( GetSnowCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// AIMING LEVELS MODIFIER + if (GetAimLevelsModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetAimLevelsModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetAimLevelsModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 10, BULLET_ARMORSNOWCAMO_X, BULLET_ARMORSNOWCAMO_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 5, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; } - // STEALTH ICON - if ( GetStealthBonus( gpItemDescObject ) != 0 ) + ///////////////////// CTH CAP MODIFIER + if (GetPercentCapModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentCapModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentCapModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 18, BULLET_ARMORSTEALTH_X, BULLET_ARMORSTEALTH_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 6, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].visionrangebonus != 0 ) + ///////////////////// GUN HANDLING MODIFIER + if (GetPercentHandlingModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetPercentHandlingModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetPercentHandlingModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 17, BULLET_ARMORVISIONRANGEBONUS_X, BULLET_ARMORVISIONRANGEBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 7, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // DAY VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].dayvisionrangebonus != 0 ) + ///////////////////// DROP COMPENSATION MODIFIER + if (GetDropCompensationModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetDropCompensationModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetDropCompensationModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 14, BULLET_ARMORDAYVISIONRANGEBONUS_X, BULLET_ARMORDAYVISIONRANGEBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 8, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + ///////////////////// TARGET TRACKING MODIFIER + if (GetTargetTrackingModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetTargetTrackingModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetTargetTrackingModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 9, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // NIGHT VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].nightvisionrangebonus != 0 ) + ///////////////////// DAMAGE MODIFIER + if (GetDamageBonus( gpItemDescObject ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 13, BULLET_ARMORNIGHTVISIONRANGEBONUS_X, BULLET_ARMORNIGHTVISIONRANGEBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 10, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; } - // BRIGHT LIGHT VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus != 0 ) + ///////////////////// MELEE DAMAGE MODIFIER + if (GetMeleeDamageBonus( gpItemDescObject ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 15, BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_X, BULLET_ARMORBRIGHTLIGHTVISIONRANGEBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 11, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; } - // CAVE VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].cavevisionrangebonus != 0 ) + ///////////////////// RANGE MODIFIER + if (GetRangeBonus( gpItemDescObject ) != 0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 16, BULLET_ARMORCAVEVISIONRANGEBONUS_X, BULLET_ARMORCAVEVISIONRANGEBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 12, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; } - // PERCENT TUNNEL VISION ICON - if ( Item[ gpItemDescObject->usItem ].percenttunnelvision > 0 ) + ///////////////////// SCOPE MAGNIFICATION + if (GetHighestScopeMagnificationFactor( gpItemDescObject ) > 1.0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 19, BULLET_ARMORPERCENTTUNNELVISION_X, BULLET_ARMORPERCENTTUNNELVISION_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 13, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } } - // HEARING RANGE BONUS ICON - if ( GetItemHearingRangeBonus( gpItemDescObject ) != 0 ) + ///////////////////// PROJECTION FACTOR + if (cnt-sFirstLine < sLastLine && + GetProjectionFactor( gpItemDescObject ) > 1.0 ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoArmorIcon, 20, BULLET_ARMORHEARINGRANGEBONUS_X, BULLET_ARMORHEARINGRANGEBONUS_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 14, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + ///////////////////// LATERAL RECOIL MODIFIER + INT8 bRecoilModifier; + INT8 bDummy; + GetFlatRecoilModifier( gpItemDescObject, &bRecoilModifier, &bDummy ); + if (bRecoilModifier != 0) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 15, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + + GetFlatRecoilModifier( gpItemDescObject, &bDummy, &bRecoilModifier ); + ///////////////////// VERTICAL RECOIL MODIFIER + if (bRecoilModifier != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 16, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + + ///////////////////// MAX COUNTER FORCE MODIFIER + if (GetCounterForceMaxModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetCounterForceMaxModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetCounterForceMaxModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 17, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + + ///////////////////// COUNTER FORCE ACCURACY MODIFIER + if (GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 18, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + + ///////////////////// COUNTER FORCE FREQUENCY MODIFIER + if (GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_STAND ) != 0 + || GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_CROUCH ) != 0 + || GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_PRONE ) != 0 ) + { + if( UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 19, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + } + + ///////////////////// AP MODIFIER + if (GetAPBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 20, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// DRAW AP MODIFIER + if (GetPercentReadyTimeAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 21, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// SINGLE-ATTACK AP MODIFIER + if (GetPercentAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 22, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// BURST AP MODIFIER + if (GetPercentBurstFireAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 23, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// AUTOFIRE AP MODIFIER + if (GetPercentAutofireAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 24, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// RELOAD AP MODIFIER + if (GetPercentReloadTimeAPReduction( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 25, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// MAGAZINE SIZE MODIFIER + if (GetMagSizeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 26, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// BURST SIZE MODIFIER + if (GetBurstSizeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 27, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// HIDE MUZZLE FLASH + if (IsFlashSuppressorAlt( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 28, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// LOUDNESS MODIFIER + if (GetPercentNoiseVolume( gpItemDescObject )-100 != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 29, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// ITEM SIZE MODIFIER + if (CalculateItemSize( gpItemDescObject ) - Item[ gpItemDescObject->usItem ].ItemSize != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 30, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// RELIABILITY MODIFIER + if (!(Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_PUNCH|IC_ARMOUR|IC_EXPLOSV)) && + GetReliability( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 31, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// WOODLAND CAMO + if (GetCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 32, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// URBAN CAMO + if (GetUrbanCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 33, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// DESERT CAMO + if (GetDesertCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 34, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// SNOW CAMO + if (GetSnowCamoBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 35, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// STEALTH MODIFIER + if (GetStealthBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 36, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// HEARING RANGE MODIFIER + if (GetItemHearingRangeBonus( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 37, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 0 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 38, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// NIGHT VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 2 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 39, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// DAY VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 1 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 40, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// BRIGHT LIGHT VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 3 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 41, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// CAVE VISION RANGE MODIFIER + if (GetItemVisionRangeBonus( gpItemDescObject, 4 ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 42, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; + } + + ///////////////////// PERCENT TUNNEL VISION + if (GetItemPercentTunnelVision( gpItemDescObject ) != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 43, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + cnt++; } } void DrawMiscStats( OBJECTTYPE * gpItemDescObject ) { - INT32 cnt = 0; - INT32 threshold; + if (gubDescBoxPage == 1) + { + DrawSecondaryStats( gpItemDescObject ); + } + else if (gubDescBoxPage == 2) + { + DrawAdvancedStats( gpItemDescObject ); + } - if( guiCurrentScreen == MAP_SCREEN ) - threshold = 13; - else - threshold = 11; - - if( UsingEDBSystem() == 0 ) +} + +/////////////////////////////////////////////////////////////////////////////////////// +// HEADROCK HAM 4: UDB: Draws item flags as large icons on the secondary column +void DrawSecondaryStats( OBJECTTYPE * gpItemDescObject ) +{ + if (UsingEDBSystem() == 0) + { return; + } - // ITEM SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].itemsizebonus != 0 && cnt<=threshold ) + if (gubDescBoxPage != 1) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 0, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; + // Secondary stats are drawn only on page 1. + return; } - - // RELIABILITY MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 && cnt<=threshold ) + + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_WEAPON || IC_PUNCH)) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 1, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; + // Weapons have no space on their UDB General page to show Secondary Stats anyway. + return; } - - // NOISE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction != 0 && cnt<=threshold ) + + INT32 cnt = 0; + INT32 sOffsetX = 0; + INT32 sOffsetY = 0; + + ///////////////////////////////////////////////////////////////////////////////// + // Start with class-specific secondaries + + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_ARMOUR)) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 2, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + ////////////////// FLAK JACKET + if (Item[ gpItemDescObject->usItem ].flakjacket) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 5, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + } + + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_AMMO)) + { + /////////////////// TRACER AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].tracerEffect ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 0, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + + /////////////////// ANTI-TANK AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].antiTank ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 1, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + + /////////////////// IGNORE ARMOR AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].ignoreArmour ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 2, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + + /////////////////// ACIDIC AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].acidic ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 3, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + + /////////////////// LOCKBUSTING AMMO + if ( AmmoTypes[Magazine[Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].lockBustingPower ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 4, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + } + + if (Item[ gpItemDescObject->usItem ].usItemClass & (IC_EXPLOSV)) + { + ////////////////// LOCK BOMB + if (Item[ gpItemDescObject->usItem ].lockbomb) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 25, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); + cnt++; + } + } + + ///////////////////////////////////////////////// + // Draw stats that can be had by any item. + + //////////////////// WATERPROOF + if (!Item[ gpItemDescObject->usItem ].waterdamages) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 6, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // HIDE MUZZLE FLASH ICON - if ( Item[ gpItemDescObject->usItem ].hidemuzzleflash > 0 && cnt<=threshold ) + //////////////////// ELECTRONIC + if (Item[ gpItemDescObject->usItem ].electronic) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 3, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 7, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // BIPOD ICON - if ( Item[ gpItemDescObject->usItem ].bipod != 0 && cnt<=threshold ) + //////////////////// GAS MASK + if (Item[ gpItemDescObject->usItem ].gasmask) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 4, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 8, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 && cnt<=threshold ) + //////////////////// NEEDS BATTERIES + if (Item[ gpItemDescObject->usItem ].needsbatteries) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 5, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 9, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 && cnt<=threshold ) + //////////////////// LOCKSMITH'S KIT + if (Item[ gpItemDescObject->usItem ].locksmithkit) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 6, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 10, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // LASER RANGE ICON - if ( Item[ gpItemDescObject->usItem ].bestlaserrange > 0 && cnt<=threshold ) + //////////////////// WIRE CUTTERS + if (Item[ gpItemDescObject->usItem ].wirecutters) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 7, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY + 2, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 11, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // AIMING MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].aimbonus != 0 && cnt<=threshold ) + //////////////////// CROWBAR + if (Item[ gpItemDescObject->usItem ].crowbar) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 8, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 12, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // MINIMUM RANGE FOR AIMING ICON - if ( Item[ gpItemDescObject->usItem ].minrangeforaimbonus > 0 && cnt<=threshold ) + //////////////////// CROWBAR + if (Item[ gpItemDescObject->usItem ].metaldetector) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 33, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 13, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // MAGAZINE SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].magsizebonus != 0 && cnt<=threshold ) + //////////////////// REMOTE TRIGGER + if (Item[ gpItemDescObject->usItem ].remotetrigger) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 17, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 14, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // BURST SIZE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].burstsizebonus != 0 && cnt<=threshold ) + //////////////////// REMOTE DETONATOR + if (Item[ gpItemDescObject->usItem ].remotedetonator) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 9, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 15, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // BURST TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus != 0 && cnt<=threshold ) + //////////////////// TIMER DETONATOR + if (Item[ gpItemDescObject->usItem ].detonator) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 10, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 16, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // AUTO TO-HIT MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus != 0 && cnt<=threshold ) + //////////////////// GAS CAN + if (Item[ gpItemDescObject->usItem ].gascan) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 11, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 17, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].APBonus != 0 && cnt<=threshold ) + //////////////////// TOOLKIT + if (Item[ gpItemDescObject->usItem ].toolkit) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 12, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 18, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // BURST AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentburstfireapreduction != 0 && cnt<=threshold ) + //////////////////// THERMAL OPTICS + if (Item[ gpItemDescObject->usItem ].thermaloptics) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 13, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 19, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // AUTOFIRE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentautofireapreduction != 0 && cnt<=threshold ) + //////////////////// X-RAY DEVICE + if (Item[ gpItemDescObject->usItem ].xray) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 14, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 20, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // READY AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreadytimeapreduction != 0 && cnt<=threshold ) + //////////////////// CANTEEN + if (Item[ gpItemDescObject->usItem ].canteen) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 15, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 21, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // RELOAD AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreloadtimeapreduction != 0 && cnt<=threshold ) + //////////////////// ALCOHOL + if (Item[ gpItemDescObject->usItem ].alcohol) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 16, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 22, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // SINGLE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentapreduction != 0 && cnt<=threshold ) + //////////////////// FIRST-AID KIT + if (Item[ gpItemDescObject->usItem ].firstaidkit) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 18, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 23, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } - // DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 && cnt<=threshold ) + //////////////////// MEDICAL KIT + if (Item[ gpItemDescObject->usItem ].medicalkit) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 19, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // MELEE DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].meleedamagebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 20, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // WOOD CAMO ICON - if ( Item[ gpItemDescObject->usItem ].camobonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 21, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // URBAN CAMO ICON - if ( Item[ gpItemDescObject->usItem ].urbanCamobonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 22, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // DESERT CAMO ICON - if ( Item[ gpItemDescObject->usItem ].desertCamobonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 23, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // SNOW CAMO ICON - if ( Item[ gpItemDescObject->usItem ].snowCamobonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 24, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // STEALTH MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].stealthbonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 25, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // HEARING RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].hearingrangebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 26, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].visionrangebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 27, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // DAY VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].dayvisionrangebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 29, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // NIGHT VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].nightvisionrangebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 28, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // BRIGHT LIGHT VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 30, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // CAVE VISION RANGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].cavevisionrangebonus != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 31, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); - cnt++; - } - - // PERCENT TUNNEL VISION MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percenttunnelvision != 0 && cnt<=threshold ) - { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoMiscIcon, 32, gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 24, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL ); cnt++; } } @@ -4352,429 +4470,1498 @@ void DrawWeaponValues( OBJECTTYPE * gpItemDescObject ) static CHAR16 pStr[ 100 ]; INT16 usX, usY; INT16 ubAttackAPs; + UINT8 ubNumLine; + INT16 sTop; + INT16 sHeight; + INT16 sLeft; + INT16 sWidth; if( UsingEDBSystem() == 0 ) return; - // Start with data relevant to all weapons - - // "AP COSTS" header - SetFontForeground( FONT_MCOLOR_WHITE ); - mprintf( gWeaponStats[ 9 ].sX + gsInvDescX + 2, gWeaponStats[ 9 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 2 ] ); - SetFontForeground( 6 ); - - // RELIABILITY - // equals - mprintf( gWeaponStats[ 28 ].sX + gsInvDescX, gWeaponStats[ 28 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // Calculate ammo reliability - INT8 iAmmoReliability = 0; - if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && (*gpItemDescObject)[0]->data.gun.ubGunShotsLeft > 0 ) - { - iAmmoReliability = Item[( *gpItemDescObject )[0]->data.gun.usGunAmmoItem].bReliability; - } - else - { - iAmmoReliability = 0; - } - - INT8 iReliabilityValue = iAmmoReliability + Item[ gpItemDescObject->usItem ].bReliability; - - // Determine color for value print - SetFontForeground ( 5 ); - if (iReliabilityValue < 0) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iReliabilityValue > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iReliabilityValue > 0 ) - { - swprintf( pStr, L"%+2d", iReliabilityValue ); - } - else - { - swprintf( pStr, L"%2d", iReliabilityValue ); - } - FindFontRightCoordinates( (INT16)(gWeaponStats[ 7 ].sX + gsInvDescX + gWeaponStats[ 7 ].sValDx), (INT16)(gWeaponStats[ 7 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - - // REPAIR EASE - // equals - mprintf( gWeaponStats[ 29 ].sX + gsInvDescX, gWeaponStats[ 29 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // Determine repair ease - INT8 iRepairEaseValue = Item[ gpItemDescObject->usItem ].bRepairEase; - - // Determine color for value printing - SetFontForeground ( 5 ); - if (iRepairEaseValue < 0) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iRepairEaseValue > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iRepairEaseValue > 0 ) - { - swprintf( pStr, L"%+2d", iRepairEaseValue ); - } - else - { - swprintf( pStr, L"%2d", iRepairEaseValue ); - } - FindFontRightCoordinates( (INT16)(gWeaponStats[ 8 ].sX + gsInvDescX + gWeaponStats[ 8 ].sValDx), (INT16)(gWeaponStats[ 8 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - - SetFontForeground( 6 ); - // ShotsPer4Turns -> ubAttackAPs, used later for all shot AP values ubAttackAPs = BaseAPsToShootOrStab( APBPConstants[DEFAULT_APS], APBPConstants[DEFAULT_AIMSKILL], gpItemDescObject ); + INT16 ubBasicAttackAPs = BaseAPsToShootOrStabNoModifier( APBPConstants[DEFAULT_APS], APBPConstants[DEFAULT_AIMSKILL], gpItemDescObject ); - // SINGLE SHOT AP - if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) + ////////////////////////////////////////////////////////////////////////////////////////// + // The following attributes are only drawn when the UDB is set to show the General Page. + + if (gubDescBoxPage == 1) { - // equals - mprintf( gWeaponStats[ 32 ].sX + gsInvDescX, gWeaponStats[ 32 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + ////////////////////////////////////////////////// HEADERS - // Determine color for printing value - if (ubAttackAPs <= EXCEPTIONAL_AP_COST) + SetFontForeground( FONT_MCOLOR_WHITE ); + + // "PRIMARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 0 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sTop, gItemDescGenHeaderRegions[0].sRight - gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sBottom - gItemDescGenHeaderRegions[0].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); + + // "AP COSTS" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 2 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sTop, gItemDescGenHeaderRegions[1].sRight - gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sBottom - gItemDescGenHeaderRegions[1].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); + + // "BURST / AUTOFIRE" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 3 ] ); + // If weapon has no burst/autofire, draw in greyish color. + if (GetShotsPerBurst(gpItemDescObject) <= 0 && GetAutofireShotsPerFiveAPs(gpItemDescObject) <= 0) + SetFontForeground( FONT_MCOLOR_DKGRAY ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[2].sLeft, gItemDescGenHeaderRegions[2].sTop, gItemDescGenHeaderRegions[2].sRight - gItemDescGenHeaderRegions[2].sLeft, gItemDescGenHeaderRegions[2].sBottom - gItemDescGenHeaderRegions[2].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); + + SetFontForeground( 6 ); + + ///////////////////////////////////////////////////// INDEXES + + SetFontForeground( FONT_MCOLOR_WHITE ); + + // Find out whether we need to display 2 or 3 indexes. + UINT8 Limit; + if (GetShotsPerBurst(gpItemDescObject)> 0 || GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0) { - SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); + Limit = 3; } else { - SetFontForeground( 5 ); + Limit = 2; } - // print value - swprintf( pStr, L"%2d", ubAttackAPs ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 11 ].sX + gsInvDescX + gWeaponStats[ 11 ].sValDx), (INT16)(gWeaponStats[ 11 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - - // BURST AP - if (GetShotsPerBurst(gpItemDescObject)> 0) - { - // equals - mprintf( gWeaponStats[ 33 ].sX + gsInvDescX, gWeaponStats[ 33 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", ubAttackAPs + CalcAPsToBurst( APBPConstants[DEFAULT_APS], gpItemDescObject ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 12 ].sX + gsInvDescX + gWeaponStats[ 12 ].sValDx), (INT16)(gWeaponStats[ 12 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - - // AUTO AP - if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) - { - // equals - mprintf( gWeaponStats[ 34 ].sX + gsInvDescX, gWeaponStats[ 34 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", ubAttackAPs + CalcAPsToAutofire( APBPConstants[DEFAULT_APS], gpItemDescObject, 3 ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 13 ].sX + gsInvDescX + gWeaponStats[ 13 ].sValDx), (INT16)(gWeaponStats[ 13 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - - // PRINT VALUES FOR SPECIFIC WEAPON TYPES - - // Guns and Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) - { - // ACCURACY - // equals - mprintf( gWeaponStats[ 27 ].sX + gsInvDescX, gWeaponStats[ 27 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // Get accuracy value - INT8 iAccuracyValue = Weapon[ gpItemDescObject->usItem ].bAccuracy; - - // Determine color for value printing - SetFontForeground( 5 ); - if (iAccuracyValue < 0) + // Repeatedly draw each index: four separate column headers per index. + for (UINT8 cnt = 0; cnt < Limit; cnt++) { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iAccuracyValue > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAccuracyValue > 0 ) - { - swprintf( pStr, L"%+2d", iAccuracyValue ); - } - else - { - swprintf( pStr, L"%2d", iAccuracyValue ); - } - FindFontRightCoordinates( (INT16)(gWeaponStats[ 6 ].sX + gsInvDescX + gWeaponStats[ 6 ].sValDx), (INT16)(gWeaponStats[ 6 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - // LOUDNESS - // equals - mprintf( gWeaponStats[ 38 ].sX + gsInvDescX, gWeaponStats[ 38 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // Get loudness value - INT16 iLoudnessValue = GetFinalLoudness( gpItemDescObject ); - - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", iLoudnessValue ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 17 ].sX + gsInvDescX + gWeaponStats[ 17 ].sValDx), (INT16)(gWeaponStats[ 17 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - - // Guns and Multi-use Launchers Only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // RELOAD AP - // equals - mprintf( gWeaponStats[ 35 ].sX + gsInvDescX, gWeaponStats[ 35 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", Weapon[ gpItemDescObject->usItem ].APsToReload ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 14 ].sX + gsInvDescX + gWeaponStats[ 14 ].sValDx), (INT16)(gWeaponStats[ 14 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - if ( Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) - { - // RELOAD MANUALLY AP - // equals - mprintf( gWeaponStats[ 36 ].sX + gsInvDescX, gWeaponStats[ 36 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", Weapon[gpItemDescObject->usItem].APsToReloadManually ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 15 ].sX + gsInvDescX + gWeaponStats[ 15 ].sValDx), (INT16)(gWeaponStats[ 15 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - } - - // Guns and Grenade Launchers only - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - // DRAW AP - // equals - mprintf( gWeaponStats[ 31 ].sX + gsInvDescX, gWeaponStats[ 31 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // calculate Draw AP - INT16 iDrawAP = 0; - iDrawAP = (Weapon[ gpItemDescObject->usItem ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(gpItemDescObject)) / 100); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", iDrawAP ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 10 ].sX + gsInvDescX + gWeaponStats[ 10 ].sValDx), (INT16)(gWeaponStats[ 10 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - - // Non-Launcher Guns Only - if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher ) - { - - if ( GetShotsPerBurst(gpItemDescObject)> 0 && ! GetAutofireShotsPerFiveAPs(gpItemDescObject) ) - { - // BURST PENALTY - // equals - mprintf( gWeaponStats[ 25 ].sX + gsInvDescX, gWeaponStats[ 25 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", GetBurstPenalty( gpItemDescObject, FALSE ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 4 ].sX + gsInvDescX + gWeaponStats[ 4 ].sValDx), (INT16)(gWeaponStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - // Note "else if" here to avoid displaying both types of penalties... - - else if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) - { - // AUTO PENALTY - // equals - mprintf( gWeaponStats[ 25 ].sX + gsInvDescX, gWeaponStats[ 25 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%d", GetAutoPenalty( gpItemDescObject, FALSE ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 4 ].sX + gsInvDescX + gWeaponStats[ 4 ].sValDx), (INT16)(gWeaponStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - // Add BurstPenalty if necessary - if (GetShotsPerBurst(gpItemDescObject)> 0 ) + for (UINT8 cnt2 = 0; cnt2 < 4; cnt2++) { - // Colored white and placed in front of the auto penalty. - static CHAR16 pStr2[ 100 ]; - SetFontForeground( FONT_WHITE ); - swprintf(pStr2, L"%d/", GetBurstPenalty( gpItemDescObject, FALSE ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 4 ].sX + gsInvDescX + gWeaponStats[ 4 ].sValDx) - StringPixLength(pStr,BLOCKFONT2), (INT16)(gWeaponStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr2, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr2 ); - SetFontForeground( 6 ); + // Select "PROPERTY", "0", "+" or "=" as appropriate. + swprintf(pStr, L"%s", gzItemDescGenIndexes[ cnt2 ]); + + FindFontCenterCoordinates( gItemDescGenIndexRegions[cnt][cnt2].sLeft, gItemDescGenIndexRegions[cnt][cnt2].sTop, gItemDescGenIndexRegions[cnt][cnt2].sRight - gItemDescGenIndexRegions[cnt][cnt2].sLeft, gItemDescGenIndexRegions[cnt][cnt2].sBottom - gItemDescGenIndexRegions[cnt][cnt2].sTop, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + } + + SetFontForeground( 6 ); + //////////////////// ACCURACY + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) + { + // Set line to draw into + ubNumLine = 0; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get accuracy value + INT8 iAccuracyValue = (UsingNewCTHSystem() == true ? Weapon[ gpItemDescObject->usItem ].nAccuracy : Weapon[ gpItemDescObject->usItem ].bAccuracy); + + // Get Modified Accuracy value + INT8 iFinalAccuracyValue = GetGunAccuracy( gpItemDescObject ); + + // Get difference + INT8 iAccuracyDifference = iFinalAccuracyValue - iAccuracyValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iAccuracyValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iAccuracyDifference < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iAccuracyDifference > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iAccuracyDifference > 0 ) + { + swprintf( pStr, L"%+d", iAccuracyDifference ); + } + else if ( iAccuracyDifference < 0 ) + { + swprintf( pStr, L"%d", iAccuracyDifference ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalAccuracyValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + /////////////// DAMAGE + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_PUNCH|IC_BLADE|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) + { + // Set line to draw into + ubNumLine = 1; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base damage value + UINT8 iDamageValue = GetBasicDamage ( gpItemDescObject ); + + // Get Modified Accuracy value + UINT8 iFinalDamageValue = GetDamage ( gpItemDescObject ); + + // Get difference + INT8 iDamageModifier = iFinalDamageValue - iDamageValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iDamageValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iDamageModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iDamageModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iDamageModifier > 0 ) + { + swprintf( pStr, L"+%d", iDamageModifier ); + } + else if ( iDamageModifier < 0 ) + { + swprintf( pStr, L"%d", iDamageModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalDamageValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + /////////////// RANGE + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) + { + // Set line to draw into + ubNumLine = 2; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Range value + UINT16 iRangeValue = Weapon[ gpItemDescObject->usItem ].usRange; + + // Get Final Range value + UINT16 iFinalRangeValue = GunRange( gpItemDescObject, NULL ); + + // Get difference + INT16 iRangeModifier = iFinalRangeValue - iRangeValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iRangeValue/10 ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iRangeModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iRangeModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iRangeModifier > 0 ) + { + swprintf( pStr, L"+%d", iRangeModifier/10 ); + } + else if ( iRangeModifier < 0 ) + { + swprintf( pStr, L"%d", iRangeModifier/10 ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalRangeValue/10 ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + /////////////// AIM LEVELS + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) + { + // Set line to draw into + ubNumLine = 3; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get Final Aiming Levels + UINT16 iFinalAimLevelsValue = GetAllowedAimingLevelsForItem( gpItemDescObject, ANIM_STAND ); + + // Get modifier + INT16 iAimLevelsModifier = GetAimLevelsModifier( gpItemDescObject, ANIM_STAND ); + + // Get Base Value + UINT16 iAimLevelsValue = iFinalAimLevelsValue - iAimLevelsModifier; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iAimLevelsValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iAimLevelsModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iAimLevelsModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iAimLevelsModifier > 0 ) + { + swprintf( pStr, L"+%d", iAimLevelsModifier ); + } + else if ( iAimLevelsModifier < 0 ) + { + swprintf( pStr, L"%d", iAimLevelsModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalAimLevelsValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + //////////////// SCOPE MAGNIFICATION FACTOR + if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_GUN ) + { + // Set line to draw into + ubNumLine = 4; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + FLOAT iScopeMagValue; // Get base Magnification value + FLOAT iScopeMagModifier; // Get best Magnification value + FLOAT iFinalScopeMagValue; // Get final Magnification value + + if(UsingNewCTHSystem()==true){ + iScopeMagValue = __max(1.0f, Item[ gpItemDescObject->usItem ].scopemagfactor); + iScopeMagModifier = GetHighestScopeMagnificationFactor( gpItemDescObject ); + iFinalScopeMagValue = __max( iScopeMagValue, iScopeMagModifier ); + } else { + iScopeMagValue = __max(0.0f, Item[ gpItemDescObject->usItem ].aimbonus); + iScopeMagModifier = (FLOAT)GetFlatAimBonus( gpItemDescObject ); + iFinalScopeMagValue = __max( iScopeMagValue, iScopeMagModifier ); } + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iScopeMagValue > 1.0f) + { + swprintf( pStr, L"%3.1f", iScopeMagValue ); + } + else + { + swprintf( pStr, L"--"); + } + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print Scope Mag factor from attachments + SetFontForeground( 5 ); + if (iScopeMagModifier > 1.0f && iScopeMagModifier > iScopeMagValue) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%3.1f", iScopeMagModifier ); + } + else + { + swprintf( pStr, L"--", iScopeMagModifier ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%3.1f", iFinalScopeMagValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } - // Note "if" here to display this regardless of BURST PENALTY + ///////////////// (LASER) PROJECTION FACTOR + if (GetProjectionFactor( gpItemDescObject ) > 1.0 ) + { + // Set line to draw into + ubNumLine = 5; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + FLOAT iProjectionValue; // Get base Projection value + FLOAT iProjectionModifier; // Get best Projection value + FLOAT iFinalProjectionValue; // Get final Projection value + + if(UsingNewCTHSystem() == true){ + iProjectionValue = __max(1.0f, Item[ gpItemDescObject->usItem ].projectionfactor); + iProjectionModifier = GetProjectionFactor( gpItemDescObject ); + iFinalProjectionValue = __max( iProjectionValue, iProjectionModifier ); + } else { + iProjectionValue = __max(0.0f, Item[ gpItemDescObject->usItem ].bestlaserrange / 10); + iProjectionModifier = (FLOAT)GetAverageBestLaserRange( gpItemDescObject ) / 10; + iFinalProjectionValue = __max( iProjectionValue, iProjectionModifier ); + } + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iProjectionValue > 1.0f) + { + swprintf( pStr, L"%3.1f", iProjectionValue ); + } + else + { + swprintf( pStr, L"--"); + } + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print Projection factor from attachments + SetFontForeground( 5 ); + if (iProjectionModifier > 1.0f && iProjectionModifier > iProjectionValue) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%3.1f", iProjectionModifier ); + } + else + { + swprintf( pStr, L"--", iProjectionModifier ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%3.1f", iFinalProjectionValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ///////////////// FLASH SUPPRESSION + if (IsFlashSuppressorAlt( gpItemDescObject ) == TRUE) + { + // Set line to draw into + ubNumLine = 6; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Does gun have flash suppression? + BOOLEAN iFlashValue = Item[ gpItemDescObject->usItem ].hidemuzzleflash; + + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iFlashValue) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"Y" ); + } + else + { + swprintf( pStr, L"--"); + } + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + if (!iFlashValue) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"Y" ); + } + else + { + swprintf( pStr, L"--"); + } + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"Y" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ////////////////// LOUDNESS + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) + { + // Set line to draw into + ubNumLine = 7; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Loudness value + UINT8 iLoudnessValue = Weapon[Item[gpItemDescObject->usItem].ubClassIndex].ubAttackVolume; + + // Get final Loudness value + INT16 iFinalLoudnessValue = GetFinalLoudness( gpItemDescObject ); + + // Get Loudness modifier + INT16 iLoudnessModifier = iFinalLoudnessValue - iLoudnessValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iLoudnessValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iLoudnessModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iLoudnessModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iLoudnessModifier > 0 ) + { + swprintf( pStr, L"+%d", iLoudnessModifier ); + } + else if ( iLoudnessModifier < 0 ) + { + swprintf( pStr, L"%d", iLoudnessModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalLoudnessValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + /////////////////// RELIABILITY + { + // Set line to draw into + ubNumLine = 8; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Reliability value + INT8 iReliabilityValue = Item[gpItemDescObject->usItem].bReliability; + + // Get final Reliability value + INT16 iFinalReliabilityValue = GetReliability( gpItemDescObject ); + + // Get Reliability modifier + INT16 iReliabilityModifier = iFinalReliabilityValue - iReliabilityValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iReliabilityValue < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iReliabilityValue ); + } + else if ( iReliabilityValue > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iReliabilityValue ); + } + else + { + swprintf( pStr, L"--" ); + } + + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iReliabilityModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iReliabilityModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iReliabilityModifier > 0 ) + { + swprintf( pStr, L"+%d", iReliabilityModifier ); + } + else if ( iReliabilityModifier < 0 ) + { + swprintf( pStr, L"%d", iReliabilityModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalReliabilityValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + /////////////////// REPAIR EASE + { + // Set line to draw into + ubNumLine = 9; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Reliability value + INT8 iRepairEaseValue = Item[gpItemDescObject->usItem].bRepairEase; + + // Get final Reliability value + INT8 iFinalRepairEaseValue = iRepairEaseValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iRepairEaseValue < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iRepairEaseValue ); + } + else if ( iRepairEaseValue > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iRepairEaseValue ); + } + else + { + swprintf( pStr, L"--" ); + } + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalRepairEaseValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + /////////////////// MinRangeForAimBonus + if( UsingNewCTHSystem() == false ) + { + // Set line to draw into + ubNumLine = 10; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Reliability value + INT16 iMinRangeForAimBonusValue = Item[gpItemDescObject->usItem].minrangeforaimbonus / 10; + + // Get final Reliability value + INT16 iFinalMinRangeForAimBonusValue = GetMinRangeForAimBonus(gpItemDescObject) / 10; + + // Get Reliability modifier + INT16 iMinRangeForAimBonusModifier = iFinalMinRangeForAimBonusValue - iMinRangeForAimBonusValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iMinRangeForAimBonusValue < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iMinRangeForAimBonusValue ); + } + else if ( iMinRangeForAimBonusValue > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iMinRangeForAimBonusValue ); + } + else + { + swprintf( pStr, L"--" ); + } + + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iMinRangeForAimBonusModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iMinRangeForAimBonusModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iMinRangeForAimBonusModifier > 0 ) + { + swprintf( pStr, L"+%d", iMinRangeForAimBonusModifier ); + } + else if ( iMinRangeForAimBonusModifier < 0 ) + { + swprintf( pStr, L"%d", iMinRangeForAimBonusModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalMinRangeForAimBonusValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + /////////////////// ToHitBonus + if( UsingNewCTHSystem() == false ) + { + // Set line to draw into + ubNumLine = 11; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Reliability value + INT16 iToHitBonusValue = Item[gpItemDescObject->usItem].tohitbonus; + + // Get final Reliability value + INT16 iFinalToHitBonusValue = GetFlatToHitBonus(gpItemDescObject); + + // Get Reliability modifier + INT16 iToHitBonusModifier = iFinalToHitBonusValue - iToHitBonusValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iToHitBonusValue < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iToHitBonusValue ); + } + else if ( iToHitBonusValue > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iToHitBonusValue ); + } + else + { + swprintf( pStr, L"--" ); + } + + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iToHitBonusModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iToHitBonusModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iToHitBonusModifier > 0 ) + { + swprintf( pStr, L"+%d", iToHitBonusModifier ); + } + else if ( iToHitBonusModifier < 0 ) + { + swprintf( pStr, L"%d", iToHitBonusModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalToHitBonusValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ///////////////////// DRAW AP + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem].rocketlauncher ) + { + // Set line to draw into + ubNumLine = 13; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final Draw Cost + INT16 iFinalDrawAPCost = (Weapon[ gpItemDescObject->usItem ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(gpItemDescObject)) / 100); + + // Get base Draw Cost + INT16 iDrawAPCost = Weapon[ gpItemDescObject->usItem ].ubReadyTime; + + // Get Draw Cost Modifier + INT16 iDrawAPCostModifier = iFinalDrawAPCost - iDrawAPCost; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iDrawAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iDrawAPCostModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iDrawAPCostModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iDrawAPCostModifier > 0 ) + { + swprintf( pStr, L"+%d", iDrawAPCostModifier ); + } + else if ( iDrawAPCostModifier < 0 ) + { + swprintf( pStr, L"%d", iDrawAPCostModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalDrawAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + ////////////////// SINGLE SHOT AP + if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) + { + // Set line to draw into + ubNumLine = 14; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final Attack Cost + INT16 iFinalSingleAPCost = ubAttackAPs; + + // Get base Attack Cost + INT16 iSingleAPCost = ubBasicAttackAPs; + + // Get Attack Cost Modifier + INT16 iSingleAPCostModifier = iFinalSingleAPCost - iSingleAPCost; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iSingleAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iSingleAPCostModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iSingleAPCostModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iSingleAPCostModifier > 0 ) + { + swprintf( pStr, L"+%d", iSingleAPCostModifier ); + } + else if ( iSingleAPCostModifier < 0 ) + { + swprintf( pStr, L"%d", iSingleAPCostModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalSingleAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + /////////////////// BURST AP + if (GetShotsPerBurst(gpItemDescObject)> 0) + { + // Set line to draw into + ubNumLine = 15; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final Burst Cost + INT16 iFinalBurstAPCost = ubAttackAPs + CalcAPsToBurst( APBPConstants[DEFAULT_APS], gpItemDescObject ); + + // Get base Burst Cost + INT16 iBurstAPCost = ubBasicAttackAPs + CalcAPsToBurstNoModifier( APBPConstants[DEFAULT_APS], gpItemDescObject ); + + // Get Burst Cost Modifier + INT16 iBurstAPCostModifier = iFinalBurstAPCost - iBurstAPCost; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iBurstAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iBurstAPCostModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iBurstAPCostModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iBurstAPCostModifier > 0 ) + { + swprintf( pStr, L"+%d", iBurstAPCostModifier ); + } + else if ( iBurstAPCostModifier < 0 ) + { + swprintf( pStr, L"%d", iBurstAPCostModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalBurstAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + ////////////////// AUTO AP if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) { - // AUTOFIRE SHOTS PER 5 AP - // equals - mprintf( gWeaponStats[ 26 ].sX + gsInvDescX, gWeaponStats[ 26 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + // Set line to draw into + ubNumLine = 16; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; - // print value + // Get final Autofire Cost + INT16 iFinalAutoAPCost = ubAttackAPs + CalcAPsToAutofire( APBPConstants[DEFAULT_APS], gpItemDescObject, 3 ); + + // Get base Autofire Cost + INT16 iAutoAPCost = ubBasicAttackAPs + CalcAPsToAutofireNoModifier( APBPConstants[DEFAULT_APS], gpItemDescObject, 3 ); + + // Get Autofire Cost Modifier + INT16 iAutoAPCostModifier = iFinalAutoAPCost - iAutoAPCost; + + // Print base value SetFontForeground( 5 ); - swprintf( pStr, L"%2d", GetAutofireShotsPerFiveAPs( gpItemDescObject ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 5 ].sX + gsInvDescX + gWeaponStats[ 5 ].sValDx), (INT16)(gWeaponStats[ 5 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iAutoAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - } - } - - ////////////////////////////////////////////////////////////////////// - // Begin non-weapontype-specific data. These are not type specific because they represent bonuses - // which may one day be added to various types of weapons by modders... - if (GetFlatToHitBonus( gpItemDescObject ) != 0) - { - // HIT BONUS - // equals - mprintf( gWeaponStats[ 39 ].sX + gsInvDescX, gWeaponStats[ 39 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // Determine Color for Value Printing - SetFontForeground( 5 ); - if (GetFlatToHitBonus ( gpItemDescObject ) < 0) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if (GetFlatToHitBonus ( gpItemDescObject ) > 0) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // Print Value - if ( GetFlatToHitBonus ( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d", GetFlatToHitBonus ( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d", GetFlatToHitBonus ( gpItemDescObject ) ); - } - FindFontRightCoordinates( (INT16)(gWeaponStats[ 18 ].sX + gsInvDescX + gWeaponStats[ 18 ].sValDx), (INT16)(gWeaponStats[ 18 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - if (GetFlatToHitBonus( gpItemDescObject ) > 0 && GetAverageBestLaserRange( gpItemDescObject ) / 10 > 0 ) - { - // LASER RANGE - // equals - mprintf( gWeaponStats[ 40 ].sX + gsInvDescX, gWeaponStats[ 40 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value + // Print modifier SetFontForeground( 5 ); - swprintf( pStr, L"%2d", GetAverageBestLaserRange( gpItemDescObject ) / 10 ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 19 ].sX + gsInvDescX + gWeaponStats[ 19 ].sValDx), (INT16)(gWeaponStats[ 19 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + if (iAutoAPCostModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iAutoAPCostModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iAutoAPCostModifier > 0 ) + { + swprintf( pStr, L"+%d", iAutoAPCostModifier ); + } + else if ( iAutoAPCostModifier < 0 ) + { + swprintf( pStr, L"%d", iAutoAPCostModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - } - if (GetBipodBonus( gpItemDescObject ) != 0) - { - // BIPOD BONUS - // equals - mprintf( gWeaponStats[ 43 ].sX + gsInvDescX, gWeaponStats[ 43 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - if (GetBipodBonus( gpItemDescObject ) < 0) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if (GetBipodBonus( gpItemDescObject ) > 0) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - if ( GetBipodBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d", GetBipodBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d", GetBipodBonus( gpItemDescObject ) ); - } - FindFontRightCoordinates( (INT16)(gWeaponStats[ 22 ].sX + gsInvDescX + gWeaponStats[ 22 ].sValDx), (INT16)(gWeaponStats[ 22 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - } - - if (IsScoped( gpItemDescObject )) - { - // SCOPE AIM BONUS - // equals - mprintf( gWeaponStats[ 41 ].sX + gsInvDescX, gWeaponStats[ 41 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - if (GetFlatAimBonus( gpItemDescObject ) < 0) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if (GetFlatAimBonus( gpItemDescObject ) > 0) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - if ( GetFlatAimBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d", GetFlatAimBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d", GetFlatAimBonus( gpItemDescObject ) ); - } - FindFontRightCoordinates( (INT16)(gWeaponStats[ 20 ].sX + gsInvDescX + gWeaponStats[ 20 ].sValDx), (INT16)(gWeaponStats[ 20 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - SetFontForeground( 6 ); - - - if (GetMinRangeForAimBonus(gpItemDescObject) > 0) - { - // SCOPE MINIMUM RANGE FOR AIM BONUS - // equals - mprintf( gWeaponStats[ 42 ].sX + gsInvDescX, gWeaponStats[ 42 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", GetMinRangeForAimBonus( gpItemDescObject )/10 ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 21 ].sX + gsInvDescX + gWeaponStats[ 21 ].sValDx), (INT16)(gWeaponStats[ 21 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalAutoAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); + + // Reset font color SetFontForeground( 6 ); } + + ///////////////////// RELOAD AP + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) + { + // Set line to draw into + ubNumLine = 17; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final Reload Cost + INT16 iFinalReloadAPCost = GetAPsToReload( gpItemDescObject ); + + // Get base Reload Cost + INT16 iReloadAPCost = Weapon[ gpItemDescObject->usItem ].APsToReload; + + // Get Reload Cost Modifier + INT16 iReloadAPCostModifier = iFinalReloadAPCost - iReloadAPCost; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iReloadAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iReloadAPCostModifier < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( iReloadAPCostModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iReloadAPCostModifier > 0 ) + { + swprintf( pStr, L"+%d", iReloadAPCostModifier ); + } + else if ( iReloadAPCostModifier < 0 ) + { + swprintf( pStr, L"%d", iReloadAPCostModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalReloadAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + ///////////////////// MANUAL RELOAD AP + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher + && Weapon[gpItemDescObject->usItem].APsToReloadManually > 0 ) + { + // Set line to draw into + ubNumLine = 18; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final Manual Reload Cost + INT16 iFinalManualReloadAPCost = Weapon[ gpItemDescObject->usItem ].APsToReloadManually; + + // Get base Manual Reload Cost + INT16 iManualReloadAPCost = iFinalManualReloadAPCost; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iManualReloadAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalManualReloadAPCost ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + + ///////////////////// RECOIL X/Y + if ( UsingNewCTHSystem() == true ) + { + if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher + && GetShotsPerBurst(gpItemDescObject)> 0 || GetAutofireShotsPerFiveAPs(gpItemDescObject)) + { + + INT8 iFinalRecoilX = 0; + INT8 iFinalRecoilY = 0; + + // Get final Recoil + GetRecoil( gpItemDescObject, &iFinalRecoilX, &iFinalRecoilY, 2 ); + + // Get base Recoil + INT8 iRecoilX = Weapon[ gpItemDescObject->usItem ].bRecoilX; + INT8 iRecoilY = Weapon[ gpItemDescObject->usItem ].bRecoilY; + + if (iRecoilX == -127) { iRecoilX = 0; } // -127 means "invalid". These guns don't actually have any recoil parameters. + if (iRecoilY == -127) { iRecoilY = 0; } + + // Get Recoil Modifiers + INT16 iRecoilXModifier = iFinalRecoilX - iRecoilX; + INT16 iRecoilYModifier = iFinalRecoilY - iRecoilY; + + // RECOIL X + + // Set line to draw into + ubNumLine = 19; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iRecoilX ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if ( (iRecoilXModifier < 0 && iRecoilX > 0) || (iRecoilXModifier > 0 && iRecoilX < 0) ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( (iRecoilXModifier > 0 && iRecoilX > 0) || (iRecoilXModifier < 0 && iRecoilX < 0) ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iRecoilXModifier > 0 ) + { + swprintf( pStr, L"+%d", iRecoilXModifier ); + } + else if ( iRecoilXModifier < 0 ) + { + swprintf( pStr, L"%d", iRecoilXModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalRecoilX ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + + // RECOIL Y + + // Set line to draw into + ubNumLine = 20; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iRecoilY ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if ( (iRecoilYModifier < 0 && iRecoilY > 0) || (iRecoilYModifier > 0 && iRecoilY < 0) ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + else if ( (iRecoilYModifier > 0 && iRecoilY > 0) || (iRecoilYModifier < 0 && iRecoilY < 0) ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + // Add positive/negative sign + if ( iRecoilYModifier > 0 ) + { + swprintf( pStr, L"+%d", iRecoilYModifier ); + } + else if ( iRecoilYModifier < 0 ) + { + swprintf( pStr, L"%d", iRecoilYModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalRecoilY ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + } + } + else ///////////////// BIPOD + { + if( GetBipodBonus(gpItemDescObject) > 0) + { + // Set line to draw into + ubNumLine = 20; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get base Reliability value + INT16 iBipodValue = Item[gpItemDescObject->usItem].bipod; + + // Get final Reliability value + INT16 iFinalBipodValue = GetBipodBonus(gpItemDescObject); + + // Get Reliability modifier + INT16 iBipodModifier = iFinalBipodValue - iBipodValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + if (iBipodValue < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iBipodValue ); + } + else if ( iBipodValue > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iBipodValue ); + } + else + { + swprintf( pStr, L"--" ); + } + + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iBipodModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iBipodModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iBipodModifier > 0 ) + { + swprintf( pStr, L"+%d", iBipodModifier ); + } + else if ( iBipodModifier < 0 ) + { + swprintf( pStr, L"%d", iBipodModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalBipodValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + } + + /////////////////// AUTOFIRE BULLETS PER 5 AP + if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_GUN && !Item[ gpItemDescObject->usItem].rocketlauncher + && GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) + { + // Set line to draw into + ubNumLine = 21; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final B/5AP + INT16 iFinalB5AP = GetAutofireShotsPerFiveAPs( gpItemDescObject ); + + // Get base B/5AP Cost + INT16 iB5AP = iFinalB5AP; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iB5AP ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalB5AP ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); + + } + } + if (gubDescBoxPage == 2) + { + DrawAdvancedValues( gpItemDescObject ); } } @@ -4782,363 +5969,201 @@ void DrawAmmoValues( OBJECTTYPE * gpItemDescObject, int shotsLeft ) { static CHAR16 pStr[ 100 ]; INT16 usY; - INT16 sStrX; - UINT16 uiStringLength; + INT16 usX; + UINT8 ubNumLine; + INT16 sLeft, sTop, sWidth, sHeight; if( UsingEDBSystem() == 0 ) return; - // AMMO AMOUNT - // label - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 0 ].sX + gsInvDescX, gWeaponStats[ 0 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 16 ] ); - - // data - SetFontForeground( 5 ); - swprintf( pStr, L"%d/%d", shotsLeft, Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubMagSize ); //Pulmu: Correct # of rounds for stacked ammo. - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 0 ].sX + gsInvDescX + gWeaponStats[ 0 ].sValDx+6), (INT16)(gWeaponStats[ 0 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - if (UsingEDBSystem() == 2) - mprintf( sStrX - 6, gWeaponStats[ 0 ].sY + gsInvDescY + 12, pStr ); - else - mprintf( sStrX, gWeaponStats[ 0 ].sY + gsInvDescY, pStr ); - - // AMMO PENETRATION - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 23 ].sX + gsInvDescX -5, gWeaponStats[ 23 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - FLOAT fArmourImpactReduction = 0.0; - fArmourImpactReduction = (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].armourImpactReductionMultiplier / (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].armourImpactReductionDivisor; - - // determine value print color - SetFontForeground( 5 ); - if ( fArmourImpactReduction > 1.0 ) + if (gubDescBoxPage == 0) { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( fArmourImpactReduction < 1.0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - swprintf( pStr, L"%1.2f", fArmourImpactReduction ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 2 ].sX + gsInvDescX + gWeaponStats[ 2 ].sValDx), (INT16)(gWeaponStats[ 2 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 2 ].sY + gsInvDescY, pStr ); - - // AMMO TUMBLE - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 24 ].sX + gsInvDescX -5, gWeaponStats[ 24 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - FLOAT fAfterArmourImpactReduction = 0.0; - fAfterArmourImpactReduction = (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].afterArmourDamageMultiplier / (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].afterArmourDamageDivisor; - - // determine value print color - SetFontForeground( 5 ); - if ( fAfterArmourImpactReduction < 1.0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( fAfterArmourImpactReduction > 1.0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - swprintf( pStr, L"%1.2f", fAfterArmourImpactReduction ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 3 ].sX + gsInvDescX + gWeaponStats[ 3 ].sValDx), (INT16)(gWeaponStats[ 3 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 3 ].sY + gsInvDescY, pStr ); - - // AMMO PRE-ARMOR EXPLOSION - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 25 ].sX + gsInvDescX -5, gWeaponStats[ 25 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - FLOAT fBeforeArmourImpactReduction = 0.0; - fBeforeArmourImpactReduction = (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].beforeArmourDamageMultiplier / (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].beforeArmourDamageDivisor; - - // determine value print color - SetFontForeground( 5 ); - if ( fBeforeArmourImpactReduction < 1.0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( fBeforeArmourImpactReduction > 1.0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - swprintf( pStr, L"%1.2f", fBeforeArmourImpactReduction ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 4 ].sX + gsInvDescX + gWeaponStats[ 4 ].sValDx), (INT16)(gWeaponStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 4 ].sY + gsInvDescY, pStr ); - - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 ) - { - // AMMO RANGE BONUS - // equals + ////////////////////////// AMMO REMAINING SetFontForeground( 6 ); - mprintf( gWeaponStats[ 37 ].sX + gsInvDescX, gWeaponStats[ 37 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + swprintf( pStr, gWeaponStatsDesc[16] ); + mprintf( gItemDescTextRegions[1].sLeft, gItemDescTextRegions[1].sTop, pStr ); - // determine value - INT16 iRangeBonus = 0; - iRangeBonus = Item[ gpItemDescObject->usItem ].rangebonus; - - // determine value print color SetFontForeground( 5 ); - if ( iRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iRangeBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iRangeBonus > 0 ) - { - swprintf( pStr, L"%+2d", iRangeBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iRangeBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 16 ].sX + gsInvDescX + gWeaponStats[ 16 ].sValDx), (INT16)(gWeaponStats[ 16 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 16 ].sY + gsInvDescY, pStr ); + swprintf( pStr, L"%d/%d", (*gpItemDescObject)[ gubItemDescStatusIndex ]->data.ubShotsLeft, Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubMagSize ); + FindFontRightCoordinates( gItemDescTextRegions[1].sLeft, gItemDescTextRegions[1].sTop, gItemDescTextRegions[1].sRight - gItemDescTextRegions[1].sLeft, gItemDescTextRegions[1].sBottom - gItemDescTextRegions[1].sTop, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } - - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 ) + else if (gubDescBoxPage == 1) { - // AMMO DAMAGE BONUS - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 38 ].sX + gsInvDescX, gWeaponStats[ 38 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + ////////////////////////////////////////////////// HEADERS - // determine value - INT16 iDamageBonus = 0; - iDamageBonus = Item[ gpItemDescObject->usItem ].damagebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iDamageBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iDamageBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iDamageBonus > 0 ) - { - swprintf( pStr, L"%+2d", iDamageBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iDamageBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 17 ].sX + gsInvDescX + gWeaponStats[ 17 ].sValDx), (INT16)(gWeaponStats[ 17 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 17 ].sY + gsInvDescY, pStr ); - } + SetFontForeground( FONT_MCOLOR_WHITE ); - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 ) - { - // AMMO TO-HIT BONUS - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 39 ].sX + gsInvDescX, gWeaponStats[ 39 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + // "PRIMARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 0 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sTop, gItemDescGenHeaderRegions[0].sRight - gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sBottom - gItemDescGenHeaderRegions[0].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); - // determine value - INT16 iToHitBonus = 0; - iToHitBonus = Item[ gpItemDescObject->usItem ].tohitbonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iToHitBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iToHitBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iToHitBonus > 0 ) - { - swprintf( pStr, L"%+2d", iToHitBonus ); - } - else - { - swprintf( pStr, L"%2d", iToHitBonus ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 18 ].sX + gsInvDescX + gWeaponStats[ 18 ].sValDx), (INT16)(gWeaponStats[ 18 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 18 ].sY + gsInvDescY, pStr ); - } + // "SECONDARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 1 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sTop, gItemDescGenHeaderRegions[1].sRight - gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sBottom - gItemDescGenHeaderRegions[1].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus ) - { - // AUTO PENALTY MODIFIER - // equals - mprintf( gWeaponStats[ 40 ].sX + gsInvDescX, gWeaponStats[ 40 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); SetFontForeground( 6 ); - // determine value - INT16 iAutoBonus = 0; - iAutoBonus = Item[ gpItemDescObject->usItem ].autofiretohitbonus; + ///////////////////////////////////////////////////// INDEXES - // determine value print color - SetFontForeground( 5 ); - if ( iAutoBonus < 0 ) + SetFontForeground( FONT_MCOLOR_WHITE ); + + for (UINT8 cnt = 0; cnt < 4; cnt++) { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iAutoBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAutoBonus > 0 ) - { - swprintf( pStr, L"%+2d", iAutoBonus ); - } - else - { - swprintf( pStr, L"%2d", iAutoBonus ); + // Select "PROPERTY", "0", "+" or "=" as appropriate. + swprintf(pStr, L"%s", gzItemDescGenIndexes[ cnt ]); + + FindFontCenterCoordinates( gItemDescGenIndexRegions[0][cnt].sLeft, gItemDescGenIndexRegions[0][cnt].sTop, gItemDescGenIndexRegions[0][cnt].sRight - gItemDescGenIndexRegions[0][cnt].sLeft, gItemDescGenIndexRegions[0][cnt].sBottom - gItemDescGenIndexRegions[0][cnt].sTop, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 19 ].sX + gsInvDescX + gWeaponStats[ 19 ].sValDx), (INT16)(gWeaponStats[ 19 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 19 ].sY + gsInvDescY, pStr ); - } - - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus ) - { - // BURST PENALTY MODIFIER - // equals SetFontForeground( 6 ); - mprintf( gWeaponStats[ 41 ].sX + gsInvDescX, gWeaponStats[ 41 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - // determine value - INT16 iBurstBonus = 0; - iBurstBonus = Item[ gpItemDescObject->usItem ].bursttohitbonus; + ///////////////// ARMOR PIERCING + { + // Set line to draw into + ubNumLine = 0; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; - // determine value print color - SetFontForeground( 5 ); - if ( iBurstBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iBurstBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iBurstBonus > 0 ) - { - swprintf( pStr, L"%+2d", iBurstBonus ); - } - else - { - swprintf( pStr, L"%2d", iBurstBonus ); + // Get final Penetration + FLOAT fArmourImpactReduction = 1.0f / ((FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].armourImpactReductionMultiplier / (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].armourImpactReductionDivisor); + + // Get base Penetration + FLOAT fFinalArmourImpactReduction = fArmourImpactReduction; + + // Print base value + SetFontForeground( 5 ); + if ( fArmourImpactReduction < 1.0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( fArmourImpactReduction > 1.0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%3.1f", fArmourImpactReduction ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%3.1f", fFinalArmourImpactReduction ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 20 ].sX + gsInvDescX + gWeaponStats[ 20 ].sValDx), (INT16)(gWeaponStats[ 20 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 20 ].sY + gsInvDescY, pStr ); + ///////////////////// TUMBLING + { + // Set line to draw into + ubNumLine = 1; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + + // Get final Tumbling + FLOAT fAfterArmourImpactReduction = (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].afterArmourDamageMultiplier / (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].afterArmourDamageDivisor; + + // Get base Tumbling + FLOAT fFinalAfterArmourImpactReduction = fAfterArmourImpactReduction; + + // Print base value + SetFontForeground( 5 ); + if ( fAfterArmourImpactReduction < 1.0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( fAfterArmourImpactReduction > 1.0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%3.1f", fAfterArmourImpactReduction ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%3.1f", fFinalAfterArmourImpactReduction ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ///////////////////// PRE-ARMOR EXPLOSION + { + // Set line to draw into + ubNumLine = 2; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final Explosion + FLOAT fPreArmourImpactReduction = (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].beforeArmourDamageMultiplier / (FLOAT) AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].beforeArmourDamageDivisor; + + // Get base Explosion + FLOAT fFinalPreArmourImpactReduction = fPreArmourImpactReduction; + + // Print base value + SetFontForeground( 5 ); + if ( fPreArmourImpactReduction < 1.0 ) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( fPreArmourImpactReduction > 1.0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%3.1f", fPreArmourImpactReduction ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%3.1f", fFinalPreArmourImpactReduction ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } } - - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 ) + else if (gubDescBoxPage == 2) { - // AMMO RELIABILITY BONUS - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 42 ].sX + gsInvDescX, gWeaponStats[ 42 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iReliabilityBonus = 0; - iReliabilityBonus = Item[ gpItemDescObject->usItem ].bReliability; - - // determine value print color - SetFontForeground( 5 ); - if ( iReliabilityBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iReliabilityBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iReliabilityBonus > 0 ) - { - swprintf( pStr, L"%+2d", iReliabilityBonus ); - } - else - { - swprintf( pStr, L"%2d", iReliabilityBonus ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 21 ].sX + gsInvDescX + gWeaponStats[ 21 ].sValDx), (INT16)(gWeaponStats[ 21 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 21 ].sY + gsInvDescY, pStr ); - } - - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction > 0 ) - { - // AMMO NOISE SUPPRESSION - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 41 ].sX + gsInvDescX, gWeaponStats[ 41 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iNoiseSuppression = 0; - iNoiseSuppression = Item[ gpItemDescObject->usItem ].percentnoisereduction * -1; - - SetFontForeground( 5 ); - if ( iNoiseSuppression > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iNoiseSuppression < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iNoiseSuppression > 0 ) - { - swprintf( pStr, L"%+2d%%", iNoiseSuppression ); - } - else - { - swprintf( pStr, L"%2d%%", iNoiseSuppression ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 22 ].sX + gsInvDescX + gWeaponStats[ 22 ].sValDx), (INT16)(gWeaponStats[ 22 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 22 ].sY + gsInvDescY, pStr ); + DrawAdvancedValues( gpItemDescObject ); } } @@ -5146,145 +6171,392 @@ void DrawExplosiveValues( OBJECTTYPE * gpItemDescObject ) { static CHAR16 pStr[ 100 ]; INT16 usY; - INT16 sStrX; - UINT16 uiStringLength; + INT16 usX; + UINT8 ubNumLine; + INT16 sLeft, sTop, sWidth, sHeight; if( UsingEDBSystem() == 0 ) return; - // DAMAGE - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage > 0 ) + if (gubDescBoxPage == 1) { - // equals + ////////////////////////////////////////////////// HEADERS + + SetFontForeground( FONT_MCOLOR_WHITE ); + + // "PRIMARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 0 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sTop, gItemDescGenHeaderRegions[0].sRight - gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sBottom - gItemDescGenHeaderRegions[0].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); + + // "SECONDARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 1 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sTop, gItemDescGenHeaderRegions[1].sRight - gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sBottom - gItemDescGenHeaderRegions[1].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); + SetFontForeground( 6 ); - mprintf( gWeaponStats[ 23 ].sX + gsInvDescX, gWeaponStats[ 23 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - // print value - SetFontForeground( 5 ); - - // HEADROCK HAM 3.6: Can now use negative modifier. - UINT16 explDamage = (UINT16) GetModifiedExplosiveDamage( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage ); + ///////////////////////////////////////////////////// INDEXES - //swprintf( pStr, L"%2d", Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage + ( (Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage * gGameExternalOptions.ubExplosivesDamageMultiplier ) / 100 )); - swprintf( pStr, L"%2d", explDamage ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 2 ].sX + gsInvDescX + gWeaponStats[ 2 ].sValDx), (INT16)(gWeaponStats[ 2 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 2 ].sY + gsInvDescY, pStr ); - } + SetFontForeground( FONT_MCOLOR_WHITE ); - // STUN DAMAGE - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage > 0 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 24 ].sX + gsInvDescX, gWeaponStats[ 24 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - - // HEADROCK HAM 3.6: Can now use negative modifier. - UINT16 explStunDamage = (UINT16) GetModifiedExplosiveDamage( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage ); - - //swprintf( pStr, L"%2d", Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage + ( (Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage * gGameExternalOptions.ubExplosivesDamageMultiplier ) / 100 )); - swprintf( pStr, L"%2d", explStunDamage ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 3 ].sX + gsInvDescX + gWeaponStats[ 3 ].sValDx), (INT16)(gWeaponStats[ 3 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 3 ].sY + gsInvDescY, pStr ); - } - - // LOUDNESS - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 25 ].sX + gsInvDescX, gWeaponStats[ 25 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolume ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 4 ].sX + gsInvDescX + gWeaponStats[ 4 ].sValDx), (INT16)(gWeaponStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 4 ].sY + gsInvDescY, pStr ); - - // VOLATILITY - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility > 0 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 26 ].sX + gsInvDescX, gWeaponStats[ 26 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 5 ].sX + gsInvDescX + gWeaponStats[ 5 ].sValDx), (INT16)(gWeaponStats[ 5 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 5 ].sY + gsInvDescY, pStr ); - } - - // SINGLE-EVENT EXPLOSION data - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 ) - { - // BLAST RADIUS - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 24 ].sX + gsInvDescX, gWeaponStats[ 24 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%d", 1 + ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubRadius * 2 ) ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontCenterCoordinates( (INT16)(gWeaponStats[ 45 ].sX + gsInvDescX), (INT16)(gWeaponStats[ 45 ].sY + gsInvDescY ), 12 ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 45 ].sY + gsInvDescY, pStr ); - - } - // PROLONGED EXPLOSION data - else if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) - { - // DURATION - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 34 ].sX + gsInvDescX, gWeaponStats[ 34 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 13 ].sX + gsInvDescX + gWeaponStats[ 13 ].sValDx), (INT16)(gWeaponStats[ 13 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 13 ].sY + gsInvDescY, pStr ); - - // Headrock: this integer contains the number of the array item that contains the location - // in which to display each radius value. If the explosive is a light, the values are displayed - // in reverse locations. - - INT16 isLightLocation = 0; - - if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 4 ) + for (UINT8 cnt = 0; cnt < 4; cnt++) { - isLightLocation = 2; + // Select "PROPERTY", "0", "+" or "=" as appropriate. + swprintf(pStr, L"%s", gzItemDescGenIndexes[ cnt ]); + + FindFontCenterCoordinates( gItemDescGenIndexRegions[0][cnt].sLeft, gItemDescGenIndexRegions[0][cnt].sTop, gItemDescGenIndexRegions[0][cnt].sRight - gItemDescGenIndexRegions[0][cnt].sLeft, gItemDescGenIndexRegions[0][cnt].sBottom - gItemDescGenIndexRegions[0][cnt].sTop, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } - // STARTING RADIUS - // equals SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 33 ].sX + gsInvDescX, gWeaponStats[ 33 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%d", 1 + ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStartRadius * 2) ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontCenterCoordinates( (INT16)(gWeaponStats[ 44+isLightLocation ].sX + gsInvDescX), (INT16)(gWeaponStats[ 44+isLightLocation ].sY + gsInvDescY ), 12 ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 44+isLightLocation ].sY + gsInvDescY, pStr ); + ////////////////// DAMAGE + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage > 0 ) + { + // Set line to draw into + ubNumLine = 0; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; - // FINAL RADIUS - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 33 ].sX + gsInvDescX, gWeaponStats[ 33 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + // Get final damage + INT16 iFinalDamage = GetModifiedExplosiveDamage( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDamage ); - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%d", 1 + ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubRadius * 2) ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontCenterCoordinates( (INT16)(gWeaponStats[ 46-isLightLocation ].sX + gsInvDescX), (INT16)(gWeaponStats[ 46-isLightLocation ].sY + gsInvDescY ), 12 ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 46-isLightLocation ].sY + gsInvDescY, pStr ); + // Get base damage + INT16 iDamage = iFinalDamage; + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iDamage ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalDamage ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + /////////////////// STUN DAMAGE + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage > 0 ) + { + // Set line to draw into + ubNumLine = 1; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final damage + INT16 iFinalStunDamage = GetModifiedExplosiveDamage( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStunDamage); + + // Get base damage + INT16 iStunDamage = iFinalStunDamage; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iStunDamage ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalStunDamage ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ////////////////////// BLAST RADIUS + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration == 0 ) + { + // Set line to draw into + ubNumLine = 2; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final damage + INT16 iFinalBlastRadius = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubRadius; + + // Get base damage + INT16 iBlastRadius = iFinalBlastRadius; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iBlastRadius ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalBlastRadius ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ////////////////////// PROLONGED EFFECT: START + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) + { + // Set line to draw into + ubNumLine = 2; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + INT16 iFinalEffectStartRadius; + // Get final damage + if (Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 4) + { + iFinalEffectStartRadius = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubRadius; + } + else + { + iFinalEffectStartRadius = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStartRadius; + } + + // Get base damage + INT16 iEffectStartRadius = iFinalEffectStartRadius; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iEffectStartRadius ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalEffectStartRadius ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ////////////////////// PROLONGED EFFECT: END + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) + { + // Set line to draw into + ubNumLine = 3; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + INT16 iFinalEffectEndRadius; + // Get final damage + if (Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubType == 4) + { + iFinalEffectEndRadius = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubStartRadius; + } + else + { + iFinalEffectEndRadius = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubRadius; + } + + // Get base damage + INT16 iEffectEndRadius = iFinalEffectEndRadius; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iEffectEndRadius ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalEffectEndRadius ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + ////////////////////// PROLONGED EFFECT: DURATION + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration > 0 ) + { + // Set line to draw into + ubNumLine = 4; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final damage + INT16 iFinalEffectDuration = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDuration; + + // Get base damage + INT16 iEffectDuration = iFinalEffectDuration; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iEffectDuration ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalEffectDuration ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + //////////////////// LOUDNESS + { + // Set line to draw into + ubNumLine = 5; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final damage + INT16 iFinalLoudness = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolume; + + // Get base damage + INT16 iLoudness = iFinalLoudness; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iLoudness ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalLoudness ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + + //////////////////// VOLATILITY + if ( Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility > 0 ) + { + // Set line to draw into + ubNumLine = 6; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get final damage + INT16 iFinalVolatility = Explosive[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubVolatility; + + // Get base damage + INT16 iVolatility = iFinalVolatility; + + // Print base value + SetFontForeground( 5 ); + + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iVolatility ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // no modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalVolatility ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + } + else if (gubDescBoxPage == 2) + { + DrawAdvancedValues( gpItemDescObject ); } } @@ -5292,1872 +6564,2392 @@ void DrawArmorValues( OBJECTTYPE * gpItemDescObject ) { static CHAR16 pStr[ 100 ]; INT16 usY; - INT16 sStrX; - UINT16 uiStringLength; + INT16 usX; + UINT8 ubNumLine; + INT16 sLeft, sTop, sWidth, sHeight; if( UsingEDBSystem() == 0 ) return; - // ARMOR VALUE - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 23 ].sX + gsInvDescX, gWeaponStats[ 23 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + ////////////////////////////////////////////////////////////////////////////////////////// + // The following attributes are only drawn when the UDB is set to show the General Page. - // print value - SetFontForeground( 5 ); - - // Calculate Value including attachments - UINT16 iProtection = 0; - iProtection = Armour[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubProtection; - - for (attachmentList::iterator iter = (*gpItemDescObject)[0]->attachments.begin(); iter != (*gpItemDescObject)[0]->attachments.end(); ++iter) + if (gubDescBoxPage == 1) { - if (Item[ iter->usItem ].usItemClass == IC_ARMOUR) - { - iProtection += Armour[Item[iter->usItem].ubClassIndex].ubProtection; - } - } + ////////////////////////////////////////////////// HEADERS - swprintf( pStr, L"%2d", iProtection ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 2 ].sX + gsInvDescX + gWeaponStats[ 2 ].sValDx), (INT16)(gWeaponStats[ 2 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - //wcscat( pStr, L"%%" ); - mprintf( sStrX, gWeaponStats[ 2 ].sY + gsInvDescY, pStr ); + SetFontForeground( FONT_MCOLOR_WHITE ); - // ARMOR COVERAGE - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 23 ].sX + gsInvDescX, gWeaponStats[ 23 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + // "PRIMARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 0 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sTop, gItemDescGenHeaderRegions[0].sRight - gItemDescGenHeaderRegions[0].sLeft, gItemDescGenHeaderRegions[0].sBottom - gItemDescGenHeaderRegions[0].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d%%", Armour[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubCoverage ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 3 ].sX + gsInvDescX + gWeaponStats[ 3 ].sValDx), (INT16)(gWeaponStats[ 3 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif + // "SECONDARY" header + swprintf( pStr, L"%s", gzItemDescGenHeaders[ 1 ] ); + FindFontCenterCoordinates( gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sTop, gItemDescGenHeaderRegions[1].sRight - gItemDescGenHeaderRegions[1].sLeft, gItemDescGenHeaderRegions[1].sBottom - gItemDescGenHeaderRegions[1].sTop, pStr, BLOCKFONT2, &usX, &usY ); + mprintf( usX, usY, pStr ); - mprintf( sStrX, gWeaponStats[ 3 ].sY + gsInvDescY, pStr ); - - // ARMOR DEGRADE - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 25 ].sX + gsInvDescX, gWeaponStats[ 25 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d", Armour[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDegradePercent ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 4 ].sX + gsInvDescX + gWeaponStats[ 4 ].sValDx), (INT16)(gWeaponStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 4 ].sY + gsInvDescY, pStr ); - - // AP BONUS - if ( GetAPBonus ( gpItemDescObject ) != 0 ) - { - // equals SetFontForeground( 6 ); - mprintf( gWeaponStats[ 30 ].sX + gsInvDescX, gWeaponStats[ 30 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - // determine value - INT16 iAPBonus = 0; - iAPBonus = GetAPBonus( gpItemDescObject ); - - // determine value print color - SetFontForeground( 5 ); - if ( iAPBonus < 0 ) + ///////////////////////////////////////////////////// INDEXES + + SetFontForeground( FONT_MCOLOR_WHITE ); + + for (UINT8 cnt = 0; cnt < 4; cnt++) { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Select "PROPERTY", "0", "+" or "=" as appropriate. + swprintf(pStr, L"%s", gzItemDescGenIndexes[ cnt ]); + + FindFontCenterCoordinates( gItemDescGenIndexRegions[0][cnt].sLeft, gItemDescGenIndexRegions[0][cnt].sTop, gItemDescGenIndexRegions[0][cnt].sRight - gItemDescGenIndexRegions[0][cnt].sLeft, gItemDescGenIndexRegions[0][cnt].sBottom - gItemDescGenIndexRegions[0][cnt].sTop, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } - else if ( iAPBonus > 0 ) + + SetFontForeground( 6 ); + + /////////////////// PROTECTION { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); + // Set line to draw into + ubNumLine = 0; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get protection value + UINT16 iProtectionValue = Armour[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubProtection; + + // Get Final Protection value + UINT16 iFinalProtectionValue = iProtectionValue; + for (attachmentList::iterator iter = (*gpItemDescObject)[0]->attachments.begin(); iter != (*gpItemDescObject)[0]->attachments.end(); ++iter) + { + if (Item[ iter->usItem ].usItemClass == IC_ARMOUR) + { + iFinalProtectionValue += Armour[Item[iter->usItem].ubClassIndex].ubProtection; + } + } + + // Get difference + INT16 iProtectionModifier = iFinalProtectionValue - iProtectionValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iProtectionValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + if (iProtectionModifier < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + } + else if ( iProtectionModifier > 0 ) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + } + // Add positive/negative sign + if ( iProtectionModifier > 0 ) + { + swprintf( pStr, L"+%d", iProtectionModifier ); + } + else if ( iProtectionModifier < 0 ) + { + swprintf( pStr, L"%d", iProtectionModifier ); + } + else + { + swprintf( pStr, L"--" ); + } + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalProtectionValue ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); } - - // print value - if ( iAPBonus > 0 ) + + /////////////////// COVERAGE { - swprintf( pStr, L"%+2d", iAPBonus ); + // Set line to draw into + ubNumLine = 1; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get Coverage value + UINT8 iCoverageValue = Armour[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubCoverage; + + // Get Final Coverage value + UINT8 iFinalCoverageValue = iCoverageValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iCoverageValue ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalCoverageValue ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); } - else + + //////////////////// DEGRADE RATE { - swprintf( pStr, L"%2d", iAPBonus ); + // Set line to draw into + ubNumLine = 2; + // Set Y coordinates + sTop = gItemDescGenRegions[ubNumLine][1].sTop; + sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop; + + // Get Degrade value + UINT8 iDegradeValue = Armour[Item[ gpItemDescObject->usItem ].ubClassIndex ].ubDegradePercent; + + // Get Final Degrade value + UINT8 iFinalDegradeValue = iDegradeValue; + + // Print base value + SetFontForeground( 5 ); + sLeft = gItemDescGenRegions[ubNumLine][1].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft; + swprintf( pStr, L"%d", iDegradeValue ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + mprintf( usX, usY, pStr ); + + // Print modifier + SetFontForeground( 5 ); + swprintf( pStr, L"--" ); + sLeft = gItemDescGenRegions[ubNumLine][2].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + // Print final value + SetFontForeground( FONT_MCOLOR_WHITE ); + sLeft = gItemDescGenRegions[ubNumLine][3].sLeft; + sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft; + swprintf( pStr, L"%d", iFinalDegradeValue ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + mprintf( usX, usY, pStr ); + + // Reset font color + SetFontForeground( 6 ); } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 9 ].sX + gsInvDescX + gWeaponStats[ 9 ].sValDx), (INT16)(gWeaponStats[ 9 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 9 ].sY + gsInvDescY, pStr ); + } + else if (gubDescBoxPage == 2) + { + DrawAdvancedValues( gpItemDescObject ); + } +} + +void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject ) +{ + if (gubDescBoxPage != 2) + { + return; } - // AIM BONUS - if ( GetFlatAimBonus( gpItemDescObject ) != 0 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 31 ].sX + gsInvDescX, gWeaponStats[ 31 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + INT16 sFirstLine = gubDescBoxLine; + INT16 sLastLine = gubDescBoxLine + NUM_UDB_ADV_LINES; + INT16 cnt = 0; - // determine value - INT16 iAimBonus = 0; - iAimBonus = GetFlatAimBonus( gpItemDescObject ); - - // determine value print color - SetFontForeground( 5 ); - if ( iAimBonus < 0 ) + static CHAR16 pStr[ 100 ]; + INT16 usY; + INT16 usX; + INT16 sLeft, sTop, sWidth, sHeight; + + INT16 iModifier[3]; + FLOAT iFloatModifier[3]; + + INT8 bDummyValue; + INT8 bRecoilModifier; + + ///////////////////// INDEX + swprintf( pStr, gzItemDescGenIndexes[0] ); + sLeft = gItemDescAdvIndexRegions[0][0].sLeft; + sTop = gItemDescAdvIndexRegions[0][0].sTop; + sWidth = gItemDescAdvIndexRegions[0][0].sRight - sLeft; + sHeight = gItemDescAdvIndexRegions[0][0].sBottom - sTop; + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + SetFontForeground( FONT_MCOLOR_WHITE ); + mprintf( usX, usY, pStr ); + + ///////////////////// ACCURACY MODIFIER + iModifier[0] = GetAccuracyModifier( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 && UsingNewCTHSystem() == true) + { + if (cnt >= sFirstLine && cnt < sLastLine) { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iAimBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAimBonus > 0 ) - { - swprintf( pStr, L"%+2d", iAimBonus ); - } - else - { - swprintf( pStr, L"%2d", iAimBonus ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 10 ].sX + gsInvDescX + gWeaponStats[ 10 ].sValDx), (INT16)(gWeaponStats[ 10 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 10 ].sY + gsInvDescY, pStr ); + cnt++; } - // WOODLAND CAMO - if ( GetCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// FLAT BASE MODIFIER + iModifier[0] = GetFlatBaseModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetFlatBaseModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetFlatBaseModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 31 ].sX + gsInvDescX, gWeaponStats[ 31 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // print value - SetFontForeground( 5 ); - if ( GetCamoBonus( gpItemDescObject ) < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( GetCamoBonus( gpItemDescObject ) > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( GetCamoBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d%%", GetCamoBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d%%", GetCamoBonus( gpItemDescObject ) ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 11 ].sX + gsInvDescX + gWeaponStats[ 11 ].sValDx), (INT16)(gWeaponStats[ 11 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 11 ].sY + gsInvDescY, pStr ); + cnt++; } - // URBAN CAMO - if ( GetUrbanCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// PERCENT BASE MODIFIER + iModifier[0] = GetPercentBaseModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetPercentBaseModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetPercentBaseModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 32 ].sX + gsInvDescX, gWeaponStats[ 32 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // print value - SetFontForeground( 5 ); - if ( GetUrbanCamoBonus( gpItemDescObject ) < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( GetUrbanCamoBonus( gpItemDescObject ) > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( GetUrbanCamoBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d%%", GetUrbanCamoBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d%%", GetUrbanCamoBonus( gpItemDescObject ) ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 12 ].sX + gsInvDescX + gWeaponStats[ 12 ].sValDx), (INT16)(gWeaponStats[ 12 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 12 ].sY + gsInvDescY, pStr ); + cnt++; } - // DESERT CAMO - if ( GetDesertCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// FLAT AIM MODIFIER + iModifier[0] = GetFlatAimModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetFlatAimModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetFlatAimModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 34 ].sX + gsInvDescX, gWeaponStats[ 34 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // print value - SetFontForeground( 5 ); - if ( GetDesertCamoBonus( gpItemDescObject ) < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( GetDesertCamoBonus( gpItemDescObject ) > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( GetDesertCamoBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d%%", GetDesertCamoBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d%%", GetDesertCamoBonus( gpItemDescObject ) ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 13 ].sX + gsInvDescX + gWeaponStats[ 13 ].sValDx), (INT16)(gWeaponStats[ 13 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 13 ].sY + gsInvDescY, pStr ); + cnt++; } - // SNOW CAMO - if ( GetSnowCamoBonus( gpItemDescObject ) > 0 ) + ///////////////////// PERCENT AIM MODIFIER + iModifier[0] = GetPercentAimModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetPercentAimModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetPercentAimModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 35 ].sX + gsInvDescX, gWeaponStats[ 35 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // print value - SetFontForeground( 5 ); - if ( GetSnowCamoBonus( gpItemDescObject ) < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( GetSnowCamoBonus( gpItemDescObject ) > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( GetSnowCamoBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d%%", GetSnowCamoBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d%%", GetSnowCamoBonus( gpItemDescObject ) ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 14 ].sX + gsInvDescX + gWeaponStats[ 14 ].sValDx), (INT16)(gWeaponStats[ 14 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 14 ].sY + gsInvDescY, pStr ); + cnt++; } - // STEALTH - if ( GetBasicStealthBonus( gpItemDescObject ) != 0 ) + ///////////////////// AIMING LEVELS MODIFIER + iModifier[0] = GetAimLevelsModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetAimLevelsModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetAimLevelsModifier( gpItemDescObject, ANIM_PRONE ); + if (iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0 ) { - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 35 ].sX + gsInvDescX, gWeaponStats[ 35 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // print value - SetFontForeground( 5 ); - if ( GetBasicStealthBonus( gpItemDescObject ) < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( GetBasicStealthBonus( gpItemDescObject ) > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( GetBasicStealthBonus( gpItemDescObject ) > 0 ) - { - swprintf( pStr, L"%+2d%%", GetBasicStealthBonus( gpItemDescObject ) ); - } - else - { - swprintf( pStr, L"%2d%%", GetBasicStealthBonus( gpItemDescObject ) ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 15 ].sX + gsInvDescX + gWeaponStats[ 15 ].sValDx), (INT16)(gWeaponStats[ 15 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 15 ].sY + gsInvDescY, pStr ); + cnt++; } - // VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].visionrangebonus != 0 ) + ///////////////////// CTH CAP MODIFIER + iModifier[0] = GetPercentCapModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetPercentCapModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetPercentCapModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 37 ].sX + gsInvDescX, gWeaponStats[ 37 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // determine value - INT16 iVisionRangeBonus = 0; - iVisionRangeBonus = Item[ gpItemDescObject->usItem ].visionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iVisionRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iVisionRangeBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iVisionRangeBonus > 0 ) - { - swprintf( pStr, L"%+2d", iVisionRangeBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iVisionRangeBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 16 ].sX + gsInvDescX + gWeaponStats[ 16 ].sValDx), (INT16)(gWeaponStats[ 16 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 16 ].sY + gsInvDescY, pStr ); + cnt++; } - // DAY VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].dayvisionrangebonus != 0 ) + ///////////////////// GUN HANDLING MODIFIER + iModifier[0] = GetPercentHandlingModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetPercentHandlingModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetPercentHandlingModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 38 ].sX + gsInvDescX, gWeaponStats[ 38 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // determine value - INT16 iVisionRangeBonus = 0; - iVisionRangeBonus = Item[ gpItemDescObject->usItem ].dayvisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iVisionRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iVisionRangeBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iVisionRangeBonus > 0 ) - { - swprintf( pStr, L"%+2d", iVisionRangeBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iVisionRangeBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 17 ].sX + gsInvDescX + gWeaponStats[ 17 ].sValDx), (INT16)(gWeaponStats[ 17 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 17 ].sY + gsInvDescY, pStr ); + cnt++; } - // NIGHT VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].nightvisionrangebonus != 0 ) + ///////////////////// DROP COMPENSATION MODIFIER + iModifier[0] = GetDropCompensationModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetDropCompensationModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetDropCompensationModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 39 ].sX + gsInvDescX, gWeaponStats[ 39 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // determine value - INT16 iVisionRangeBonus = 0; - iVisionRangeBonus = Item[ gpItemDescObject->usItem ].nightvisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iVisionRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iVisionRangeBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iVisionRangeBonus > 0 ) - { - swprintf( pStr, L"%+2d", iVisionRangeBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iVisionRangeBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 18 ].sX + gsInvDescX + gWeaponStats[ 18 ].sValDx), (INT16)(gWeaponStats[ 18 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 18 ].sY + gsInvDescY, pStr ); + cnt++; } - // BRIGHT LIGHT VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus != 0 ) + ///////////////////// TARGET TRACKING MODIFIER + iModifier[0] = GetTargetTrackingModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetTargetTrackingModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetTargetTrackingModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 40 ].sX + gsInvDescX, gWeaponStats[ 40 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // determine value - INT16 iVisionRangeBonus = 0; - iVisionRangeBonus = Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iVisionRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iVisionRangeBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iVisionRangeBonus > 0 ) - { - swprintf( pStr, L"%+2d", iVisionRangeBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iVisionRangeBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 19 ].sX + gsInvDescX + gWeaponStats[ 19 ].sValDx), (INT16)(gWeaponStats[ 19 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 19 ].sY + gsInvDescY, pStr ); + cnt++; } - // CAVE VISION RANGE BONUS ICON - if ( Item[ gpItemDescObject->usItem ].cavevisionrangebonus != 0 ) + ///////////////////// DAMAGE MODIFIER + if (Item[gpItemDescObject->usItem].usItemClass & (IC_GUN|IC_THROWING_KNIFE)) + iModifier[0] = (GetDamageBonus( gpItemDescObject ) * gGameExternalOptions.iGunDamageModifier) / 100; + else if (Item[gpItemDescObject->usItem].usItemClass & (IC_BLADE|IC_PUNCH)) + iModifier[0] = (GetDamageBonus( gpItemDescObject ) * gGameExternalOptions.iMeleeDamageModifier) / 100; + else if (Item[gpItemDescObject->usItem].usItemClass & (IC_EXPLOSV|IC_LAUNCHER)) + iModifier[0] = (GetDamageBonus( gpItemDescObject ) * gGameExternalOptions.iExplosivesDamageModifier) / 100; + else + iModifier[0] = GetDamageBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 41 ].sX + gsInvDescX, gWeaponStats[ 41 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // determine value - INT16 iVisionRangeBonus = 0; - iVisionRangeBonus = Item[ gpItemDescObject->usItem ].cavevisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iVisionRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iVisionRangeBonus > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iVisionRangeBonus > 0 ) - { - swprintf( pStr, L"%+2d", iVisionRangeBonus / 10 ); - } - else - { - swprintf( pStr, L"%2d", iVisionRangeBonus / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 20 ].sX + gsInvDescX + gWeaponStats[ 20 ].sValDx), (INT16)(gWeaponStats[ 20 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 20 ].sY + gsInvDescY, pStr ); + cnt++; } - // PERCENT TUNNEL VISION ICON - if ( Item[ gpItemDescObject->usItem ].percenttunnelvision > 0 ) + ///////////////////// MELEE DAMAGE MODIFIER + iModifier[0] = GetMeleeDamageBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) { - // equals - SetFontForeground( 6 ); - //mprintf( gWeaponStats[ 34 ].sX + gsInvDescX, gWeaponStats[ 34 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // print value - SetFontForeground( 5 ); - swprintf( pStr, L"%2d%%", Item[ gpItemDescObject->usItem ].percenttunnelvision ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 21 ].sX + gsInvDescX + gWeaponStats[ 21 ].sValDx), (INT16)(gWeaponStats[ 21 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gWeaponStats[ 21 ].sY + gsInvDescY, pStr ); + cnt++; } - // HEARING RANGE BONUS ICON - if ( GetItemHearingRangeBonus( gpItemDescObject ) != 0 ) + ///////////////////// RANGE MODIFIER + iModifier[0] = GetRangeBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) { - // equals - SetFontForeground( 6 ); - mprintf( gWeaponStats[ 42 ].sX + gsInvDescX, gWeaponStats[ 42 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; - // determine value - INT16 iHearingRangeBonus = 0; - iHearingRangeBonus = GetItemHearingRangeBonus( gpItemDescObject ); - - // determine value print color - SetFontForeground( 5 ); - if ( iHearingRangeBonus < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else if ( iHearingRangeBonus > 0 ) + cnt++; + } + + ///////////////////// SCOPE MAGNIFICATION + iFloatModifier[0] = GetHighestScopeMagnificationFactor( gpItemDescObject ); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] > 1.0 && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 1.0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%3.1fx", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"1.0x" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - - // print value - if ( iHearingRangeBonus > 0 ) + cnt++; + } + + ///////////////////// PROJECTION FACTOR + iFloatModifier[0] = GetProjectionFactor( gpItemDescObject ); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] > 1.0 && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) { - swprintf( pStr, L"%+2d", iHearingRangeBonus / 10 ); + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 1.0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%3.1fx", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"1.0x" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - else + cnt++; + } + + ///////////////////// LATERAL RECOIL MODIFIER + GetFlatRecoilModifier( gpItemDescObject, &bRecoilModifier, &bDummyValue ); + iModifier[0] = bRecoilModifier; + iModifier[1] = bRecoilModifier; + iModifier[2] = bRecoilModifier; + if (iModifier[0] != 0 && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) { - swprintf( pStr, L"%2d", iHearingRangeBonus / 10 ); + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 22 ].sX + gsInvDescX + gWeaponStats[ 22 ].sValDx), (INT16)(gWeaponStats[ 22 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 22 ].sY + gsInvDescY, pStr ); + cnt++; + } + + ///////////////////// VERTICAL RECOIL MODIFIER + GetFlatRecoilModifier( gpItemDescObject, &bDummyValue, &bRecoilModifier ); + iModifier[0] = bRecoilModifier; + iModifier[1] = bRecoilModifier; + iModifier[2] = bRecoilModifier; + if (iModifier[0] != 0 && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// MAX COUNTER FORCE MODIFIER + iModifier[0] = GetCounterForceMaxModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetCounterForceMaxModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetCounterForceMaxModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// COUNTER FORCE ACCURACY MODIFIER + iModifier[0] = GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetCounterForceAccuracyModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// COUNTER FORCE FREQUENCY MODIFIER + iModifier[0] = GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_STAND ); + iModifier[1] = GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_CROUCH ); + iModifier[2] = GetCounterForceFrequencyModifier( gpItemDescObject, ANIM_PRONE ); + if ((iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0) && UsingNewCTHSystem() == true ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// AP MODIFIER + iModifier[0] = GetAPBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// DRAW AP MODIFIER + iModifier[0] = GetPercentReadyTimeAPReduction( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"-%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", abs(iModifier[cnt2]) ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// SINGLE-ATTACK AP MODIFIER + iModifier[0] = GetPercentAPReduction( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"-%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", abs(iModifier[cnt2]) ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// BURST AP MODIFIER + iModifier[0] = GetPercentBurstFireAPReduction( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"-%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", abs(iModifier[cnt2]) ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// AUTOFIRE AP MODIFIER + iModifier[0] = GetPercentAutofireAPReduction( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"-%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", abs(iModifier[cnt2]) ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// RELOAD AP MODIFIER + iModifier[0] = GetPercentReloadTimeAPReduction( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"-%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", abs(iModifier[cnt2]) ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// MAGAZINE SIZE MODIFIER + iModifier[0] = GetMagSizeBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// BURST SIZE MODIFIER + iModifier[0] = GetBurstSizeBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// HIDE MUZZLE FLASH + iModifier[0] = IsFlashSuppressorAlt( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2]) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"Y", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// LOUDNESS MODIFIER + iModifier[0] = GetPercentNoiseVolume( gpItemDescObject )-100; + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", abs(iModifier[cnt2]) ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// ITEM SIZE MODIFIER + iModifier[0] = CalculateItemSize( gpItemDescObject ) - Item[ gpItemDescObject->usItem ].ItemSize; + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// RELIABILITY MODIFIER + iModifier[0] = GetReliability( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (!(Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_PUNCH|IC_ARMOUR|IC_EXPLOSV)) && + iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// WOODLAND CAMO + iModifier[0] = GetCamoBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// URBAN CAMO + iModifier[0] = GetUrbanCamoBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// DESERT CAMO + iModifier[0] = GetDesertCamoBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// SNOW CAMO + iModifier[0] = GetSnowCamoBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// STEALTH MODIFIER + iModifier[0] = GetStealthBonus( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// HEARING RANGE MODIFIER + iFloatModifier[0] = (GetItemHearingRangeBonus( gpItemDescObject ) / 10.0f); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iFloatModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// VISION RANGE MODIFIER + iFloatModifier[0] = (GetItemVisionRangeBonus( gpItemDescObject, 0 ) / 10.0f); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iFloatModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// NIGHT VISION RANGE MODIFIER + iFloatModifier[0] = (GetItemVisionRangeBonus( gpItemDescObject, 2 ) / 10.0f); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iFloatModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// DAY VISION RANGE MODIFIER + iFloatModifier[0] = (GetItemVisionRangeBonus( gpItemDescObject, 1 ) / 10.0f); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iFloatModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// BRIGHT LIGHT VISION RANGE MODIFIER + iFloatModifier[0] = (GetItemVisionRangeBonus( gpItemDescObject, 3 ) / 10.0f); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iFloatModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// CAVE VISION RANGE MODIFIER + iFloatModifier[0] = (GetItemVisionRangeBonus( gpItemDescObject, 4 ) / 10.0f); + iFloatModifier[1] = iFloatModifier[0]; + iFloatModifier[2] = iFloatModifier[0]; + if (iFloatModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iFloatModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"+%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else if (iFloatModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; + } + + ///////////////////// PERCENT TUNNEL VISION + iModifier[0] = GetItemPercentTunnelVision( gpItemDescObject ); + iModifier[1] = iModifier[0]; + iModifier[2] = iModifier[0]; + if (iModifier[0] != 0 ) + { + if (cnt >= sFirstLine && cnt < sLastLine) + { + // Set Y coordinates + sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop; + sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop; + + // Print Values + for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++) + { + if (UsingNewCTHSystem() == false && cnt2 > 0) + break; + SetFontForeground( 5 ); + sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft; + sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft; + if (iModifier[cnt2] > 0) + { + SetFontForeground( ITEMDESC_FONTNEGATIVE ); + swprintf( pStr, L"+%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else if (iModifier[cnt2] < 0) + { + SetFontForeground( ITEMDESC_FONTPOSITIVE ); + swprintf( pStr, L"%d", iModifier[cnt2] ); + wcscat( pStr, L"%" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%" ); + #endif + } + else + { + swprintf( pStr, L"--" ); + FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + } + cnt++; } } void DrawMiscValues( OBJECTTYPE * gpItemDescObject ) { - static CHAR16 pStr[ 100 ]; - INT16 usY; - INT16 sStrX; - UINT16 uiStringLength; - UINT8 cnt; - if( UsingEDBSystem() == 0 ) return; - if(guiCurrentScreen ==MAP_SCREEN) - cnt = 14; - else - cnt = 12; - - // ITEM SIZE MODIFIER - if ( Item[ gpItemDescObject->usItem ].itemsizebonus != 0 && cnt<=27 ) + if (gubDescBoxPage == 2) { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iItemSizeModifier = 0; - iItemSizeModifier = Item[ gpItemDescObject->usItem ].itemsizebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iItemSizeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iItemSizeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iItemSizeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iItemSizeModifier ); - } - else - { - swprintf( pStr, L"%2d", iItemSizeModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // RELIABILITY MODIFIER - if ( Item[ gpItemDescObject->usItem ].bReliability != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iReliabilityModifier = 0; - iReliabilityModifier = Item[ gpItemDescObject->usItem ].bReliability; - - // determine value print color - SetFontForeground( 5 ); - if ( iReliabilityModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iReliabilityModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iReliabilityModifier > 0 ) - { - swprintf( pStr, L"%+2d", iReliabilityModifier ); - } - else - { - swprintf( pStr, L"%2d", iReliabilityModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // NOISE MODIFIER - if ( Item[ gpItemDescObject->usItem ].percentnoisereduction != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iLoudnessModifier = 0; - iLoudnessModifier = Item[ gpItemDescObject->usItem ].percentnoisereduction * -1 ; - - // determine value print color - SetFontForeground( 5 ); - if ( iLoudnessModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iLoudnessModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iLoudnessModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iLoudnessModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iLoudnessModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // HIDE MUZZLE FLASH - // NO DATA SHOWN, icon either appears or does not appear. - // HEADROCK HAM 3.5 - Fixed this, because the count needs to be increased to skip a line! - if ( Item[ gpItemDescObject->usItem ].hidemuzzleflash > 0 && cnt<=27 ) - { - cnt++; - } - - // BIPOD - if ( Item[ gpItemDescObject->usItem ].bipod != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iBipodModifier = 0; - iBipodModifier = Item[ gpItemDescObject->usItem ].bipod; - - // determine value print color - SetFontForeground( 5 ); - if ( iBipodModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iBipodModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iBipodModifier > 0 ) - { - swprintf( pStr, L"%+2d", iBipodModifier ); - } - else - { - swprintf( pStr, L"%2d", iBipodModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // RANGE - if ( Item[ gpItemDescObject->usItem ].rangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iRangeModifier = 0; - iRangeModifier = Item[ gpItemDescObject->usItem ].rangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iRangeModifier / 10 ); - } - else - { - swprintf( pStr, L"%2d", iRangeModifier / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // TO-HIT MODIFIER - if ( Item[ gpItemDescObject->usItem ].tohitbonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iToHitModifier = 0; - iToHitModifier = Item[ gpItemDescObject->usItem ].tohitbonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iToHitModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iToHitModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iToHitModifier > 0 ) - { - swprintf( pStr, L"%+2d", iToHitModifier ); - } - else - { - swprintf( pStr, L"%2d", iToHitModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // LASER RANGE - if ( Item[ gpItemDescObject->usItem ].bestlaserrange > 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iLaserRange = 0; - iLaserRange = Item[ gpItemDescObject->usItem ].bestlaserrange; - - // determine value print color - SetFontForeground( 5 ); - - // print value - swprintf( pStr, L"%2d", iLaserRange / 10 ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // AIMING MODIFIER - if ( Item[ gpItemDescObject->usItem ].aimbonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iAimModifier = 0; - iAimModifier = Item[ gpItemDescObject->usItem ].aimbonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iAimModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iAimModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAimModifier > 0 ) - { - swprintf( pStr, L"%+2d", iAimModifier ); - } - else - { - swprintf( pStr, L"%2d", iAimModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // MINIMUM RANGE FOR AIMING BONUS - if ( Item[ gpItemDescObject->usItem ].minrangeforaimbonus > 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iMinRangeAimingBonus = 0; - iMinRangeAimingBonus = Item[ gpItemDescObject->usItem ].minrangeforaimbonus; - - // determine value print color - SetFontForeground( 5 ); - - // print value - swprintf( pStr, L"%2d", iMinRangeAimingBonus / 10 ); - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // MAGAZINE SIZE MODIFIER - if ( Item[ gpItemDescObject->usItem ].magsizebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iMagSizeModifier = 0; - iMagSizeModifier = Item[ gpItemDescObject->usItem ].magsizebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iMagSizeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iMagSizeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iMagSizeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iMagSizeModifier ); - } - else - { - swprintf( pStr, L"%2d", iMagSizeModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // BURST SIZE MODIFIER - if ( Item[ gpItemDescObject->usItem ].burstsizebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iBurstSizeModifier = 0; - iBurstSizeModifier = Item[ gpItemDescObject->usItem ].burstsizebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iBurstSizeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iBurstSizeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iBurstSizeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iBurstSizeModifier ); - } - else - { - swprintf( pStr, L"%2d", iBurstSizeModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // BURST TO-HIT MODIFIER - if ( Item[ gpItemDescObject->usItem ].bursttohitbonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iBurstToHitModifier = 0; - iBurstToHitModifier = Item[ gpItemDescObject->usItem ].bursttohitbonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iBurstToHitModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iBurstToHitModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iBurstToHitModifier > 0 ) - { - swprintf( pStr, L"%+2d", iBurstToHitModifier ); - } - else - { - swprintf( pStr, L"%2d", iBurstToHitModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // AUTO TO-HIT MODIFIER - if ( Item[ gpItemDescObject->usItem ].autofiretohitbonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iAutoToHitModifier = 0; - iAutoToHitModifier = Item[ gpItemDescObject->usItem ].autofiretohitbonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iAutoToHitModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iAutoToHitModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAutoToHitModifier > 0 ) - { - swprintf( pStr, L"%+2d", iAutoToHitModifier ); - } - else - { - swprintf( pStr, L"%2d", iAutoToHitModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // AP MODIFIER - if ( Item[ gpItemDescObject->usItem ].APBonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iAPModifier = 0; - iAPModifier = Item[ gpItemDescObject->usItem ].APBonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iAPModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iAPModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAPModifier > 0 ) - { - swprintf( pStr, L"%+2d", iAPModifier ); - } - else - { - swprintf( pStr, L"%2d", iAPModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // BURST AP MODIFIER - if ( Item[ gpItemDescObject->usItem ].percentburstfireapreduction != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iBurstAPModifier = 0; - iBurstAPModifier = Item[ gpItemDescObject->usItem ].percentburstfireapreduction * -1 ; - - // determine value print color - SetFontForeground( 5 ); - if ( iBurstAPModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iBurstAPModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iBurstAPModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iBurstAPModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iBurstAPModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // AUTOFIRE AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentautofireapreduction != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iAutoAPModifier = 0; - iAutoAPModifier = Item[ gpItemDescObject->usItem ].percentautofireapreduction * -1 ; - - // determine value print color - SetFontForeground( 5 ); - if ( iAutoAPModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iAutoAPModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iAutoAPModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iAutoAPModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iAutoAPModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // READY AP MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].percentreadytimeapreduction != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iReadyAPModifier = 0; - iReadyAPModifier = Item[ gpItemDescObject->usItem ].percentreadytimeapreduction * -1 ; - - // determine value print color - SetFontForeground( 5 ); - if ( iReadyAPModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iReadyAPModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iReadyAPModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iReadyAPModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iReadyAPModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // RELOAD AP MODIFIER - if ( Item[ gpItemDescObject->usItem ].percentreloadtimeapreduction != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iReloadAPModifier = 0; - iReloadAPModifier = Item[ gpItemDescObject->usItem ].percentreloadtimeapreduction * -1 ; - - // determine value print color - SetFontForeground( 5 ); - if ( iReloadAPModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iReloadAPModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iReloadAPModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iReloadAPModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iReloadAPModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // SINGLE AP MODIFIER - if ( Item[ gpItemDescObject->usItem ].percentapreduction != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iSingleAPModifier = 0; - iSingleAPModifier = Item[ gpItemDescObject->usItem ].percentapreduction * -1 ; - - // determine value print color - SetFontForeground( 5 ); - if ( iSingleAPModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iSingleAPModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iSingleAPModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iSingleAPModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iSingleAPModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // DAMAGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].damagebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iDamageModifier = 0; - iDamageModifier = Item[ gpItemDescObject->usItem ].damagebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iDamageModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iDamageModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iDamageModifier > 0 ) - { - swprintf( pStr, L"%+2d", iDamageModifier ); - } - else - { - swprintf( pStr, L"%2d", iDamageModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // MELEE DAMAGE MODIFIER ICON - if ( Item[ gpItemDescObject->usItem ].meleedamagebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iMeleeDamageModifier = 0; - iMeleeDamageModifier = Item[ gpItemDescObject->usItem ].meleedamagebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iMeleeDamageModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iMeleeDamageModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iMeleeDamageModifier > 0 ) - { - swprintf( pStr, L"%+2d", iMeleeDamageModifier ); - } - else - { - swprintf( pStr, L"%2d", iMeleeDamageModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // WOOD CAMO - if ( Item[ gpItemDescObject->usItem ].camobonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iWoodCamoModifier = 0; - iWoodCamoModifier = Item[ gpItemDescObject->usItem ].camobonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iWoodCamoModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iWoodCamoModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iWoodCamoModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iWoodCamoModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iWoodCamoModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // URBAN CAMO - if ( Item[ gpItemDescObject->usItem ].urbanCamobonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iUrbanCamoModifier = 0; - iUrbanCamoModifier = Item[ gpItemDescObject->usItem ].urbanCamobonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iUrbanCamoModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iUrbanCamoModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iUrbanCamoModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iUrbanCamoModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iUrbanCamoModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // DESERT CAMO - if ( Item[ gpItemDescObject->usItem ].desertCamobonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iDesertCamoModifier = 0; - iDesertCamoModifier = Item[ gpItemDescObject->usItem ].desertCamobonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iDesertCamoModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iDesertCamoModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iDesertCamoModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iDesertCamoModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iDesertCamoModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // SNOW CAMO - if ( Item[ gpItemDescObject->usItem ].snowCamobonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iSnowCamoModifier = 0; - iSnowCamoModifier = Item[ gpItemDescObject->usItem ].snowCamobonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iSnowCamoModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iSnowCamoModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iSnowCamoModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iSnowCamoModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iSnowCamoModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // STEALTH MODIFIER - if ( Item[ gpItemDescObject->usItem ].stealthbonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iStealthModifier = 0; - iStealthModifier = Item[ gpItemDescObject->usItem ].stealthbonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iStealthModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iStealthModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iStealthModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iStealthModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iStealthModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // HEARING RANGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].hearingrangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iHearingRangeModifier = 0; - iHearingRangeModifier = Item[ gpItemDescObject->usItem ].hearingrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iHearingRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iHearingRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iHearingRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iHearingRangeModifier ); - } - else - { - swprintf( pStr, L"%2d", iHearingRangeModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // VISION RANGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].visionrangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iVisionRangeModifier = 0; - iVisionRangeModifier = Item[ gpItemDescObject->usItem ].visionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iVisionRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iVisionRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iVisionRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iVisionRangeModifier / 10 ); - } - else - { - swprintf( pStr, L"%2d", iVisionRangeModifier / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // DAY VISION RANGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].dayvisionrangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iDayVisionRangeModifier = 0; - iDayVisionRangeModifier = Item[ gpItemDescObject->usItem ].dayvisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iDayVisionRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iDayVisionRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iDayVisionRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iDayVisionRangeModifier / 10 ); - } - else - { - swprintf( pStr, L"%2d", iDayVisionRangeModifier / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // NIGHT VISION RANGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].nightvisionrangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iNightVisionRangeModifier = 0; - iNightVisionRangeModifier = Item[ gpItemDescObject->usItem ].nightvisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iNightVisionRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iNightVisionRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iNightVisionRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iNightVisionRangeModifier / 10 ); - } - else - { - swprintf( pStr, L"%2d", iNightVisionRangeModifier / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // BRIGHT LIGHT VISION RANGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iBrightLightVisionRangeModifier = 0; - iBrightLightVisionRangeModifier = Item[ gpItemDescObject->usItem ].brightlightvisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iBrightLightVisionRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iBrightLightVisionRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iBrightLightVisionRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iBrightLightVisionRangeModifier / 10 ); - } - else - { - swprintf( pStr, L"%2d", iBrightLightVisionRangeModifier / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // CAVE VISION RANGE MODIFIER - if ( Item[ gpItemDescObject->usItem ].cavevisionrangebonus != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iCaveVisionRangeModifier = 0; - iCaveVisionRangeModifier = Item[ gpItemDescObject->usItem ].cavevisionrangebonus; - - // determine value print color - SetFontForeground( 5 ); - if ( iCaveVisionRangeModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iCaveVisionRangeModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iCaveVisionRangeModifier > 0 ) - { - swprintf( pStr, L"%+2d", iCaveVisionRangeModifier / 10 ); - } - else - { - swprintf( pStr, L"%2d", iCaveVisionRangeModifier / 10 ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; - } - - // PERCENT TUNNEL VISION MODIFIER - if ( Item[ gpItemDescObject->usItem ].percenttunnelvision != 0 && cnt<=27 ) - { - // equals - SetFontForeground( 6 ); - mprintf( gMiscItemStatsEDB[ cnt ].sX + gsInvDescX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - - // determine value - INT16 iPercentTunnelVisionModifier = 0; - iPercentTunnelVisionModifier = Item[ gpItemDescObject->usItem ].percenttunnelvision; - - // determine value print color - SetFontForeground( 5 ); - if ( iPercentTunnelVisionModifier > 0 ) - { - SetFontForeground( ITEMDESC_FONTNEGATIVE ); - } - else if ( iPercentTunnelVisionModifier < 0 ) - { - SetFontForeground( ITEMDESC_FONTPOSITIVE ); - } - - // print value - if ( iPercentTunnelVisionModifier > 0 ) - { - swprintf( pStr, L"%+2d%%", iPercentTunnelVisionModifier ); - } - else - { - swprintf( pStr, L"%2d%%", iPercentTunnelVisionModifier ); - } - uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ cnt ].sX + gsInvDescX + gMiscItemStatsEDB[ cnt ].sValDx), (INT16)(gMiscItemStatsEDB[ cnt ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( sStrX, gMiscItemStatsEDB[ cnt ].sY + gsInvDescY, pStr ); - cnt++; + DrawAdvancedValues( gpItemDescObject ); } } - diff --git a/Tactical/Interface Enhanced.h b/Tactical/Interface Enhanced.h index ebd8aed5..ae01f42f 100644 --- a/Tactical/Interface Enhanced.h +++ b/Tactical/Interface Enhanced.h @@ -4,14 +4,18 @@ extern INV_DESC_STATS gMiscItemStatsEDB[]; UINT8 UsingEDBSystem(); -void InitItemDescriptionBoxOffsets(); +void InitItemDescriptionBoxOffsets(OBJECTTYPE * gpItemDescObject); BOOLEAN InternalInitEnhancedDescBox(); void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurrentItemDescriptionScreen ); void DeleteEnhancedDescBox( UINT32 guiCurrentItemDescriptionScreen ); -void InitDescStatCoords(); +void InitDescStatCoords(OBJECTTYPE *pObject); void InitLBECoords(); -void InitEDBCoords(); +void InitEDBCoords(OBJECTTYPE * pObject); +// HEADROCK HAM 4: UDB Secondary Stats column icons (no values) +void DrawSecondaryStats( OBJECTTYPE * gpItemDescObject ); +void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject ); +void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject ); void DrawWeaponStats( OBJECTTYPE * gpItemDescObject ); void DrawAmmoStats( OBJECTTYPE * gpItemDescObject ); void DrawExplosiveStats( OBJECTTYPE * gpItemDescObject ); diff --git a/Tactical/Interface Items.cpp b/Tactical/Interface Items.cpp index 8766bec7..1bb20252 100644 --- a/Tactical/Interface Items.cpp +++ b/Tactical/Interface Items.cpp @@ -3,6 +3,7 @@ #include "language defines.h" #else #include "builddefines.h" + #include "mapscreen.h" #include #include #include @@ -77,6 +78,10 @@ #include "InterfaceItemImages.h" #endif +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - all "APBPConstants[AP_PICKUP_ITEM]" were replaced by GetBasicAPsToPickupItem() +//////////////////////////////////////////////////////////////////////////////////////////////////////// + //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; @@ -128,13 +133,6 @@ extern int SM_ITEMDESC_START_Y; #define CAMO_REGION_HEIGHT 75 #define CAMO_REGION_WIDTH 75 -// HEADROCK: Changed to INT16s for dynamic ODB-EDB switch. These are icon locations for the Description Box. -// With EDB, many more icons will appear, for new object data fields. -INT16 BULLET_SING_X; -INT16 BULLET_SING_Y; -INT16 BULLET_BURST_X; -INT16 BULLET_BURST_Y; - #define BULLET_WIDTH 3 #define BULLET_GAP 5 @@ -145,16 +143,13 @@ INT16 ITEMDESC_NAME_X; INT16 ITEMDESC_NAME_Y; INT16 ITEMDESC_ITEM_X; INT16 ITEMDESC_ITEM_Y; -INT16 ITEMDESC_DESC_START_X; -INT16 ITEMDESC_DESC_START_Y; -INT16 ITEMDESC_PROS_START_X; -INT16 ITEMDESC_PROS_START_Y; -INT16 ITEMDESC_CONS_START_X; -INT16 ITEMDESC_CONS_START_Y; -INT16 ITEMDESC_DESC_WIDTH; INT16 ITEMDESC_ITEM_STATUS_X; INT16 ITEMDESC_ITEM_STATUS_Y; INT16 ITEMDESC_ITEM_STATUS_HEIGHT; +INT16 ITEMDESC_AMMO_X; +INT16 ITEMDESC_AMMO_Y; +INT16 ITEMDESC_DONE_X; +INT16 ITEMDESC_DONE_Y; #define DOTDOTDOT L"..." #define COMMA_AND_SPACE L", " @@ -165,9 +160,6 @@ INT16 ITEMDESC_ITEM_STATUS_HEIGHT; #define ITEMDESC_ITEM_WIDTH 117 #define ITEMDESC_ITEM_HEIGHT 54 -#define ITEMDESC_AMMO_X ( 10 + gsInvDescX ) -#define ITEMDESC_AMMO_Y ( 50 + gsInvDescY ) - #define ITEMDESC_AMMO_TEXT_X 3 #define ITEMDESC_AMMO_TEXT_Y 1 #define ITEMDESC_AMMO_TEXT_WIDTH 31 @@ -180,7 +172,7 @@ INT16 ITEMDESC_ITEM_STATUS_HEIGHT; #define ITEM_FONT TINYFONT1 //CHRISL: Moved to Interface Items.h for EDB -//#define EXCEPTIONAL_DAMAGE 40 +//#define EXCEPTIONAL_GUN_DAMAGE 40 //#define EXCEPTIONAL_WEIGHT 20 //#define EXCEPTIONAL_RANGE 400 //#define EXCEPTIONAL_MAGAZINE 50 @@ -247,17 +239,23 @@ UINT32 guiNewlyPlacedItemTimer = 0; BOOLEAN gfBadThrowItemCTGH; BOOLEAN gfDontChargeAPsToPickup = FALSE; BOOLEAN gbItemPointerLocateGood = FALSE; +INT32 iItemPosition = 0; // ITEM DESCRIPTION BOX STUFF UINT32 guiItemDescBox; UINT32 guiItemDescBoxBackground; +// HEADROCK HAM 4: Image file for LBE backgrounds +UINT32 guiItemInfoLBEBackground; UINT32 guiMapItemDescBox; +UINT32 guiAttachmentSlot; UINT32 guiItemGraphic; UINT32 guiMoneyGraphicsForDescBox; UINT32 guiBullet; BOOLEAN gfInItemDescBox = FALSE; UINT32 guiCurrentItemDescriptionScreen=0; OBJECTTYPE *gpItemDescObject = NULL; +// HEADROCK HAM 4: Remembers the object that was open before an attachment desc is opened on top of it. +OBJECTTYPE *gpItemDescPrevObject = NULL; BOOLEAN gfItemDescObjectIsAttachment = FALSE; CHAR16 gzItemName[ SIZE_ITEM_NAME ]; CHAR16 gzItemDesc[ SIZE_ITEM_INFO ]; @@ -280,7 +278,7 @@ MOUSE_REGION gItemDescAttachmentRegions[MAX_ATTACHMENTS]; MOUSE_REGION gProsAndConsRegions[2]; void BtnMoneyButtonCallback(GUI_BUTTON *btn,INT32 reason); -UINT32 guiMoneyButtonBtn[MAX_ATTACHMENTS]; +UINT32 guiMoneyButtonBtn[OLD_MAX_ATTACHMENTS_101]; INT32 guiMoneyButtonImage; INT32 guiMoneyDoneButtonImage; @@ -352,6 +350,22 @@ extern BOOLEAN fMapScreenBottomDirty; INT32 giMapInvDescButtonImage; INT32 giMapInvDescButton = -1; +// HEADROCK HAM 4: Item Description Box TAB buttons for UDB +INT32 giMapInvDescTabButtonImage; +INT32 giInvDescTabButtonImage; +INT32 giInvDescTabButton[3] = {-1, -1, -1}; +void ItemDescTabButtonCallback( GUI_BUTTON *btn, INT32 reason ); +void ItemDescTabButtonOn( UINT8 ubItemDescTabButtonIndex ); +void ItemDescTabButtonOff( UINT8 ubItemDescTabButtonIndex ); +// HEADROCK HAM 4: Item Description Box Scroll Buttons for UDB +INT32 giInvDescAdvButtonUpImage; +INT32 giInvDescAdvButtonDownImage; +INT32 giInvDescAdvButton[2] = {-1, -1}; +void ItemDescAdvButtonCallback( GUI_BUTTON *btn, INT32 reason ); +void ItemDescAdvButtonOn( UINT8 ubItemDescAdvButtonIndex ); +void ItemDescAdvButtonOff( UINT8 ubItemDescAdvButtonIndex ); +void ItemDescAdvButtonCheck( void ); + // the done descrition button callback void ItemDescDoneButtonCallback( GUI_BUTTON *btn, INT32 reason ); @@ -435,9 +449,6 @@ typedef struct STR16 sString2[NUM_INV_HELPTEXT_ENTRIES]; } INV_HELPTEXT; -//CHRISL: Moved declaration to InitDescStatCoords for EDB -INV_DESC_STATS gWeaponStats[47]; - //CHRISL: Moved declaration to InitDescStatCoords for EDB // displayed AFTER the mass/weight/"Kg" line INV_DESC_STATS gMoneyStats[6]; @@ -445,10 +456,7 @@ INV_DESC_STATS gMoneyStats[6]; //CHRISL: Created for LBENODE Rendering with EDB INV_DESC_STATS gLBEStats[48]; -INV_ATTACHXY gItemDescAttachmentsXY[4]; - -//CHRISL: Moved declaration to InitDescStatCoords for EDB -SGPRect gItemDescProsConsRects[2]; +INV_ATTACHXY gItemDescAttachmentsXY[MAX_ATTACHMENTS]; INV_HELPTEXT gItemDescHelpText = { @@ -487,6 +495,18 @@ UINT32 guiBodyInvVO[ 5 ][ 2 ]; UINT32 guiGoldKeyVO; INT8 gbCompatibleApplyItem = FALSE; +// HEADROCK HAM 4: New region coordinate tables for UDB +INV_DESC_REGIONS gItemDescLBEBackground[4]; // Coordinates for displaying LBE background image +INV_DESC_REGIONS gItemDescGenHeaderRegions[3]; // Header text regions for various parts of the General Tab +INV_DESC_REGIONS gItemDescGenIndexRegions[3][4]; // Index text regions for various parts of the General Tab +INV_DESC_REGIONS gItemDescGenRegions[NUM_UDB_GEN_LINES * 2][4]; // Data regions, 4 sub-columns each +INV_DESC_REGIONS gItemDescGenSecondaryRegions[26]; // Secondary data regions, 3x5 +INV_DESC_REGIONS gItemDescTextRegions[7]; // Main description regions +INV_DESC_REGIONS gItemDescAdvIndexRegions[1][4]; +INV_DESC_REGIONS gItemDescAdvRegions[NUM_UDB_ADV_LINES][4]; // Advanced data regions, 4 sub-columns each + +INV_DESC_REGIONS gODBItemDescRegions[4][8]; // Four regions of eight sub-regions each. + BOOLEAN AttemptToAddSubstring( STR16 zDest, STR16 zTemp, UINT32 * puiStringLength, UINT32 uiPixLimit ) { UINT32 uiRequiredStringLength, uiTempStringLength; @@ -529,6 +549,7 @@ void GenerateProsString( STR16 zItemPros, OBJECTTYPE * pObject, UINT32 uiPixLimi ubWeight = ubWeight + Item[ (*pObject)[0]->data.gun.usGunAmmoItem ].ubWeight; } + //CHRISL: TODO - This needs to be updated for NCTH if (Weapon[usItem].bAccuracy >= EXCEPTIONAL_ACCURACY ) { zTemp = Message[STR_ACCURATE]; @@ -559,7 +580,9 @@ void GenerateProsString( STR16 zItemPros, OBJECTTYPE * pObject, UINT32 uiPixLimi } } - if ( GunRange( pObject ) >= EXCEPTIONAL_RANGE ) + UINT16 exceptionalRange = (UINT16)((EXCEPTIONAL_RANGE * gGameExternalOptions.iGunRangeModifier ) / 100); + + if ( GunRange( pObject, NULL ) >= exceptionalRange ) // SANDRO - added argument { zTemp = Message[STR_LONG_RANGE]; if ( ! AttemptToAddSubstring( zItemPros, zTemp, &uiStringLength, uiPixLimit ) ) @@ -568,7 +591,19 @@ void GenerateProsString( STR16 zItemPros, OBJECTTYPE * pObject, UINT32 uiPixLimi } } - if (GetDamage(pObject) >= EXCEPTIONAL_DAMAGE) + UINT16 exceptionalDamage; + // Melee damage + if ( Item[pObject->usItem].usItemClass == IC_BLADE || Item[pObject->usItem].usItemClass == IC_PUNCH || Item[pObject->usItem].usItemClass == IC_TENTACLES ) + { + exceptionalDamage = (UINT16)(( EXCEPTIONAL_MELEE_DAMAGE * gGameExternalOptions.iMeleeDamageModifier ) / 100); + } + // Gun damage + else + { + exceptionalDamage = (UINT16)(( EXCEPTIONAL_GUN_DAMAGE * gGameExternalOptions.iGunDamageModifier ) / 100); + } + + if (GetDamage(pObject) >= exceptionalDamage) { zTemp = Message[STR_HIGH_DAMAGE]; if ( ! AttemptToAddSubstring( zItemPros, zTemp, &uiStringLength, uiPixLimit ) ) @@ -604,7 +639,7 @@ void GenerateProsString( STR16 zItemPros, OBJECTTYPE * pObject, UINT32 uiPixLimi } } - if ( Item[usItem].bReliability >= EXCEPTIONAL_RELIABILITY ) + if ( GetReliability( pObject ) >= EXCEPTIONAL_RELIABILITY ) { zTemp = Message[STR_RELIABLE]; if ( ! AttemptToAddSubstring( zItemPros, zTemp, &uiStringLength, uiPixLimit ) ) @@ -650,6 +685,7 @@ void GenerateConsString( STR16 zItemCons, OBJECTTYPE * pObject, UINT32 uiPixLimi zItemCons[0] = 0; + //CHRISL: TODO - This needs to be updated for NCTH if (Weapon[usItem].bAccuracy <= BAD_ACCURACY) { zTemp = Message[STR_INACCURATE]; @@ -685,7 +721,7 @@ void GenerateConsString( STR16 zItemCons, OBJECTTYPE * pObject, UINT32 uiPixLimi } } - if ( GunRange( pObject ) <= BAD_RANGE) + if ( GunRange( pObject, NULL ) <= BAD_RANGE) // SANDRO - added argument { zTemp = Message[STR_SHORT_RANGE]; if ( ! AttemptToAddSubstring( zItemCons, zTemp, &uiStringLength, uiPixLimit ) ) @@ -740,7 +776,7 @@ void GenerateConsString( STR16 zItemCons, OBJECTTYPE * pObject, UINT32 uiPixLimi } } - if ( Item[usItem].bReliability <= BAD_RELIABILITY ) + if ( GetReliability( pObject ) <= BAD_RELIABILITY ) { zTemp = Message[STR_UNRELIABLE]; if ( ! AttemptToAddSubstring( zItemCons, zTemp, &uiStringLength, uiPixLimit ) ) @@ -769,6 +805,85 @@ void GenerateConsString( STR16 zItemCons, OBJECTTYPE * pObject, UINT32 uiPixLimi } } +BOOLEAN UseNASDesc(OBJECTTYPE *pObject){ + if(pObject->exists() == FALSE) + return FALSE; + return (Item[pObject->usItem].usItemClass != IC_LBEGEAR && Item[pObject->usItem].usItemClass != IC_MONEY && UsingNewAttachmentSystem()==true); +} + +//WarmSteel - This function is used to move groups of items with NAS along the Y axe +INT16 sNASYCorrection(OBJECTTYPE * pObject){ + + //WarmSteel - If this confuses you, it's basically the same structure as in InitDescStatCoords. + if(UseNASDesc(pObject)){ + if(UsingEDBSystem() > 0) + { + if( guiCurrentScreen == MAP_SCREEN ) + { + return 113; + } + else + { + if (UsingEDBSystem() == 1) // NIV EDB + { + return 0; + } + if (UsingEDBSystem() == 2) // OIV EDB + { + return 0; + } + } + } + else + { + if(guiCurrentScreen ==MAP_SCREEN) + { + return 113; + } + else + { + return 0; + } + } + } + //WarmSteel - Item does not qualify for NAS layout. + return 0; +} +//WarmSteel - This function is used to move groups of items with NAS along the X axe +INT16 sNASXCorrection(OBJECTTYPE * pObject){ + + //WarmSteel - If this confuses you, it's basically the same structure as in InitDescStatCoords. + if(UseNASDesc(pObject)){ + if(UsingEDBSystem() > 0) + { + if( guiCurrentScreen == MAP_SCREEN ) + { + return 0; + } + else + { + if (UsingEDBSystem()) // NIV EDB + { + return 190; + } + } + } + else //ODB + { + if(guiCurrentScreen ==MAP_SCREEN) + { + return 0; + } + else + { + return 90; + } + } + } + //WarmSteel - Item does not qualify for NAS layout. + return 0; +} + // CHRISL: New function to setup GSMInvData based on game options void InitInvData(INV_REGIONS &InvData, BOOLEAN fBigPocket, INT16 sBarDx, INT16 sBarDy, INT16 sWidth, INT16 sHeight, INT16 sX, INT16 sY) { @@ -1472,7 +1587,7 @@ void INVRenderINVPanelItem( SOLDIERTYPE *pSoldier, INT16 sPocket, UINT8 fDirtyLe if(gpItemPointer != NULL) { if(!gfSMDisableForItems && !CanItemFitInPosition(pSoldier, gpItemPointer, (INT8)sPocket, FALSE)){ - if(!ValidAttachment(gpItemPointer->usItem, pObject->usItem)){ + if(!ValidAttachment(gpItemPointer->usItem, pObject )){ fHatchItOut = TRUE; } else{ @@ -1571,7 +1686,7 @@ BOOLEAN CompatibleItemForApplyingOnMerc( OBJECTTYPE *pTestObject ) // ATE: Would be nice to have flag here to check for these types.... if ( Item[usItem].camouflagekit || usItem == ADRENALINE_BOOSTER || usItem == REGEN_BOOSTER || usItem == SYRINGE_3 || usItem == SYRINGE_4 || usItem == SYRINGE_5 || - Item[usItem].alcohol || Item[usItem].canteen || usItem == JAR_ELIXIR ) + Item[usItem].alcohol || Item[usItem].canteen || usItem == JAR_ELIXIR || (usItem == 1022 && gGameExternalOptions.fCamoRemoving) ) // Added rag usable on self - SANDRO { return( TRUE ); } @@ -1737,8 +1852,8 @@ BOOLEAN HandleCompatibleAmmoUIForMapScreen( SOLDIERTYPE *pSoldier, INT32 bInvPos continue; } - if ( ValidAttachment( pObject->usItem, pTestObject->usItem ) || - ValidAttachment( pTestObject->usItem, pObject->usItem ) || + if ( ValidAttachment( pObject->usItem, pTestObject ) || + ValidAttachment( pTestObject->usItem, pObject ) || ValidLaunchable( pTestObject->usItem, pObject->usItem ) || ValidLaunchable( pObject->usItem, pTestObject->usItem ) ) { @@ -1838,8 +1953,8 @@ BOOLEAN HandleCompatibleAmmoUIForMapInventory( SOLDIERTYPE *pSoldier, INT32 bInv continue; } - if ( ValidAttachment( pObject->usItem, pTestObject->usItem ) || - ValidAttachment( pTestObject->usItem, pObject->usItem ) || + if ( ValidAttachment( pObject->usItem, pTestObject ) || + ValidAttachment( pTestObject->usItem, pObject ) || ValidLaunchable( pTestObject->usItem, pObject->usItem ) || ValidLaunchable( pObject->usItem, pTestObject->usItem ) ) { @@ -1970,8 +2085,8 @@ BOOLEAN InternalHandleCompatibleAmmoUI( SOLDIERTYPE *pSoldier, OBJECTTYPE *pTest continue; } - if ( ValidAttachment( pObject->usItem, pTestObject->usItem ) || - ValidAttachment( pTestObject->usItem, pObject->usItem ) || + if ( ValidAttachment( pObject->usItem, pTestObject ) || + ValidAttachment( pTestObject->usItem, pObject ) || ValidLaunchable( pTestObject->usItem, pObject->usItem ) || ValidLaunchable( pObject->usItem, pTestObject->usItem ) ) { @@ -2298,7 +2413,7 @@ void RenderPocketItemCapacity( UINT32 uiWhichBuffer, UINT8 pCapacity, INT16 bPos if(pSoldier != NULL && !CanItemFitInPosition( pSoldier, gpItemPointer, (INT8)bPos, FALSE )) { // Further check to see if the cursor item is valid ammo or a valid attachment - if(!CompatibleAmmoForGun(gpItemPointer, &pSoldier->inv[bPos]) && !ValidAttachment(gpItemPointer->usItem, pSoldier->inv[bPos].usItem)) + if(!CompatibleAmmoForGun(gpItemPointer, &pSoldier->inv[bPos]) && !ValidAttachment(gpItemPointer->usItem, &(pSoldier->inv[bPos]))) { return; } @@ -2328,7 +2443,7 @@ void RenderPocketItemCapacity( UINT32 uiWhichBuffer, UINT8 pCapacity, INT16 bPos SetFontForeground( FONT_YELLOW ); swprintf( pStr, L"L" ); } - else if(ValidAttachment(gpItemPointer->usItem, pSoldier->inv[bPos].usItem)) + else if(ValidAttachment(gpItemPointer->usItem, &(pSoldier->inv[bPos]) )) { SetFontForeground( FONT_YELLOW ); swprintf( pStr, L"A" ); @@ -2586,7 +2701,7 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec #endif if ( ItemHasAttachments( pObject, pSoldier, iter ) ) { - if ( !IsGrenadeLauncherAttached( pObject ) ) + if ( !IsGrenadeLauncherAttached( pObject, iter ) ) { SetFontForeground( FONT_GREEN ); } @@ -2698,7 +2813,7 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec else { OBJECTTYPE* pAttachment = (*pObject)[iter]->GetAttachmentAtIndex(ubStatusIndex - RENDER_ITEM_ATTACHMENT1); - if (pAttachment) { + if (pAttachment->exists()) { swprintf( pStr, L"%s", ShortItemNames[ pAttachment->usItem ] ); } } @@ -2822,59 +2937,101 @@ BOOLEAN InitItemDescriptionBox( SOLDIERTYPE *pSoldier, UINT8 ubPosition, INT16 s // HEADROCK: The following two functions set various coordinates for use by the description box, depending on // an options.ini setting that determines whether the Enhanced box or the Original box is used. -void InitItemDescriptionBoxStartCoords( BOOLEAN fIsEnhanced ) +void InitItemDescriptionBoxStartCoords( BOOLEAN fIsEnhanced, BOOLEAN fUsingNAS ) { UINT8 mode = UsingEDBSystem(); + if(fUsingNAS){ + if (guiCurrentItemDescriptionScreen != SHOPKEEPER_SCREEN) + { + ITEMDESC_START_X = 115; + ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); + ITEMDESC_HEIGHT = 195; + ITEMDESC_WIDTH = 335; // OIV only + } + else if( UsingNewInventorySystem() == true ) // ODB/NIV + { + ITEMDESC_START_X = 200;//259; + ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); + ITEMDESC_HEIGHT = guiCurrentItemDescriptionScreen == SHOPKEEPER_SCREEN ? 193 : 195; + ITEMDESC_WIDTH = 430; // OIV only + } + else // ODB/OIV + { + ITEMDESC_HEIGHT = 193; + ITEMDESC_WIDTH = 430; // OIV only + ITEMDESC_START_X = 214;//214 + ITEMDESC_START_Y = (1-(ITEMDESC_HEIGHT-INV_INTERFACE_HEIGHT) + INV_INTERFACE_START_Y); + } - if( mode == 1 ) // EDB - { - ITEMDESC_START_X = 115; - ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); - ITEMDESC_HEIGHT = 195; - ITEMDESC_WIDTH = 335; // OIV only - } - else if( mode == 2 ) // EDB/OIV Tactical - { - ITEMDESC_START_X = 214; - ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); - ITEMDESC_HEIGHT = 133; - ITEMDESC_WIDTH = 477; // OIV only - } - else if( UsingNewInventorySystem() == true ) // ODB/NIV - { - ITEMDESC_START_X = 259; - ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); - ITEMDESC_HEIGHT = guiCurrentItemDescriptionScreen == SHOPKEEPER_SCREEN ? 133 : 195; - ITEMDESC_WIDTH = 320; // OIV only - } - else // ODB/OIV - { - ITEMDESC_START_X = 214; - ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); - ITEMDESC_HEIGHT = 133; - ITEMDESC_WIDTH = 320; // OIV only - } + if(UsingNewInventorySystem() == true && guiCurrentScreen == GAME_SCREEN) + { + if(iResolution == 0) + ITEMDESC_WIDTH = 526; + else if(iResolution == 1) + ITEMDESC_WIDTH = 686; + else if(iResolution == 2) + ITEMDESC_WIDTH = 910; + } - if(UsingNewInventorySystem() == true && guiCurrentScreen == GAME_SCREEN) - { - if(iResolution == 0) - ITEMDESC_WIDTH = 526; - else if(iResolution == 1) - ITEMDESC_WIDTH = 686; - else if(iResolution == 2) - ITEMDESC_WIDTH = 910; - } + //CHRISL: This allows EDB to work in Strategic OIV mode + if(guiCurrentScreen == MAP_SCREEN) + { + if(iResolution == 0) // 640x480 res + ITEMDESC_HEIGHT = 268; + else if(iResolution == 2 || UsingNewInventorySystem() == true) // 1024x768 or NIV + ITEMDESC_HEIGHT = 490; + else if(iResolution == 1) // 800x600 + ITEMDESC_HEIGHT = (mode > 0) ? 490 : 373; + ITEMDESC_WIDTH = ((UsingNewInventorySystem() == true && iResolution != 0)) ? 272 : 272; + } + } else { + if( UsingNewInventorySystem() == true ) // ODB/NIV + { + if (guiCurrentItemDescriptionScreen != SHOPKEEPER_SCREEN) + { + // HEADROCK HAM 4: + ITEMDESC_START_X = 115; + ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); + ITEMDESC_HEIGHT = 195; + ITEMDESC_WIDTH = 335; // OIV only + } + else + { + ITEMDESC_START_X = 259; + ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); + ITEMDESC_HEIGHT = guiCurrentItemDescriptionScreen == SHOPKEEPER_SCREEN ? 133 : 195; + ITEMDESC_WIDTH = 320; // OIV only + } + } + else // ODB/OIV + { + ITEMDESC_START_X = 214; + ITEMDESC_START_Y = (1 + INV_INTERFACE_START_Y); + ITEMDESC_HEIGHT = 133; + ITEMDESC_WIDTH = 320; // OIV only + } - //CHRISL: This allows EDB to work in Strategic OIV mode - if(guiCurrentScreen == MAP_SCREEN) - { - if(iResolution == 0) // 640x480 res - ITEMDESC_HEIGHT = 268; - else if(iResolution == 2 || UsingNewInventorySystem() == true) // 1024x768 or NIV - ITEMDESC_HEIGHT = 490; - else if(iResolution == 1) // 800x600 - ITEMDESC_HEIGHT = 373; - ITEMDESC_WIDTH = ((UsingNewInventorySystem() == true && iResolution != 0)) ? 272 : 272; + if(UsingNewInventorySystem() == true && guiCurrentScreen == GAME_SCREEN) + { + if(iResolution == 0) + ITEMDESC_WIDTH = 526; + else if(iResolution == 1) + ITEMDESC_WIDTH = 686; + else if(iResolution == 2) + ITEMDESC_WIDTH = 910; + } + + //CHRISL: This allows EDB to work in Strategic OIV mode + if(guiCurrentScreen == MAP_SCREEN) + { + if(iResolution == 0) // 640x480 res + ITEMDESC_HEIGHT = 268; + else if(iResolution == 2 || UsingNewInventorySystem() == true) // 1024x768 or NIV + ITEMDESC_HEIGHT = 490; + else if(iResolution == 1) // 800x600 + ITEMDESC_HEIGHT = 373; + ITEMDESC_WIDTH = ((UsingNewInventorySystem() == true && iResolution != 0)) ? 272 : 272; + } } } @@ -2897,19 +3054,6 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, INT16 usX, usY; INT16 sForeColour; -/* Moved to InitItemDescriptionBoxStartCoords - // CHRISL: Set some initial coords - ITEMDESC_START_X = ((UsingNewInventorySystem() == true && iResolution != 0)) ? 259 : 214; //115:214 - ITEMDESC_START_Y = ((UsingNewInventorySystem() == true && iResolution != 0)) ? (1 + INV_INTERFACE_START_Y) : (1 + INV_INTERFACE_START_Y); - ITEMDESC_HEIGHT = ((UsingNewInventorySystem() == true && iResolution != 0)) ? 195 : 133; //195:133 - ITEMDESC_WIDTH = 320; -*/ - // This initializes the start coordinates of the description box, based on the box we want to use. - //CHRISL: Initialize coords based on EDB/NIV settings - InitDescStatCoords(); - InitEDBCoords(); - InitItemDescriptionBoxStartCoords( gGameExternalOptions.iEnhancedDescriptionBox ); - //CHRISL: We only want this condition to be true when looking at MONEY. Not IC_MONEY since we can't actually split // things like gold nuggets or wallets. // ADB: Make sure the current object isn't money if there's something in hand @@ -2925,6 +3069,9 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, //Set the current screen guiCurrentItemDescriptionScreen = guiCurrentScreen; + // Set up start coordinates for the box. + InitItemDescriptionBoxStartCoords( gGameExternalOptions.iEnhancedDescriptionBox, UseNASDesc( pObject ) ); + // Set X, Y if(guiCurrentScreen == GAME_SCREEN) { @@ -2939,7 +3086,11 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, // Headrock: initialize coordinates of icons, values and text, based on gsInvDescXY and the type of description // box we want to use. - InitItemDescriptionBoxOffsets(); + //CHRISL: Initialize coords based on EDB/NIV settings + // This initializes the start coordinates of the description box, based on the box we want to use. + InitDescStatCoords( pObject ); + InitEDBCoords( pObject ); + InitItemDescriptionBoxOffsets(pObject); gpItemDescObject = pObject; gubItemDescStatusIndex = ubStatusIndex; @@ -2961,11 +3112,11 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, // HEADROCK: Create "Done" button. Coordinates changed - button moved to new location for // enhanced Description Box project. if(UsingEDBSystem() > 0) - giMapInvDescButton= QuickCreateButton( giMapInvDescButtonImage, (UINT16)( gsInvDescX + 199 ), (UINT16)( gsInvDescY + 334 ), + giMapInvDescButton= QuickCreateButton( giMapInvDescButtonImage, (UINT16)( ITEMDESC_DONE_X ), (UINT16)(ITEMDESC_DONE_Y), BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, ( GUI_CALLBACK )BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)ItemDescDoneButtonCallback ); else - giMapInvDescButton= QuickCreateButton( giMapInvDescButtonImage, (UINT16)( gsInvDescX + 204 ), (UINT16)( gsInvDescY + 107 ), + giMapInvDescButton= QuickCreateButton( giMapInvDescButtonImage, (UINT16)( ITEMDESC_DONE_X ), (UINT16)(ITEMDESC_DONE_Y), BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, ( GUI_CALLBACK )BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)ItemDescDoneButtonCallback ); @@ -2984,13 +3135,9 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, MSYS_AddRegion( &gInvDesc); } - // Add region + // Add ammo eject button for GUN type objects. if ( (Item[ pObject->usItem ].usItemClass & IC_GUN) && !Item[pObject->usItem].rocketlauncher ) { - // Add button -// if( guiCurrentScreen != MAP_SCREEN ) - //if( guiCurrentItemDescriptionScreen != MAP_SCREEN ) - if ( GetMagSize(gpItemDescObject) <= 99 ) { // HEADROCK HAM 3.4: "Bullet Hide" feature - bullet count only shown during combat if character is competent enough. @@ -3023,25 +3170,6 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, giItemDescAmmoButtonImages = LoadButtonImage(ubString,AmmoTypes[(*pObject)[ubStatusIndex]->data.gun.ubGunAmmoType].grayed,AmmoTypes[(*pObject)[ubStatusIndex]->data.gun.ubGunAmmoType].offNormal,-1,AmmoTypes[(*pObject)[ubStatusIndex]->data.gun.ubGunAmmoType].onNormal,-1 ); - //switch( (*pObject)[ubStatusIndex]->data.gun.ubGunAmmoType ) - //{ - // case AMMO_AP: - // case AMMO_SUPER_AP: - // //sForeColour = ITEMDESC_FONTAPFORE; - // giItemDescAmmoButtonImages = LoadButtonImage(ubString,8,5,-1,7,-1 ); - // break; - // case AMMO_HP: - // //sForeColour = ITEMDESC_FONTHPFORE; - // - // giItemDescAmmoButtonImages = LoadButtonImage(ubString,12,9,-1,11,-1 ); - // break; - // default: - // //sForeColour = FONT_MCOLOR_WHITE; - // giItemDescAmmoButtonImages = LoadButtonImage(ubString,4,1,-1,3,-1 ); - // break; - - //} - if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) { // in mapscreen, move over a bit @@ -3049,7 +3177,7 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, sForeColour, FONT_MCOLOR_BLACK, sForeColour, FONT_MCOLOR_BLACK, TEXT_CJUSTIFIED, - (INT16)(ITEMDESC_AMMO_X + 18), (INT16)(ITEMDESC_AMMO_Y - 5), BUTTON_TOGGLE ,MSYS_PRIORITY_HIGHEST, + (INT16)(ITEMDESC_AMMO_X), (INT16)(ITEMDESC_AMMO_Y), BUTTON_TOGGLE ,MSYS_PRIORITY_HIGHEST, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescAmmoCallback ); } @@ -3057,14 +3185,12 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, { // not in mapscreen - giItemDescAmmoButton = CreateIconAndTextButton( giItemDescAmmoButtonImages, pStr, TINYFONT1, + giItemDescAmmoButton = CreateIconAndTextButton( giItemDescAmmoButtonImages, pStr, TINYFONT1, sForeColour, FONT_MCOLOR_BLACK, sForeColour, FONT_MCOLOR_BLACK, TEXT_CJUSTIFIED, (INT16)(ITEMDESC_AMMO_X), (INT16)(ITEMDESC_AMMO_Y), BUTTON_TOGGLE ,MSYS_PRIORITY_HIGHEST, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescAmmoCallback ); - - //if we are being called from the } //if we are being init from the shop keeper screen and this is a dealer item we are getting info from if( guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE && pShopKeeperItemDescObject != NULL ) @@ -3090,94 +3216,55 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, } // HEADROCK: Tooltip Regions for stats. Only happens with Enhanced Description Box turned on. - // EDB 1.3: Moves this here to init coordinates earlier. if(UsingEDBSystem() > 0) InternalInitEDBTooltipRegion( gpItemDescObject, guiCurrentItemDescriptionScreen ); + // Item pros and cons tooltips region is created now. if ( ITEM_PROS_AND_CONS( gpItemDescObject->usItem ) ) { - if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + for ( cnt = 0; cnt < 2; cnt++ ) { - for ( cnt = 0; cnt < 2; cnt++ ) + // HEADROCK: Rectangle coordinates for tooltip determined by description box used. + // Add region for pros/cons help text + MSYS_DefineRegion( &gProsAndConsRegions[ cnt ], + gItemDescTextRegions[3+(cnt*2)].sLeft, + gItemDescTextRegions[3+(cnt*2)].sTop, + gItemDescTextRegions[3+(cnt*2)].sRight, + gItemDescTextRegions[3+(cnt*2)].sBottom, + MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); + + MSYS_AddRegion( &gProsAndConsRegions[cnt]); + + if (cnt == 0) { - // HEADROCK: Rectangle coordinates for tooltip determined by description box used. - // Add region for pros/cons help text - MSYS_DefineRegion( &gProsAndConsRegions[ cnt ], - (INT16)(gsInvDescX + gItemDescProsConsRects[ cnt ].iLeft), - (INT16)(gsInvDescY + gItemDescProsConsRects[ cnt ].iTop), - (INT16)(gsInvDescX + gItemDescProsConsRects[ cnt ].iRight), - (INT16)(gsInvDescY + gItemDescProsConsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gProsAndConsRegions[cnt]); - - if (cnt == 0) - { - wcscpy( gzFullItemPros, gzProsLabel ); - wcscat( gzFullItemPros, L" " ); - // use temp variable to prevent an initial comma from being displayed - GenerateProsString( gzFullItemTemp, gpItemDescObject, 1000 ); - wcscat( gzFullItemPros, gzFullItemTemp ); - SetRegionFastHelpText( &(gProsAndConsRegions[ cnt ]), gzFullItemPros ); - } - else - { - wcscpy( gzFullItemCons, gzConsLabel ); - wcscat( gzFullItemCons, L" " ); - // use temp variable to prevent an initial comma from being displayed - GenerateConsString( gzFullItemTemp, gpItemDescObject, 1000 ); - wcscat( gzFullItemCons, gzFullItemTemp ); - SetRegionFastHelpText( &(gProsAndConsRegions[ cnt ]), gzFullItemCons ); - } - SetRegionHelpEndCallback( &(gProsAndConsRegions[ cnt ]), HelpTextDoneCallback ); + wcscpy( gzFullItemPros, gzProsLabel ); + wcscat( gzFullItemPros, L" " ); + // use temp variable to prevent an initial comma from being displayed + GenerateProsString( gzFullItemTemp, gpItemDescObject, 1000 ); + wcscat( gzFullItemPros, gzFullItemTemp ); + SetRegionFastHelpText( &(gProsAndConsRegions[ cnt ]), gzFullItemPros ); } - - } - else - { - for ( cnt = 0; cnt < 2; cnt++ ) + else { - // Headrock: Rectangle coordinates for tooltip determined by description box used. - // Add region for pros/cons help text - MSYS_DefineRegion( &gProsAndConsRegions[ cnt ], - (INT16)(gsInvDescX + gItemDescProsConsRects[ cnt ].iLeft), - (INT16)(gsInvDescY + gItemDescProsConsRects[ cnt ].iTop), - (INT16)(gsInvDescX + gItemDescProsConsRects[ cnt ].iRight), - (INT16)(gsInvDescY + gItemDescProsConsRects[ cnt ].iBottom), - MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback ); - - MSYS_AddRegion( &gProsAndConsRegions[cnt]); - - if (cnt == 0) - { - wcscpy( gzFullItemPros, gzProsLabel ); - wcscat( gzFullItemPros, L" " ); - // use temp variable to prevent an initial comma from being displayed - GenerateProsString( gzFullItemTemp, gpItemDescObject, 1000 ); - wcscat( gzFullItemPros, gzFullItemTemp ); - SetRegionFastHelpText( &(gProsAndConsRegions[ cnt ]), gzFullItemPros ); - } - else - { - wcscpy( gzFullItemCons, gzConsLabel ); - wcscat( gzFullItemCons, L" " ); - // use temp variable to prevent an initial comma from being displayed - GenerateConsString( gzFullItemTemp, gpItemDescObject, 1000 ); - wcscat( gzFullItemCons, gzFullItemTemp ); - SetRegionFastHelpText( &(gProsAndConsRegions[ cnt ]), gzFullItemCons ); - } - SetRegionHelpEndCallback( &(gProsAndConsRegions[ cnt ]), HelpTextDoneCallback ); + wcscpy( gzFullItemCons, gzConsLabel ); + wcscat( gzFullItemCons, L" " ); + // use temp variable to prevent an initial comma from being displayed + GenerateConsString( gzFullItemTemp, gpItemDescObject, 1000 ); + wcscat( gzFullItemCons, gzFullItemTemp ); + SetRegionFastHelpText( &(gProsAndConsRegions[ cnt ]), gzFullItemCons ); } + SetRegionHelpEndCallback( &(gProsAndConsRegions[ cnt ]), HelpTextDoneCallback ); } } // Load graphic // HEADROCK: Select STI based on Description Box used: VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; - if(UsingEDBSystem() > 0) + // HEADROCK HAM 4: No more need for two files. Just use one. + //if(UsingEDBSystem() > 0) strcpy( VObjectDesc.ImageFile, "INTERFACE\\infobox_interface_edb.sti" ); - else - strcpy( VObjectDesc.ImageFile, "INTERFACE\\infobox_interface.sti" ); + //else + // strcpy( VObjectDesc.ImageFile, "INTERFACE\\infobox_interface.sti" ); CHECKF( AddVideoObject( &VObjectDesc, &guiItemDescBox) ); if(ubPosition != 255 && UsingNewInventorySystem() == true) @@ -3191,16 +3278,29 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, // HEADROCK: Select STI based on Description Box used: VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; - if(UsingEDBSystem() > 0) + // HEADROCK HAM 4: No more need for two files. Just use the EDB one. + //if(UsingEDBSystem() > 0) strcpy( VObjectDesc.ImageFile, "INTERFACE\\iteminfoc_edb.STI" ); - else - strcpy( VObjectDesc.ImageFile, "INTERFACE\\iteminfoc.STI" ); + //else + // strcpy( VObjectDesc.ImageFile, "INTERFACE\\iteminfoc.STI" ); CHECKF( AddVideoObject( &VObjectDesc, &guiMapItemDescBox) ); + if(UsingNewInventorySystem()) + { + // HEADROCK HAM 4: LBE backgrounds for desc box + VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; + strcpy( VObjectDesc.ImageFile, "INTERFACE\\INFOBOX_LBE.STI" ); + CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoLBEBackground) ); + } + VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; strcpy( VObjectDesc.ImageFile, "INTERFACE\\bullet.STI" ); CHECKF( AddVideoObject( &VObjectDesc, &guiBullet) ); + VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; + strcpy( VObjectDesc.ImageFile, "INTERFACE\\ATTACHMENT_SLOT.STI" ); + CHECKF( AddVideoObject( &VObjectDesc, &guiAttachmentSlot) ); + // HEADROCK: Added new STIs CHECKF( InternalInitEnhancedDescBox() ); @@ -3225,7 +3325,7 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) { guiMoneyButtonImage = LoadButtonImage("INTERFACE\\Info_bil.sti", -1,1,-1,2,-1 ); - for(cnt=0; cnt 0) + { + if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + { + giMapInvDescTabButtonImage= LoadButtonImage( "INTERFACE\\iteminfotabbutton.sti" ,-1,0,-1,1,-1 ); + } + else + { + giInvDescTabButtonImage= LoadButtonImage( "INTERFACE\\iteminfotacticaltabbutton.sti" ,-1,0,-1,1,-1 ); + } + for (cnt = 0; cnt < 3; cnt++) + { + if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + { + giInvDescTabButton[cnt] = CreateIconAndTextButton( giMapInvDescTabButtonImage, gzItemDescTabButtonText[cnt], BLOCKFONT2, + 5, DEFAULT_SHADOW, + 5, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + (UINT16)( gsInvDescX + 11 + (cnt*77) ), (UINT16)( gsInvDescY + 92 + sNASYCorrection( pObject ) ), BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescTabButtonCallback ); + } + else + { + // NAS-specific offset to these buttons + INT16 sNASOffsetX; + if (UseNASDesc( pObject )) + { + sNASOffsetX = 62; + } + else + { + sNASOffsetX = 0; + } + giInvDescTabButton[cnt] = CreateIconAndTextButton( giInvDescTabButtonImage, gzItemDescTabButtonShortText[cnt], BLOCKFONT2, + 5, DEFAULT_SHADOW, + 5, DEFAULT_SHADOW, + TEXT_CJUSTIFIED, + (UINT16)( gsInvDescX + 200 + sNASOffsetX ), (UINT16)( gsInvDescY + 4 + (cnt*63) ), BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescTabButtonCallback ); + } + //giInvDescTabButton[cnt] = QuickCreateButton( giMapInvDescTabButtonImage, (UINT16)( gsInvDescX + 11 + (cnt*77) ), (UINT16)( gsInvDescY + 92 ), + // BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + // DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescTabButtonCallback ); + MSYS_SetBtnUserData( giInvDescTabButton[cnt], 0, cnt); + SetButtonFastHelpText( giInvDescTabButton[ cnt ], gzUDBButtonTooltipText[ cnt ] ); + } + + // Toggle on the button that corresponds to our selected tab. + ItemDescTabButtonOn( gubDescBoxPage ); + } + + // HEADROCK HAM 4: Up/Down Arrow Buttons for Advanced tab. + if (UsingEDBSystem() > 0) + { + INT16 sButtonLocationX; + INT16 sButtonLocationY1; + INT16 sButtonLocationY2; + if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + { + // NAS and NON-NAS uses the same basic coordinates - adds Y Offset as necessary through the NAS-related + // adjustment function. + sButtonLocationX = 224; + sButtonLocationY1 = 118; + sButtonLocationY2 = 295; + } + else + { + // NAS pushes everything 62 pixels right. + if (UseNASDesc(pObject)) + { + sButtonLocationX = 510; + sButtonLocationY1 = 5; + sButtonLocationY2 = 175; + } + else + { + sButtonLocationX = 448; + sButtonLocationY1 = 5; + sButtonLocationY2 = 175; + } + } + + /////////// Up Button + giInvDescAdvButtonUpImage= LoadButtonImage( "INTERFACE\\iteminfoadvancedbutton.sti" ,-1,0,-1,2,-1 ); + giInvDescAdvButton[0] = QuickCreateButton( giInvDescAdvButtonUpImage, (UINT16)( gsInvDescX + sButtonLocationX ), (UINT16)( gsInvDescY + sButtonLocationY1 + sNASYCorrection( pObject ) ), + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescAdvButtonCallback ); + + MSYS_SetBtnUserData( giInvDescAdvButton[0], 0, 0); + + ////////// Down Button + giInvDescAdvButtonDownImage= LoadButtonImage( "INTERFACE\\iteminfoadvancedbutton.sti" ,-1,1,-1,3,-1 ); + giInvDescAdvButton[1] = QuickCreateButton( giInvDescAdvButtonDownImage, (UINT16)( gsInvDescX + sButtonLocationX ), (UINT16)( gsInvDescY + sButtonLocationY2 + sNASYCorrection( pObject ) ), + BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)ItemDescAdvButtonCallback ); + + MSYS_SetBtnUserData( giInvDescAdvButton[1], 0, 1); + + // Hide both buttons. They'll be shown if required. + HideButton( giInvDescAdvButton[0] ); + HideButton( giInvDescAdvButton[1] ); + } + fInterfacePanelDirty = DIRTYLEVEL2; @@ -3314,7 +3518,7 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, } // if ( !(Item[ pObject->usItem ].fFlags & ITEM_HIDDEN_ADDON) && ( ValidAttachment( gpItemPointer->usItem, pObject->usItem ) || ValidLaunchable( gpItemPointer->usItem, pObject->usItem ) || ValidMerge( gpItemPointer->usItem, pObject->usItem ) ) ) - if ( !(Item[ pObject->usItem ].hiddenaddon ) && ( ValidAttachment( gpItemPointer->usItem, pObject->usItem ) || ValidLaunchable( gpItemPointer->usItem, pObject->usItem ) || ValidMerge( gpItemPointer->usItem, pObject->usItem ) ) ) + if ( !(Item[ pObject->usItem ].hiddenaddon ) && ( ValidAttachment( gpItemPointer->usItem, pObject ) || ValidLaunchable( gpItemPointer->usItem, pObject->usItem ) || ValidMerge( gpItemPointer->usItem, pObject->usItem ) ) ) { SetUpFastHelpListRegions( gItemDescHelpText.iXPosition, @@ -3347,44 +3551,160 @@ BOOLEAN InternalInitItemDescriptionBox( OBJECTTYPE *pObject, INT16 sX, INT16 sY, //CHRISL: This function is designed to recreate the attachment tooltips void UpdateAttachmentTooltips(OBJECTTYPE *pObject, UINT8 ubStatusIndex) { - INT32 cnt; + UINT32 slotCount = 0; + + //WarmSteel - Copied most of this from bobby rays attachment listing. No need to reinvent the wheel. + BOOLEAN fAttachmentsFound = FALSE; + // Contains entire string of attachment names + CHAR16 attachStr[2500]; + // Contains current attachment string + CHAR16 attachStr2[100]; + // Contains temporary attachment list before added to string constant from text.h + CHAR16 attachStr3[2500]; + UINT16 usAttachment; + std::vector attachList, parseList; + std::vector usAttachmentSlotIndexVector = GetItemSlots(pObject); //start by deleting the currently defined regions if they exist - for ( cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) + for (INT32 cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) { if( gItemDescAttachmentRegions[cnt].IDNumber != 0 ) MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); } //now, create new regions - for ( cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) + for (slotCount = 0; ;++slotCount ) { + //stopping conditions, not inside the for loop because it is different depending on the attachment system. + if (UsingNewAttachmentSystem()==true) { + if(slotCount >= usAttachmentSlotIndexVector.size()) + break; + } else { + if(slotCount >= OLD_MAX_ATTACHMENTS_101) + break; + } + + //Empty those Strings + swprintf( attachStr, L"" ); + swprintf( attachStr2, L"" ); + swprintf( attachStr3, L"" ); + + fAttachmentsFound = FALSE; + // Build a mouse region here that is over any others..... //if (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) - MSYS_DefineRegion( &gItemDescAttachmentRegions[cnt], (INT16)(gsInvDescX + gItemDescAttachmentsXY[cnt].sX), (INT16)(gsInvDescY + gItemDescAttachmentsXY[cnt].sY), (INT16)(gsInvDescX + gItemDescAttachmentsXY[cnt].sX + gItemDescAttachmentsXY[cnt].sWidth), (INT16)(gsInvDescY + gItemDescAttachmentsXY[cnt].sY + gItemDescAttachmentsXY[cnt].sHeight), MSYS_PRIORITY_HIGHEST, + MSYS_DefineRegion( &gItemDescAttachmentRegions[slotCount], (INT16)(gsInvDescX + gItemDescAttachmentsXY[slotCount].sX), (INT16)(gsInvDescY + gItemDescAttachmentsXY[slotCount].sY), (INT16)(gsInvDescX + gItemDescAttachmentsXY[slotCount].sX + gItemDescAttachmentsXY[slotCount].sWidth), (INT16)(gsInvDescY + gItemDescAttachmentsXY[slotCount].sY + gItemDescAttachmentsXY[slotCount].sHeight), MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescAttachmentsCallback ); else - MSYS_DefineRegion( &gItemDescAttachmentRegions[cnt], (INT16)(gsInvDescX + gItemDescAttachmentsXY[cnt].sX), (INT16)(gsInvDescY + gItemDescAttachmentsXY[cnt].sY), (INT16)(gsInvDescX + gItemDescAttachmentsXY[cnt].sX + gItemDescAttachmentsXY[cnt].sBarDx + gItemDescAttachmentsXY[cnt].sWidth), (INT16)(gsInvDescY + gItemDescAttachmentsXY[cnt].sY + gItemDescAttachmentsXY[cnt].sHeight), MSYS_PRIORITY_HIGHEST, + MSYS_DefineRegion( &gItemDescAttachmentRegions[slotCount], (INT16)(gsInvDescX + gItemDescAttachmentsXY[slotCount].sX), (INT16)(gsInvDescY + gItemDescAttachmentsXY[slotCount].sY), (INT16)(gsInvDescX + gItemDescAttachmentsXY[slotCount].sX + gItemDescAttachmentsXY[slotCount].sBarDx + gItemDescAttachmentsXY[slotCount].sWidth), (INT16)(gsInvDescY + gItemDescAttachmentsXY[slotCount].sY + gItemDescAttachmentsXY[slotCount].sHeight), MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescAttachmentsCallback ); // Add region - MSYS_AddRegion( &gItemDescAttachmentRegions[cnt]); - MSYS_SetRegionUserData( &gItemDescAttachmentRegions[cnt], 0, cnt ); + MSYS_AddRegion( &gItemDescAttachmentRegions[slotCount]); + MSYS_SetRegionUserData( &gItemDescAttachmentRegions[slotCount], 0, slotCount ); //CHRISL: Include the ubStatusIndex in the region information so we know which object in a stack we're looking at - MSYS_SetRegionUserData( &gItemDescAttachmentRegions[cnt], 1, ubStatusIndex ); + MSYS_SetRegionUserData( &gItemDescAttachmentRegions[slotCount], 1, ubStatusIndex ); // CHRISL: Instead of looking at object 0, let's look at the object we actually right clicked on using ubStatusIndex - OBJECTTYPE* pAttachment = (*pObject)[ubStatusIndex]->GetAttachmentAtIndex(cnt); - if (pAttachment) { - SetRegionFastHelpText( &(gItemDescAttachmentRegions[ cnt ]), ItemNames[ pAttachment->usItem ] ); - SetRegionHelpEndCallback( &(gItemDescAttachmentRegions[ cnt ]), HelpTextDoneCallback ); - } - else - { - SetRegionFastHelpText( &(gItemDescAttachmentRegions[ cnt ]), Message[ STR_ATTACHMENTS ] ); - SetRegionHelpEndCallback( &(gItemDescAttachmentRegions[ cnt ]), HelpTextDoneCallback ); + OBJECTTYPE* pAttachment = (*pObject)[ubStatusIndex]->GetAttachmentAtIndex(slotCount); + if (pAttachment->exists()) { + SetRegionFastHelpText( &(gItemDescAttachmentRegions[ slotCount ]), ItemNames[ pAttachment->usItem ] ); + } else if (UsingNewAttachmentSystem()==true && !usAttachmentSlotIndexVector.empty()) { + + UINT16 usLoopSlotID = usAttachmentSlotIndexVector[slotCount]; + attachList.clear(); + + //Print all attachments that fit on this item. + for(UINT16 usLoop = 0; usLoop < MAXATTACHMENTS; usLoop++) + { //We no longer find valid attachments from AttachmentSlots.xml so we need to work a bit harder to get our list + usAttachment = 0; + if(Attachment[usLoop][1] == pObject->usItem && AttachmentSlots[usLoopSlotID].nasAttachmentClass & Item[Attachment[usLoop][0]].nasAttachmentClass) + { //search primary item attachments.xml + usAttachment = Attachment[usLoop][0]; + } + else if(Launchable[usLoop][1] == pObject->usItem && AttachmentSlots[usLoopSlotID].nasAttachmentClass & Item[Launchable[usLoop][0]].nasAttachmentClass) + { //search primary item launchables.xml + usAttachment = Launchable[usLoop][0]; + } + else + { //search for attachments/launchables made valid by other attachments + for(UINT8 x=0; x<(*pObject)[ubStatusIndex]->attachments.size(); x++) + { + OBJECTTYPE* pAttachment2 = (*pObject)[ubStatusIndex]->GetAttachmentAtIndex(x); + if(pAttachment2->exists()) + { + if(Attachment[usLoop][1] == pAttachment2->usItem && AttachmentSlots[usLoopSlotID].nasAttachmentClass & Item[Attachment[usLoop][0]].nasAttachmentClass) + usAttachment = Attachment[usLoop][0]; + else if(Launchable[usLoop][1] == pAttachment2->usItem && AttachmentSlots[usLoopSlotID].nasAttachmentClass & Item[Launchable[usLoop][0]].nasAttachmentClass) + usAttachment = Launchable[usLoop][0]; + } + } + } + if(Attachment[usLoop][0] == 0 && Launchable[usLoop][0] == 0) + break; + + if( usAttachment > 0 && !Item[usAttachment].hiddenaddon && !Item[usAttachment].hiddenattachment && ItemIsLegal(usAttachment)) + attachList.push_back(usAttachment); + } + + if(attachList.size()>0){ + parseList = attachList; + for(std::vector::iterator pIter=parseList.begin(); pIter != parseList.end(); ++pIter){ + BOOLEAN fDuplicate = FALSE; + for(std::vector::iterator aIter=attachList.begin(); aIter != attachList.end();){ + UINT16 pi = *pIter; + UINT16 ai = *aIter; + if(pi == ai && !fDuplicate){ + fDuplicate = TRUE; + ++aIter; + continue; + } else if(pi == ai && fDuplicate){ + aIter = attachList.erase(aIter); + continue; + } else { + ++aIter; + } + } + } + } + for(UINT16 loop = 0; loop < attachList.size(); loop++){ + usAttachment = attachList[loop]; + // If the attachment is not hidden + if (usAttachment > 0 && !Item[ usAttachment ].hiddenaddon && !Item[ usAttachment ].hiddenattachment) + { + if (wcslen( attachStr3 ) + wcslen(Item[usAttachment].szItemName) > 3600) + { + // End list early to avoid overflow + wcscat( attachStr3, L"\n..." ); + break; + } + else + {// Add the attachment's name to the list. + fAttachmentsFound = TRUE; + swprintf( attachStr2, L"\n%s", Item[ usAttachment ].szItemName ); + wcscat( attachStr3, attachStr2); + } + } + } + + if (fAttachmentsFound) + { + // Add extra empty line and attachment list title + swprintf( attachStr, L"%s:\n ", Message[ STR_ATTACHMENTS ] ); + // Print the attachments + wcscat( attachStr, attachStr3 ); + } else if(usLoopSlotID != 0) { + swprintf( attachStr2, L"\n%s", AttachmentSlots[usLoopSlotID].szSlotName ); + wcscat( attachStr, attachStr2); + } else { + wcscat( attachStr, Message[ STR_ATTACHMENTS ] ); + } + SetRegionFastHelpText( &(gItemDescAttachmentRegions[ slotCount ]), attachStr ); + } else { + SetRegionFastHelpText( &(gItemDescAttachmentRegions[ slotCount ]), Message[ STR_ATTACHMENTS ] ); } + SetRegionHelpEndCallback( &(gItemDescAttachmentRegions[ slotCount ]), HelpTextDoneCallback ); } } @@ -3488,7 +3808,7 @@ void ItemDescAmmoCallback(GUI_BUTTON *btn,INT32 reason) //holding an item if(Magazine[Item[gpItemPointer->usItem].ubClassIndex].ubCalibre == Weapon[Item[gpItemDescObject->usItem].ubClassIndex].ubCalibre) { - ReloadGun(gpItemDescSoldier, gpItemDescObject, gpItemPointer); + ReloadGun(gpItemDescSoldier, gpItemDescObject, gpItemPointer, ubStatusIndex); } if(gpItemPointer->ubNumberOfObjects == 0) { @@ -3627,9 +3947,9 @@ void ItemDescAmmoCallback(GUI_BUTTON *btn,INT32 reason) //CHRISL: We need to know which item in the stack we're working with. -void DoAttachment( UINT8 subObject ) +void DoAttachment( UINT8 subObject, INT32 iItemPos ) { - if ( gpItemDescObject->AttachObject( gpItemDescSoldier, gpItemPointer, TRUE, subObject ) ) + if ( gpItemDescObject->AttachObject( gpItemDescSoldier, gpItemPointer, TRUE, subObject, iItemPos) ) { if (gpItemPointer->exists() == false) { @@ -3679,7 +3999,7 @@ void PermanantAttachmentMessageBoxCallBack( UINT8 ubExitValue ) { if ( ubExitValue == MSG_BOX_RETURN_YES ) { - DoAttachment(0); + DoAttachment(0, iItemPosition); } // else do nothing } @@ -3689,7 +4009,7 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) UINT32 uiItemPos, ubStatusIndex; static BOOLEAN fRightDown = FALSE; - if ( gfItemDescObjectIsAttachment ) + if ( gfItemDescObjectIsAttachment || !gpItemDescObject->exists() ) { // screen out completely return; @@ -3712,19 +4032,44 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) if ( gpItemPointer != NULL ) { // nb pointer could be NULL because of inventory manipulation in mapscreen from sector inv - if ( !gpItemPointerSoldier || EnoughPoints( gpItemPointerSoldier, AttachmentAPCost( gpItemPointer->usItem, gpItemDescObject->usItem ), 0, TRUE ) ) + if ( !gpItemPointerSoldier || EnoughPoints( gpItemPointerSoldier, AttachmentAPCost( gpItemPointer->usItem, gpItemDescObject, gpItemPointerSoldier ), 0, TRUE ) ) { // if ( (Item[ gpItemPointer->usItem ].fFlags & ITEM_INSEPARABLE) && ValidAttachment( gpItemPointer->usItem, gpItemDescObject->usItem ) ) - if ( (Item[ gpItemPointer->usItem ].inseparable ) && ValidAttachment( gpItemPointer->usItem, gpItemDescObject->usItem ) ) + if ( (Item[ gpItemPointer->usItem ].inseparable ) && ValidAttachment( gpItemPointer->usItem, gpItemDescObject ) ) { + iItemPosition = uiItemPos; DoScreenIndependantMessageBox( Message[ STR_PERMANENT_ATTACHMENT ], ( UINT8 )MSG_BOX_FLAG_YESNO, PermanantAttachmentMessageBoxCallBack ); return; } - DoAttachment((UINT8)ubStatusIndex); + DoAttachment((UINT8)ubStatusIndex, uiItemPos); + if(gpItemPointer->exists()){ + if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + { + // Set mouse + guiExternVo = GetInterfaceGraphicForItem( &(Item[ gpItemPointer->usItem ]) ); + gusExternVoSubIndex = Item[ gpItemPointer->usItem ].ubGraphicNum; + + MSYS_ChangeRegionCursor( &gMPanelRegion , EXTERN_CURSOR ); + MSYS_SetCurrentCursor( EXTERN_CURSOR ); + fMapInventoryItem=TRUE; + fTeamPanelDirty=TRUE; + } + + //Dirty interface + fInterfacePanelDirty = DIRTYLEVEL2; + + // re-evaluate repairs + gfReEvaluateEveryonesNothingToDo = TRUE; + + UpdateItemHatches(); + + + } if(gpItemDescObject != NULL) { + InitDescStatCoords(gpItemDescObject); UpdateAttachmentTooltips(gpItemDescObject, ubStatusIndex); InternalInitEDBTooltipRegion(gpItemDescObject, guiCurrentItemDescriptionScreen); } @@ -3733,11 +4078,11 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) else { // ATE: Make sure we have enough AP's to drop it if we pick it up! - if ( pAttachment && EnoughPoints( gpItemDescSoldier, ( AttachmentAPCost( pAttachment->usItem, gpItemDescObject->usItem ) + APBPConstants[AP_PICKUP_ITEM] ), 0, TRUE ) ) + if ( pAttachment->exists() && EnoughPoints( gpItemDescSoldier, ( AttachmentAPCost( pAttachment->usItem, gpItemDescObject, gpItemPointerSoldier ) + APBPConstants[AP_PICKUP_ITEM] ), 0, TRUE ) ) { // Get attachment if there is one // The follwing function will handle if no attachment is here - if ( gpItemDescObject->RemoveAttachment( pAttachment, &gItemPointer, ubStatusIndex ) ) + if ( gpItemDescObject->RemoveAttachment( pAttachment, &gItemPointer, ubStatusIndex, gpItemDescSoldier ) ) { gpItemPointer = &gItemPointer; gpItemPointerSoldier = gpItemDescSoldier; @@ -3769,13 +4114,14 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) UpdateItemHatches(); - if(gpItemDescObject != NULL) - { - UpdateAttachmentTooltips(gpItemDescObject, ubStatusIndex); - InternalInitEDBTooltipRegion(gpItemDescObject, guiCurrentItemDescriptionScreen); - } } } + if(gpItemDescObject != NULL) + { + InitDescStatCoords(gpItemDescObject); + UpdateAttachmentTooltips(gpItemDescObject, ubStatusIndex); + InternalInitEDBTooltipRegion(gpItemDescObject, guiCurrentItemDescriptionScreen); + } } } else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN ) @@ -3786,7 +4132,7 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) { fRightDown = FALSE; - if ( pAttachment ) + if ( pAttachment->exists() ) { static OBJECTTYPE Object2; @@ -3798,7 +4144,9 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) fShopkeeperItem = TRUE; } + OBJECTTYPE *pTemp = gpItemDescObject; DeleteItemDescriptionBox( ); + gpItemDescPrevObject = pTemp; Object2 = *pAttachment; gfItemDescObjectIsAttachment = TRUE; @@ -3813,6 +4161,7 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) } } +/*INT8 DetermineShowBox( ) INT8 DetermineShowBox( ) { if(gpItemDescObject == NULL) @@ -3825,19 +4174,22 @@ INT8 DetermineShowBox( ) if (UsingEDBSystem() == 2) { if (Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_EXPLOSV|IC_AMMO|IC_ARMOUR|IC_PUNCH) && UsingEDBSystem() > 0 ) - return 6; + return(UsingNewAttachmentSystem()==true ? 8 : 6); else - return 7; + return(UsingNewAttachmentSystem()==true ? 9 : 7); } else if (guiCurrentItemDescriptionScreen == MAP_SCREEN) { if (Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_EXPLOSV|IC_AMMO|IC_ARMOUR|IC_PUNCH) && UsingEDBSystem() > 0 ) - return 6; + return(UsingNewAttachmentSystem()==true ? 7 : 6); else - return 1; + if(UsingEDBSystem() > 0) + return(UsingNewAttachmentSystem()==true ? 8 : 1); + else + return(UsingNewAttachmentSystem()==true ? 6 : 1); } else - return 0; + return(UsingNewAttachmentSystem()==true ? 5 : 0); } else if(UsingNewInventorySystem() == true) //NIV { @@ -3845,32 +4197,274 @@ INT8 DetermineShowBox( ) return (gpItemDescObject->GetLBEPointer(gubItemDescStatusIndex)->lbeClass + (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 1 : 0)); else if(Item[gpItemDescObject->usItem].usItemClass == IC_LBEGEAR) return (LoadBearingEquipment[Item[gpItemDescObject->usItem].ubClassIndex].lbeClass + (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 1 : 0)); - else if (Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_EXPLOSV|IC_AMMO|IC_ARMOUR|IC_PUNCH) && UsingEDBSystem() > 0 ) - return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 6 : 5); - else - return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 1 : 0); + else if (Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_EXPLOSV|IC_AMMO|IC_ARMOUR|IC_PUNCH) && UsingEDBSystem() > 0 ){ + if(UsingNewAttachmentSystem()==true) + return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 7 : 8); + else + return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 6 : 5); + }else{ + if(UsingNewAttachmentSystem()==true && UsingEDBSystem() > 0 && Item[gpItemDescObject->usItem].usItemClass != IC_MONEY) + return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 8 : 9); + else if(UsingNewAttachmentSystem()==true && Item[gpItemDescObject->usItem].usItemClass != IC_MONEY) + return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 6 : 5); + else + return (guiCurrentItemDescriptionScreen == MAP_SCREEN ? 1 : 0); + } } return 0; +}*/ + +INT8 DetermineShowBox( ) +{ + INT8 bShowBox = 0; + + // HEADROCK HAM 4: Function altered for Ultra Description Box + + if(gpItemDescObject == NULL) + return 0; + + if(iResolution == 0) + return 0; + + if(UsingEDBSystem() <= 0) + if (guiCurrentItemDescriptionScreen == MAP_SCREEN) + if (UseNASDesc( gpItemDescObject) ) + return 2; + else + return 1; + else + if (UseNASDesc( gpItemDescObject) ) + return 1; + else + return 0; + + if(UsingNewInventorySystem() == false) //OIV + { + if (guiCurrentItemDescriptionScreen == MAP_SCREEN) + { + if (UsingEDBSystem() > 0) + { + if (Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_PUNCH)) + { + switch (gubDescBoxPage) + { + case 0: + bShowBox = 3; + break; + case 1: + bShowBox = 4; + break; + case 2: + bShowBox = 6; + break; + } + } + else + { + switch (gubDescBoxPage) + { + case 0: + bShowBox = 3; + break; + case 1: + bShowBox = 5; + break; + case 2: + bShowBox = 6; + break; + } + } + } + else + { + if (UseNASDesc( gpItemDescObject) ) + bShowBox = 2; + else + bShowBox = 1; + } + } + else + return 0; // Tactical OIV no longer enables UDB. It always defaults to ODB. + } + else if(UsingNewInventorySystem() == true) //NIV + { + if (Item[gpItemDescObject->usItem].usItemClass & (IC_WEAPON|IC_PUNCH) && UsingEDBSystem() > 0 ) + { + if (guiCurrentItemDescriptionScreen == MAP_SCREEN) + { + switch (gubDescBoxPage) + { + case 0: + bShowBox = 3; + break; + case 1: + bShowBox = 4; + break; + case 2: + bShowBox = 6; + break; + } + } + else + { + switch (gubDescBoxPage) + { + case 0: + bShowBox = 2; + break; + case 1: + bShowBox = 3; + break; + case 2: + bShowBox = 5; + break; + } + } + } + else if (UsingEDBSystem() > 0) + { + if (guiCurrentItemDescriptionScreen == MAP_SCREEN) + { + switch (gubDescBoxPage) + { + case 0: + bShowBox = 3; + break; + case 1: + bShowBox = 5; + break; + case 2: + bShowBox = 6; + break; + } + } + else + { + switch (gubDescBoxPage) + { + case 0: + bShowBox = 2; + break; + case 1: + bShowBox = 4; + break; + case 2: + bShowBox = 5; + break; + } + } + } + else + if (UseNASDesc( gpItemDescObject) ) + bShowBox = 2; + else + bShowBox = 1; + } + + if (UsingEDBSystem() > 0 && UseNASDesc( gpItemDescObject )) + { + bShowBox += 4; + } + + return bShowBox; +} + +// HEADROCK HAM 4: This picks an LBE picture to be displayed on top of the description box when necessary. +INT8 DetermineShowLBE( ) +{ + if(gpItemDescObject == NULL) + return -1; + + if(iResolution == 0) + return -1; + + if(!UsingNewInventorySystem()) + { + return -1; + } + else + { + if(!(gpItemDescObject->IsActiveLBE(gubItemDescStatusIndex) || Item[gpItemDescObject->usItem].usItemClass == IC_LBEGEAR)) + { + return -1; + } + else + { + if(gpItemDescObject->IsActiveLBE(gubItemDescStatusIndex)) + return (gpItemDescObject->GetLBEPointer(gubItemDescStatusIndex)->lbeClass - 1); + else if(Item[gpItemDescObject->usItem].usItemClass == IC_LBEGEAR) + return (LoadBearingEquipment[Item[gpItemDescObject->usItem].ubClassIndex].lbeClass - 1); + else + return -1; + } + } +} + +// HEADROCK HAM 4: Function to get the number of the item condition string +UINT8 GetConditionString( UINT8 ubStatus, UINT8 *ubFontColor ) +{ + if (ubStatus > 99) + { + *ubFontColor = FONT_WHITE; + return 0; + } + else if (ubStatus >= 95 && ubStatus <= 99) + { + *ubFontColor = FONT_LTGREEN; + return 1; + } + else if (ubStatus >= 80 && ubStatus <= 94) + { + *ubFontColor = FONT_GREEN; + return 2; + } + else if (ubStatus >= 60 && ubStatus <= 79) + { + *ubFontColor = FONT_YELLOW; + return 3; + } + else if (ubStatus >= 40 && ubStatus <= 59) + { + *ubFontColor = FONT_ORANGE; + return 4; + } + else if (ubStatus >= 10 && ubStatus <= 39) + { + *ubFontColor = FONT_RED; + return 5; + } + else if (ubStatus < 10) + { + *ubFontColor = FONT_DKRED; + return 6; + } + // Default + else + { + return 0; + } } void RenderItemDescriptionBox( ) { - ETRLEObject *pTrav; - UINT32 usHeight, usWidth; - INT16 sCenX, sCenY, sStrX; - HVOBJECT hVObject; - CHAR16 sTempString[ 128 ]; + ETRLEObject *pTrav; + UINT32 usHeight, usWidth; + INT32 sOffsetX, sOffsetY; + INT16 sCenX, sCenY, sStrX; + HVOBJECT hVObject; + CHAR16 sTempString[ 128 ]; - UINT16 uiStringLength, uiRightLength; - static CHAR16 pStr[ 100 ]; - INT32 cnt; - FLOAT fWeight; - INT16 usX, usY; - INT16 ubAttackAPs; - BOOLEAN fHatchOutAttachments = gfItemDescObjectIsAttachment; // if examining attachment, always hatch out attachment slots - INT16 sProsConsIndent; - INT8 showBox=DetermineShowBox(); + UINT16 uiStringLength; + static CHAR16 pStr[ 100 ]; + INT32 cnt; + FLOAT fWeight; + INT16 usX, usY; + INT16 ubAttackAPs; + INT16 sProsConsIndent; + INT8 showBox = DetermineShowBox(); + INT8 showLBE = DetermineShowLBE(); + std::vector usAttachmentSlotIndexVector = GetItemSlots(gpItemDescObject, gubItemDescStatusIndex); int status = 0; int shotsLeft = 0; @@ -3883,14 +4477,33 @@ void RenderItemDescriptionBox( ) { // TAKE A LOOK AT THE VIDEO OBJECT SIZE ( ONE OF TWO SIZES ) AND CENTER! GetVideoObject( &hVObject, guiItemGraphic ); - pTrav = &(hVObject->pETRLEObject[ 0 ] ); - usHeight = (UINT32)pTrav->usHeight; - usWidth = (UINT32)pTrav->usWidth; + if(hVObject->ubBitDepth == 8) + { + pTrav = &(hVObject->pETRLEObject[ 0 ] ); + usHeight = (UINT32)pTrav->usHeight; + usWidth = (UINT32)pTrav->usWidth; + sOffsetX = (INT32)pTrav->sOffsetX; + sOffsetY = (INT32)pTrav->sOffsetY; + } + else if(hVObject->ubBitDepth == 16 && hVObject->p16BPPObject) + { + usHeight = hVObject->p16BPPObject->usHeight; + usWidth = hVObject->p16BPPObject->usWidth; + sOffsetX = hVObject->p16BPPObject->sOffsetX; + sOffsetY = hVObject->p16BPPObject->sOffsetY; + } + else if(hVObject->ubBitDepth == 32) + { + usHeight = hVObject->p16BPPObject->usHeight; + usWidth = hVObject->p16BPPObject->usWidth; + sOffsetX = hVObject->p16BPPObject->sOffsetX; + sOffsetY = hVObject->p16BPPObject->sOffsetY; + } // CENTER IN SLOT! // REMOVE OFFSETS! - sCenX = ITEMDESC_ITEM_X + (INT16)( abs( ITEMDESC_ITEM_WIDTH - (double)usWidth ) / 2 ) - pTrav->sOffsetX; - sCenY = ITEMDESC_ITEM_Y + (INT16)( abs( ITEMDESC_ITEM_HEIGHT - (double)usHeight ) / 2 )- pTrav->sOffsetY; + sCenX = ITEMDESC_ITEM_X + (INT16)( abs( ITEMDESC_ITEM_WIDTH - (double)usWidth ) / 2 ) - sOffsetX; + sCenY = ITEMDESC_ITEM_Y + (INT16)( abs( ITEMDESC_ITEM_HEIGHT - (double)usHeight ) / 2 )- sOffsetY; RenderBackpackButtons(1); /* CHRISL: Needed for new inventory backpack buttons */ @@ -3903,6 +4516,29 @@ void RenderItemDescriptionBox( ) BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemDescBox, showBox, gsInvDescX, gsInvDescY, VO_BLT_SRCTRANSPARENCY, NULL ); } + //WarmSteel - Draw the attachment slots needed for NAS, read their positions from XML. + if(UsingNewAttachmentSystem()==true && UseNASDesc(gpItemDescObject) && !usAttachmentSlotIndexVector.empty()){ + + for(UINT16 slotCount = 0; slotCount < usAttachmentSlotIndexVector.size(); slotCount++){ + INT16 sX = gsInvDescX + AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].usDescPanelPosX - 6; //Warmsteel - Retracting a number to account for the status bar. + INT16 sY = gsInvDescY + AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].usDescPanelPosY - 1; + + //WarmSteel - Clear the background rectangle so we can paint it. + if ( guiSAVEBUFFER == FRAME_BUFFER ) + { + InvalidateRegion( sX, sY, (INT16)(sX + 8), (INT16)(sY + 8 ) ); + } + else + { + RestoreExternBackgroundRect( sX, sY, 8, 8 ); + } + if(AttachmentSlots[usAttachmentSlotIndexVector[slotCount]].fBigSlot){ + BltVideoObjectFromIndex( guiSAVEBUFFER, guiAttachmentSlot, 1, sX, sY, VO_BLT_SRCTRANSPARENCY, NULL ); + } else { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiAttachmentSlot, 0, sX, sY, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + } //Display the money 'seperating' border if ( gpItemDescObject->usItem == MONEY ) { @@ -3911,8 +4547,10 @@ void RenderItemDescriptionBox( ) } // Display item - if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) BltVideoObjectOutlineShadowFromIndex( guiSAVEBUFFER, guiItemGraphic, 0, sCenX - 2, sCenY + 2 ); - + if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) + { + BltVideoObjectOutlineShadowFromIndex( guiSAVEBUFFER, guiItemGraphic, 0, sCenX - 2, sCenY + 2 ); + } BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemGraphic, 0, sCenX, sCenY, VO_BLT_SRCTRANSPARENCY, NULL ); // Display status @@ -3925,16 +4563,53 @@ void RenderItemDescriptionBox( ) RenderLBENODEItems( gpItemDescObject, gubItemDescStatusIndex ); } + // HEADROCK HAM 4: First, display LBE Background + if(UsingNewInventorySystem() == true && Item[gpItemDescObject->usItem].usItemClass == IC_LBEGEAR && showLBE >= 0) + { + // Exchange LBE images to conserve space in tactical, as appropriate for the UDB/ODB system used. + INT8 showLBEImage = showLBE; + if (guiCurrentItemDescriptionScreen != MAP_SCREEN) + if (UsingEDBSystem() > 0) + showLBEImage += 4; + else + showLBEImage += 8; + + // Draw LBE background image + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoLBEBackground, showLBEImage, gItemDescLBEBackground[showLBE].sLeft, gItemDescLBEBackground[showLBE].sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + // Render LBE items + RenderLBENODEItems( gpItemDescObject, gubItemDescStatusIndex ); + } + if (gpItemPointer) { -// if ( ( Item[ gpItemPointer->usItem ].fFlags & ITEM_HIDDEN_ADDON ) || - if ( ( Item[ gpItemPointer->usItem ].hiddenaddon ) || - - ( !ValidItemAttachment( gpItemDescObject, gpItemPointer->usItem, FALSE ) && - !ValidMerge( gpItemPointer->usItem, gpItemDescObject->usItem ) && !ValidLaunchable( gpItemPointer->usItem, gpItemDescObject->usItem ) ) ) + if(UsingNewAttachmentSystem()==true) { - // hatch out the attachment panels - fHatchOutAttachments = TRUE; + //WarmSteel - This hatches out attachment slots one by one, instead of all of em. + for(cnt = 0; cnt < (INT32)(*gpItemDescObject)[gubItemDescStatusIndex]->attachments.size(); cnt++) + { + //if ( ( Item[ gpItemPointer->usItem ].fFlags & ITEM_HIDDEN_ADDON ) || + if ( ( Item[ gpItemPointer->usItem ].hiddenaddon ) || + + ( !ValidItemAttachmentSlot( gpItemDescObject, gpItemPointer->usItem, FALSE, FALSE, gubItemDescStatusIndex, cnt, FALSE, NULL, usAttachmentSlotIndexVector) && + !ValidMerge( gpItemPointer->usItem, gpItemDescObject->usItem ) ) ) + { + // hatch out this attachment panel + DrawHatchOnInventory( guiSAVEBUFFER, (INT16) (gsInvDescX + gItemDescAttachmentsXY[ cnt ].sX), (INT16) (gsInvDescY + gItemDescAttachmentsXY[ cnt ].sY - 2), (INT16)(gItemDescAttachmentsXY[ cnt ].sWidth + gItemDescAttachmentsXY[ cnt ].sBarDx), (INT16) (gItemDescAttachmentsXY[ cnt ].sHeight + 2) ); + } + } + } else { + for(cnt = 0; cnt < OLD_MAX_ATTACHMENTS_101; cnt++) + { + //if ( ( Item[ gpItemPointer->usItem ].fFlags & ITEM_HIDDEN_ADDON ) || + if ( ( Item[ gpItemPointer->usItem ].hiddenaddon ) || + + ( !ValidItemAttachment( gpItemDescObject, gpItemPointer->usItem, FALSE, FALSE, gubItemDescStatusIndex, usAttachmentSlotIndexVector) && + !ValidMerge( gpItemPointer->usItem, gpItemDescObject->usItem ) && !ValidLaunchable( gpItemPointer->usItem, gpItemDescObject->usItem ) ) ) + { + // hatch out the attachment panels + DrawHatchOnInventory( guiSAVEBUFFER, (INT16) (gsInvDescX + gItemDescAttachmentsXY[ cnt ].sX), (INT16) (gsInvDescY + gItemDescAttachmentsXY[ cnt ].sY - 2), (INT16)(gItemDescAttachmentsXY[ cnt ].sWidth + gItemDescAttachmentsXY[ cnt ].sBarDx), (INT16) (gItemDescAttachmentsXY[ cnt ].sHeight + 2) ); + } + } } } @@ -3943,21 +4618,29 @@ void RenderItemDescriptionBox( ) for (attachmentList::iterator iter = (*gpItemDescObject)[gubItemDescStatusIndex]->attachments.begin(); iter != (*gpItemDescObject)[gubItemDescStatusIndex]->attachments.end(); ++iter, ++cnt) { - sCenX = gsInvDescX + gItemDescAttachmentsXY[cnt].sX; - sCenY = gsInvDescY + gItemDescAttachmentsXY[cnt].sY; - INVRenderItem( guiSAVEBUFFER, NULL, gpItemDescObject, sCenX, sCenY, gItemDescAttachmentsXY[cnt].sWidth, gItemDescAttachmentsXY[cnt].sHeight, DIRTYLEVEL2, NULL, (UINT8)(RENDER_ITEM_ATTACHMENT1 + cnt), FALSE, 0, gubItemDescStatusIndex ); - sCenX = sCenX + gItemDescAttachmentsXY[cnt].sBarDx; - sCenY = sCenY + gItemDescAttachmentsXY[cnt].sBarDy; - DrawItemUIBarEx( gpItemDescObject, (UINT8)(DRAW_ITEM_STATUS_ATTACHMENT1 + cnt), sCenX, sCenY, ITEM_BAR_WIDTH, ITEM_BAR_HEIGHT, Get16BPPColor( STATUS_BAR ), Get16BPPColor( STATUS_BAR_SHADOW ), TRUE , guiSAVEBUFFER, gubItemDescStatusIndex ); - } - for (cnt = 0; cnt < MAX_ATTACHMENTS; ++cnt) - { - if (fHatchOutAttachments) - { - DrawHatchOnInventory( guiSAVEBUFFER, (INT16) (gsInvDescX + gItemDescAttachmentsXY[ cnt ].sX), (INT16) (gsInvDescY + gItemDescAttachmentsXY[ cnt ].sY - 2), (INT16)(gItemDescAttachmentsXY[ cnt ].sWidth + gItemDescAttachmentsXY[ cnt ].sBarDx), (INT16) (gItemDescAttachmentsXY[ cnt ].sHeight + 2) ); + if(iter->exists()){ + sCenX = gsInvDescX + gItemDescAttachmentsXY[cnt].sX; + sCenY = gsInvDescY + gItemDescAttachmentsXY[cnt].sY; + INVRenderItem( guiSAVEBUFFER, NULL, gpItemDescObject, sCenX, sCenY, gItemDescAttachmentsXY[cnt].sWidth, gItemDescAttachmentsXY[cnt].sHeight, DIRTYLEVEL2, NULL, (UINT8)(RENDER_ITEM_ATTACHMENT1 + cnt), FALSE, 0, gubItemDescStatusIndex ); + sCenX = sCenX + gItemDescAttachmentsXY[cnt].sBarDx; + sCenY = sCenY + gItemDescAttachmentsXY[cnt].sBarDy; + DrawItemUIBarEx( gpItemDescObject, (UINT8)(DRAW_ITEM_STATUS_ATTACHMENT1 + cnt), sCenX, sCenY, ITEM_BAR_WIDTH, ITEM_BAR_HEIGHT, Get16BPPColor( STATUS_BAR ), Get16BPPColor( STATUS_BAR_SHADOW ), TRUE , guiSAVEBUFFER, gubItemDescStatusIndex ); } } + // HEADROCK HAM 4: If vieweing the UDB Advanced page, reveal buttons and set them as appropriate + if (UsingEDBSystem() && gubDescBoxPage == 2) + { + ShowButton( giInvDescAdvButton[0] ); + ShowButton( giInvDescAdvButton[1] ); + ItemDescAdvButtonCheck(); + } + else if (UsingEDBSystem()) + { + HideButton( giInvDescAdvButton[0] ); + HideButton( giInvDescAdvButton[1] ); + } + //HEADROCK/CHRISL: This condition needs to run differently depending on whether EDB is active of not if(UsingEDBSystem() > 0) { @@ -3988,20 +4671,20 @@ void RenderItemDescriptionBox( ) { // display bullets for ROF if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) - BltVideoObjectFromIndex( guiSAVEBUFFER, guiBullet, 0, BULLET_SING_X, BULLET_SING_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiBullet, 0, gODBItemDescRegions[3][1].sLeft, gODBItemDescRegions[3][1].sTop, VO_BLT_SRCTRANSPARENCY, NULL ); if ( GetShotsPerBurst(gpItemDescObject) > 0 ) { for ( cnt = 0; cnt < __min(GetShotsPerBurst(gpItemDescObject),12); cnt++ ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiBullet, 0, BULLET_BURST_X + cnt * (BULLET_WIDTH/2 + 1), BULLET_BURST_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiBullet, 0, gODBItemDescRegions[3][4].sLeft + cnt * (BULLET_WIDTH/2 + 1), gODBItemDescRegions[3][4].sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } else if ( GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) { for ( cnt = 0; cnt < 10; cnt++ ) { - BltVideoObjectFromIndex( guiSAVEBUFFER, guiBullet, 0, BULLET_BURST_X + cnt * (BULLET_WIDTH/2 + 1), BULLET_BURST_Y, VO_BLT_SRCTRANSPARENCY, NULL ); + BltVideoObjectFromIndex( guiSAVEBUFFER, guiBullet, 0, gODBItemDescRegions[3][4].sLeft + cnt * (BULLET_WIDTH/2 + 1), gODBItemDescRegions[3][4].sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } @@ -4020,6 +4703,12 @@ void RenderItemDescriptionBox( ) RenderLBENODEItems( gpItemDescObject, gubItemDescStatusIndex ); } + //////////////////////////////////////////////////////////////////////////////////// + // This section displays on screen all values that are common to both EDB and ODB. + // They are drawn based on variable coordinates, which have been set beforehand + // based on the system being used. + //////////////////////////////////////////////////////////////////////////////////// + // Render font desc SetFont( ITEMDESC_FONT ); SetFontBackground( FONT_MCOLOR_BLACK ); @@ -4034,15 +4723,11 @@ void RenderItemDescriptionBox( ) mprintf( ITEMDESC_NAME_X, ITEMDESC_NAME_Y, L"%s", gzItemName ); #endif - // Render "normal" item data - SetFontForeground( FONT_BLACK ); - SetFontShadow( ITEMDESC_FONTSHADOW2 ); - - // Item Full Description - DisplayWrappedString( (INT16)ITEMDESC_DESC_START_X, (INT16)ITEMDESC_DESC_START_Y, ITEMDESC_DESC_WIDTH, 2, ITEMDESC_FONT, FONT_BLACK, gzItemDesc, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - + // Render extra data on name bar for weapons and launchers (Caliber, Fingerprints) if ( ITEM_PROS_AND_CONS( gpItemDescObject->usItem ) ) { + SetFontForeground( FONT_BLACK ); + SetFontShadow( ITEMDESC_FONTSHADOW2 ); // Caliber if ( (Item[gpItemDescObject->usItem].fingerprintid ) && (*gpItemDescObject)[gubItemDescStatusIndex]->data.ubImprintID < NO_PROFILE ) { @@ -4057,46 +4742,204 @@ void RenderItemDescriptionBox( ) FindFontRightCoordinates( (INT16) ITEMDESC_CALIBER_X, (INT16) ITEMDESC_CALIBER_Y, ITEMDESC_CALIBER_WIDTH, ITEM_STATS_HEIGHT, pStr, ITEMDESC_FONT, &usX, &usY); mprintf( usX, usY, pStr ); - - SetFontForeground( FONT_MCOLOR_DKWHITE2 ); - SetFontShadow( ITEMDESC_FONTSHADOW3 ); - // PROs - mprintf( (INT16)ITEMDESC_PROS_START_X, (INT16)ITEMDESC_PROS_START_Y, gzProsLabel ); - - // HEADROCK: Disabled PROs/CONs text for OIV EDB Tactical - if (UsingEDBSystem() != 2) - { - sProsConsIndent = __max( StringPixLength( gzProsLabel, ITEMDESC_FONT ), StringPixLength( gzConsLabel, ITEMDESC_FONT ) ) + 10; - gzItemPros[0] = 0; - GenerateProsString( gzItemPros, gpItemDescObject, ITEMDESC_DESC_WIDTH - sProsConsIndent - StringPixLength( DOTDOTDOT, ITEMDESC_FONT ) ); - if (gzItemPros[0] != 0) - { - SetFontForeground( FONT_BLACK ); - SetFontShadow( ITEMDESC_FONTSHADOW2 ); - DisplayWrappedString( (INT16)(ITEMDESC_PROS_START_X + sProsConsIndent), (INT16)ITEMDESC_PROS_START_Y, (INT16)(ITEMDESC_DESC_WIDTH - sProsConsIndent), 2, ITEMDESC_FONT, FONT_BLACK, gzItemPros, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); - } - } - - SetFontForeground( FONT_MCOLOR_DKWHITE2 ); - SetFontShadow( ITEMDESC_FONTSHADOW3 ); - // CONs - mprintf( (INT16)ITEMDESC_CONS_START_X, (INT16)ITEMDESC_CONS_START_Y, gzConsLabel ); - - // HEADROCK: Disabled PROs/CONs text for OIV EDB Tactical - if (UsingEDBSystem() != 2) - { - GenerateConsString( gzItemCons, gpItemDescObject, ITEMDESC_DESC_WIDTH - sProsConsIndent - StringPixLength( DOTDOTDOT, ITEMDESC_FONT ) ); - if (gzItemCons[0] != 0) - { - SetFontForeground( FONT_BLACK ); - SetFontShadow( ITEMDESC_FONTSHADOW2 ); - DisplayWrappedString( (INT16)(ITEMDESC_CONS_START_X + sProsConsIndent), (INT16)ITEMDESC_CONS_START_Y, (INT16)(ITEMDESC_DESC_WIDTH - sProsConsIndent), 2, ITEMDESC_FONT, FONT_BLACK, gzItemCons, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); - } - } } - // Get length of string - uiRightLength=35; + ///////////////////////////////////////////////////////////////////////////////////// + // Render Item DESCRIPTION page. Contains the item's full-text description, item + // condition, item weight, and for weapons also PROS and CONS. + if (UsingEDBSystem() == 0 || gubDescBoxPage == 0) + { + UINT8 ForegroundColor; + UINT8 ShadowColor; + SetFont( BLOCKFONT2 ); + + /////////// DISPLAY FULL DESCRIPTION TEXT + if (UsingEDBSystem()) + { + ForegroundColor = 6; + ShadowColor = DEFAULT_SHADOW; + } + else + { + ForegroundColor = FONT_MCOLOR_BLACK; + ShadowColor = ITEMDESC_FONTSHADOW2; + } + SetFontShadow( ShadowColor ); + + DisplayWrappedString( gItemDescTextRegions[0].sLeft, gItemDescTextRegions[0].sTop, gItemDescTextRegions[0].sRight - gItemDescTextRegions[0].sLeft, 2, ITEMDESC_FONT, ForegroundColor, gzItemDesc, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + + /////////// DISPLAY CONDITION + ForegroundColor = 6; + SetFontShadow( DEFAULT_SHADOW ); + + // Note: for Ammo items, remaining bullets replace condition, so it's handled later on. + // For money, condition is irrelevant, and not displayed here. + if ( Item[ gpItemDescObject->usItem ].usItemClass != IC_AMMO && Item[ gpItemDescObject->usItem ].usItemClass != IC_MONEY ) + { + ////////// label + if (UsingEDBSystem()) + { + // UDB system displays a string with colored condition text. + SetFontForeground( ForegroundColor ); + swprintf( pStr, L"%s", gConditionDesc[0] ); // "In " + mprintf( gItemDescTextRegions[1].sLeft, gItemDescTextRegions[1].sTop, pStr ); + // Record length + INT16 indent = StringPixLength( gConditionDesc[0], ITEMDESC_FONT ); + + UINT8 ConditionColor = 0; + UINT8 ConditionStringNum = GetConditionString( status, &ConditionColor ); + swprintf( pStr, L"%s", gConditionDesc[ConditionStringNum+1 ] ); + SetFontForeground( ConditionColor ); + mprintf( gItemDescTextRegions[1].sLeft+indent+2, gItemDescTextRegions[1].sTop, pStr ); + // Record length + indent += StringPixLength( gConditionDesc[ConditionStringNum + 1], ITEMDESC_FONT ); + + SetFontForeground( ForegroundColor ); + swprintf( pStr, L"%s", gConditionDesc[8] ); // " Condition." + mprintf( gItemDescTextRegions[1].sLeft + indent + 2, gItemDescTextRegions[1].sTop, pStr ); + } + else + { + SetFontForeground( ForegroundColor ); + swprintf( pStr, L"%s", gWeaponStatsDesc[ 0 ] ); + mprintf( gODBItemDescRegions[0][0].sLeft, gODBItemDescRegions[0][0].sTop, pStr ); + } + + SetFontForeground( 5 ); + + // value + // This is gross, but to get the % to work out right... + swprintf( pStr, L"%2d%%", status); + + if (UsingEDBSystem()) + { + FindFontRightCoordinates( gItemDescTextRegions[1].sLeft, gItemDescTextRegions[1].sTop, gItemDescTextRegions[1].sRight - gItemDescTextRegions[1].sLeft, gItemDescTextRegions[1].sBottom - gItemDescTextRegions[1].sTop ,pStr, BLOCKFONT2, &usX, &usY); + } + else + { + FindFontRightCoordinates( gODBItemDescRegions[0][0].sLeft, gODBItemDescRegions[0][0].sTop, gODBItemDescRegions[0][0].sRight - gODBItemDescRegions[0][0].sLeft, gODBItemDescRegions[0][0].sBottom - gODBItemDescRegions[0][0].sTop ,pStr, BLOCKFONT2, &usX, &usY); + } + + #ifdef CHINESE + wcscat( pStr, ChineseSpecString1 ); + #else + wcscat( pStr, L"%%" ); + #endif + + mprintf( usX, usY, pStr ); + } + + /////////// DISPLAY WEIGHT + // Note: Money has no weight. Skip this. + if(Item[ gpItemDescObject->usItem ].usItemClass != IC_MONEY) + { + SetFontForeground( 6 ); + + // label + if (UsingEDBSystem()) + { + mprintf( gItemDescTextRegions[2].sLeft, gItemDescTextRegions[2].sTop, gWeaponStatsDesc[1] ); + } + else + { + mprintf( gODBItemDescRegions[1][0].sLeft, gODBItemDescRegions[1][0].sTop, gWeaponStatsDesc[1] ); + } + // Calculate total weight of item and attachments + fWeight = gpItemDescObject->GetWeightOfObjectInStack(gubItemDescStatusIndex) / 10.0f; + if ( !gGameSettings.fOptions[ TOPTION_USE_METRIC_SYSTEM ] ) // metric units not enabled + { + fWeight = fWeight * 2.2f; + } + if ( fWeight < 0.1 && gubItemDescStatusIndex < gpItemDescObject->ubNumberOfObjects ) + { + fWeight = 0.1f; + } + // Change value colors + if (fWeight <= (EXCEPTIONAL_WEIGHT / 10) && Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON ) + { + SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); + } + else + { + SetFontForeground( 5 ); + } + //Print + swprintf( pStr, L"%1.1f %s", fWeight, GetWeightUnitString() ); + if (UsingEDBSystem()) + { + FindFontRightCoordinates( gItemDescTextRegions[2].sLeft, gItemDescTextRegions[2].sTop, gItemDescTextRegions[2].sRight - gItemDescTextRegions[2].sLeft ,gItemDescTextRegions[2].sBottom - gItemDescTextRegions[2].sTop ,pStr, BLOCKFONT2, &usX, &usY); + } + else + { + FindFontRightCoordinates( gODBItemDescRegions[1][0].sLeft, gODBItemDescRegions[1][0].sTop, gODBItemDescRegions[1][0].sRight - gODBItemDescRegions[1][0].sLeft ,gODBItemDescRegions[1][0].sBottom - gODBItemDescRegions[1][0].sTop ,pStr, BLOCKFONT2, &usX, &usY); + } + mprintf( usX, usY, pStr ); + } + + /////////// DISPLAY PROS/CONS (weapons and launchers only) + + if ( ITEM_PROS_AND_CONS( gpItemDescObject->usItem ) ) + { + SetFontForeground( FONT_MCOLOR_DKWHITE2 ); + SetFontShadow( ITEMDESC_FONTSHADOW3 ); + // PROs + mprintf( gItemDescTextRegions[3].sLeft, gItemDescTextRegions[3].sTop, gzProsLabel ); + + sProsConsIndent = __max( StringPixLength( gzProsLabel, ITEMDESC_FONT ), StringPixLength( gzConsLabel, ITEMDESC_FONT ) ) + 10; + gzItemPros[0] = 0; + GenerateProsString( gzItemPros, gpItemDescObject, (gItemDescTextRegions[4].sRight - gItemDescTextRegions[4].sLeft) - StringPixLength( DOTDOTDOT, ITEMDESC_FONT ) ); + if (gzItemPros[0] != 0) + { + if (UsingEDBSystem()) + { + ForegroundColor = 5; + SetFontShadow( DEFAULT_SHADOW ); + } + else + { + ForegroundColor = FONT_MCOLOR_BLACK; + SetFontShadow( ITEMDESC_FONTSHADOW2 ); + } + + DisplayWrappedString( gItemDescTextRegions[4].sLeft, gItemDescTextRegions[4].sTop, (gItemDescTextRegions[4].sRight - gItemDescTextRegions[4].sLeft), 2, ITEMDESC_FONT, ForegroundColor, gzItemPros, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED ); + } + + SetFontForeground( FONT_MCOLOR_DKWHITE2 ); + SetFontShadow( ITEMDESC_FONTSHADOW3 ); + // CONs + mprintf( gItemDescTextRegions[5].sLeft, gItemDescTextRegions[5].sTop, gzConsLabel ); + + // HEADROCK: Disabled PROs/CONs text for OIV EDB Tactical + + GenerateConsString( gzItemCons, gpItemDescObject, (gItemDescTextRegions[6].sRight - gItemDescTextRegions[6].sLeft) - StringPixLength( DOTDOTDOT, ITEMDESC_FONT ) ); + if (gzItemCons[0] != 0) + { + if (UsingEDBSystem()) + { + ForegroundColor = 5; + SetFontShadow( DEFAULT_SHADOW ); + } + else + { + ForegroundColor = FONT_MCOLOR_BLACK; + SetFontShadow( ITEMDESC_FONTSHADOW2 ); + } + + DisplayWrappedString( gItemDescTextRegions[6].sLeft, gItemDescTextRegions[6].sTop, (gItemDescTextRegions[6].sRight - gItemDescTextRegions[6].sLeft), 2, ITEMDESC_FONT, ForegroundColor, gzItemCons, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED); + } + MSYS_EnableRegion( &(gProsAndConsRegions[ 0 ]) ); + MSYS_EnableRegion( &(gProsAndConsRegions[ 1 ]) ); + } + } + // HEADROCK HAM 4: If not displaying the UDB Description Page, disable the pros/cons rects. + else + { + MSYS_DisableRegion( &(gProsAndConsRegions[ 0 ]) ); + MSYS_DisableRegion( &(gProsAndConsRegions[ 1 ]) ); + } + + // Render "normal" item data + SetFontShadow( DEFAULT_SHADOW ); ////////////////////////////////////////////////////////////////////////////// // DATA VALUES @@ -4105,139 +4948,84 @@ void RenderItemDescriptionBox( ) // they are replaced by icons, which have already been blitted above. ////////////////////////////////////////////////////////////////////////////// - // We begin by printing out data for ALL items, namely status and weight. - SetFont( BLOCKFONT2 ); - SetFontForeground( 6 ); - SetFontShadow( DEFAULT_SHADOW ); - - // For ammo, capacity replaces status. Money and Keys do not get a status display at all. - if ( Item[ gpItemDescObject->usItem ].usItemClass != IC_AMMO && Item[ gpItemDescObject->usItem ].usItemClass != IC_MONEY ) - { - // STATUS - // label - mprintf( gWeaponStats[ 0 ].sX + gsInvDescX, gWeaponStats[ 0 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 0 ] ); - SetFontForeground( 5 ); - // print value - // This is gross, but to get the % to work out right... - swprintf( pStr, L"%2d%%", status); - if (UsingEDBSystem() == 2) - FindFontRightCoordinates( (INT16)(gWeaponStats[ 0 ].sX + gsInvDescX + gWeaponStats[ 0 ].sValDx), (INT16)(gWeaponStats[ 0 ].sY + gsInvDescY + 12 ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - else - FindFontRightCoordinates( (INT16)(gWeaponStats[ 0 ].sX + gsInvDescX + gWeaponStats[ 0 ].sValDx), (INT16)(gWeaponStats[ 0 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - - #ifdef CHINESE - wcscat( pStr, ChineseSpecString1 ); - #else - wcscat( pStr, L"%%" ); - #endif - - mprintf( usX, usY, pStr ); - } - - if(Item[ gpItemDescObject->usItem ].usItemClass != IC_MONEY) - { - // WEIGHT - SetFontForeground( 6 ); - swprintf( sTempString, gWeaponStatsDesc[ 1 ], GetWeightUnitString() ); - mprintf( gWeaponStats[ 1 ].sX + gsInvDescX, gWeaponStats[ 1 ].sY + gsInvDescY, L"%s", sTempString ); - - // Calculate total weight of item and attachments - fWeight = gpItemDescObject->GetWeightOfObjectInStack(gubItemDescStatusIndex) / 10.0f; - if ( !gGameSettings.fOptions[ TOPTION_USE_METRIC_SYSTEM ] ) // metric units not enabled - { - fWeight = fWeight * 2.2f; - } - if ( fWeight < 0.1 && gubItemDescStatusIndex < gpItemDescObject->ubNumberOfObjects ) - { - fWeight = 0.1f; - } - // Values - if (fWeight <= (EXCEPTIONAL_WEIGHT / 10) && Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON ) - { - SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); - } - else - { - SetFontForeground( 5 ); - } - //Weight - swprintf( pStr, L"%1.1f", fWeight ); - if (UsingEDBSystem() == 2) - FindFontRightCoordinates( (INT16)(gWeaponStats[ 1 ].sX + gsInvDescX + gWeaponStats[ 1 ].sValDx), (INT16)(gWeaponStats[ 1 ].sY + gsInvDescY + 12 ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - else - FindFontRightCoordinates( (INT16)(gWeaponStats[ 1 ].sX + gsInvDescX + gWeaponStats[ 1 ].sValDx), (INT16)(gWeaponStats[ 1 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - } - ///////////////////////////////////////// // BEGIN WEAPONS-SPECIFIC CHARACTERISTICS ///////////////////////////////////////// if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_WEAPON || Item[ gpItemDescObject->usItem ].usItemClass & IC_PUNCH ) { - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) - { - // RANGE - SetFontForeground( 6 ); - if(UsingEDBSystem() > 0) - mprintf( gWeaponStats[ 23 ].sX + gsInvDescX, gWeaponStats[ 23 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - else - mprintf( gWeaponStats[ 2 ].sX + gsInvDescX, gWeaponStats[ 2 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 3 ] ); - - if ( GunRange( gpItemDescObject ) >= EXCEPTIONAL_RANGE) - { - SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); - } - else - { - SetFontForeground( 5 ); - } - swprintf( pStr, L"%2d", ( GunRange( gpItemDescObject ) ) / 10 ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 2 ].sX + gsInvDescX + gWeaponStats[ 2 ].sValDx), (INT16)(gWeaponStats[ 2 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - } - if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_PUNCH|IC_BLADE|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) - { - // DAMAGE - SetFontForeground( 6 ); - if(UsingEDBSystem() > 0) - mprintf( gWeaponStats[ 24 ].sX + gsInvDescX, gWeaponStats[ 24 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); - else - mprintf( gWeaponStats[ 3 ].sX + gsInvDescX, gWeaponStats[ 3 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 4 ] ); - - UINT8 ubImpact = GetDamage(gpItemDescObject); - - if ( ubImpact >= EXCEPTIONAL_DAMAGE) - { - SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); - } - else - { - SetFontForeground( 5 ); - } - - //Damage - swprintf( pStr, L"%2d", ubImpact ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 3 ].sX + gsInvDescX + gWeaponStats[ 3 ].sValDx), (INT16)(gWeaponStats[ 3 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - } - if(UsingEDBSystem() > 0) + { + SetFontShadow( ITEMDESC_FONTSHADOW3 ); DrawWeaponValues(gpItemDescObject); + } else { + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE) ) + { + // RANGE + SetFontForeground( 6 ); + mprintf( gODBItemDescRegions[2][4].sLeft, gODBItemDescRegions[2][4].sTop, L"%s", gWeaponStatsDesc[ 3 ] ); + + if ( GunRange( gpItemDescObject, NULL ) >= EXCEPTIONAL_RANGE) + { + SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); + } + else + { + SetFontForeground( 5 ); + } + swprintf( pStr, L"%2d", ( GunRange( gpItemDescObject, NULL ) ) / 10 ); + FindFontRightCoordinates( gODBItemDescRegions[2][7].sLeft, gODBItemDescRegions[2][7].sTop, gODBItemDescRegions[2][7].sRight - gODBItemDescRegions[2][7].sLeft, gODBItemDescRegions[2][7].sBottom - gODBItemDescRegions[2][7].sTop ,pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + if ( Item[ gpItemDescObject->usItem ].usItemClass & (IC_GUN|IC_PUNCH|IC_BLADE|IC_THROWING_KNIFE) && !Item[ gpItemDescObject->usItem ].singleshotrocketlauncher ) + { + // DAMAGE + SetFontForeground( 6 ); + mprintf( gODBItemDescRegions[2][0].sLeft, gODBItemDescRegions[2][0].sTop, L"%s", gWeaponStatsDesc[ 4 ] ); + + UINT8 ubImpact = GetDamage(gpItemDescObject); + + UINT16 exceptionalDamage; + // Melee damage + if ( Item[gpItemDescObject->usItem].usItemClass == IC_BLADE || Item[gpItemDescObject->usItem].usItemClass == IC_PUNCH || Item[gpItemDescObject->usItem].usItemClass == IC_TENTACLES ) + { + exceptionalDamage = (UINT16)(( EXCEPTIONAL_MELEE_DAMAGE * gGameExternalOptions.iMeleeDamageModifier ) / 100); + } + // Gun damage + else + { + exceptionalDamage = (UINT16)(( EXCEPTIONAL_GUN_DAMAGE * gGameExternalOptions.iGunDamageModifier ) / 100); + } + + if ( ubImpact >= exceptionalDamage) + { + SetFontForeground( ITEMDESC_FONTHIGHLIGHT ); + } + else + { + SetFontForeground( 5 ); + } + + //Damage + swprintf( pStr, L"%2d", ubImpact ); + FindFontRightCoordinates( gODBItemDescRegions[2][3].sLeft, gODBItemDescRegions[2][3].sTop, gODBItemDescRegions[2][3].sRight - gODBItemDescRegions[2][3].sLeft, gODBItemDescRegions[2][3].sBottom - gODBItemDescRegions[2][3].sTop ,pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + } + //LABELS SetFontForeground( 6 ); - mprintf( gWeaponStats[ 5 ].sX + gsInvDescX, gWeaponStats[ 5 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 6 ] ); + mprintf( gODBItemDescRegions[3][0].sLeft, gODBItemDescRegions[3][0].sTop, L"%s", gWeaponStatsDesc[ 6 ] ); if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_GUN || Item[ gpItemDescObject->usItem ].usItemClass & IC_LAUNCHER) { // equals sign if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) - mprintf( gWeaponStats[ 7 ].sX + gsInvDescX, gWeaponStats[ 7 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 7 ] ); + mprintf( gODBItemDescRegions[3][2].sLeft, gODBItemDescRegions[3][2].sTop, L"%s", gWeaponStatsDesc[ 7 ] ); } if (GetShotsPerBurst(gpItemDescObject) > 0 || GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0 ) { - mprintf( gWeaponStats[ 8 ].sX + gsInvDescX, gWeaponStats[ 8 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 8 ] ); + mprintf( gODBItemDescRegions[3][6].sLeft, gODBItemDescRegions[3][6].sTop, L"%s", gWeaponStatsDesc[ 8 ] ); } ubAttackAPs = BaseAPsToShootOrStab( APBPConstants[DEFAULT_APS], APBPConstants[DEFAULT_AIMSKILL], gpItemDescObject ); @@ -4258,7 +5046,7 @@ void RenderItemDescriptionBox( ) if ( !Weapon[gpItemDescObject->usItem].NoSemiAuto ) { swprintf( pStr, L"%2d", ubAttackAPs ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 5 ].sX + gsInvDescX + gWeaponStats[ 5 ].sValDx), (INT16)(gWeaponStats[ 5 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + FindFontRightCoordinates( gODBItemDescRegions[3][3].sLeft, gODBItemDescRegions[3][3].sTop, gODBItemDescRegions[3][3].sRight - gODBItemDescRegions[3][3].sLeft, gODBItemDescRegions[3][3].sBottom - gODBItemDescRegions[3][3].sTop ,pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); } @@ -4273,14 +5061,14 @@ void RenderItemDescriptionBox( ) SetFontForeground( 5 ); } swprintf( pStr, L"%2d", ubAttackAPs + CalcAPsToBurst( APBPConstants[DEFAULT_APS], gpItemDescObject ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 6 ].sX + gsInvDescX + gWeaponStats[ 6 ].sValDx), (INT16)(gWeaponStats[ 6 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + FindFontRightCoordinates( gODBItemDescRegions[3][7].sLeft, gODBItemDescRegions[3][7].sTop, gODBItemDescRegions[3][7].sRight - gODBItemDescRegions[3][7].sLeft, gODBItemDescRegions[3][7].sBottom - gODBItemDescRegions[3][7].sTop ,pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); } else if (GetAutofireShotsPerFiveAPs(gpItemDescObject) > 0) { SetFontForeground( 5 ); swprintf( pStr, L"%2d", ubAttackAPs + CalcAPsToAutofire( APBPConstants[DEFAULT_APS], gpItemDescObject, 3 ) ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 6 ].sX + gsInvDescX + gWeaponStats[ 6 ].sValDx), (INT16)(gWeaponStats[ 6 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + FindFontRightCoordinates( gODBItemDescRegions[3][7].sLeft, gODBItemDescRegions[3][7].sTop, gODBItemDescRegions[3][7].sRight - gODBItemDescRegions[3][7].sLeft, gODBItemDescRegions[3][7].sBottom - gODBItemDescRegions[3][7].sTop ,pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); } } @@ -4293,74 +5081,88 @@ void RenderItemDescriptionBox( ) } else if ( gpItemDescObject->usItem == MONEY ) { - //Labels - SetFont( BLOCKFONT2 ); - SetFontShadow( DEFAULT_SHADOW ); - SetFontForeground( 6 ); - - //Display the 'Seperate text' - if( gfAddingMoneyToMercFromPlayersAccount ) - mprintf( (UINT16)(gMoneyButtonLoc.x + gMoneyButtonOffsets[4].x), (UINT16)(gMoneyButtonLoc.y + gMoneyButtonOffsets[4].y), gzMoneyAmounts[5] ); - else - mprintf( (UINT16)(gMoneyButtonLoc.x + gMoneyButtonOffsets[4].x), (UINT16)(gMoneyButtonLoc.y + gMoneyButtonOffsets[4].y ), gzMoneyAmounts[4] ); - - //if the player is removing money from the players account - if( gfAddingMoneyToMercFromPlayersAccount ) + if ((UsingEDBSystem() && gubDescBoxPage == 0) || !UsingEDBSystem()) { - //Display the 'Removing' - mprintf( gMoneyStats[ 0 ].sX + gsInvDescX, gMoneyStats[ 0 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_PLAYERS ] ); - //Display the 'REmaining' - mprintf( gMoneyStats[ 2 ].sX + gsInvDescX, gMoneyStats[ 2 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_AMOUNT_2_WITHDRAW ] ); + for (INT8 x = 0; x < 4; x++) + { + EnableButton(guiMoneyButtonBtn[ x ]); + } + //Labels + SetFont( BLOCKFONT2 ); + SetFontShadow( DEFAULT_SHADOW ); + SetFontForeground( 6 ); + + //Display the 'Seperate text' + if( gfAddingMoneyToMercFromPlayersAccount ) + mprintf( (UINT16)(gMoneyButtonLoc.x + gMoneyButtonOffsets[4].x), (UINT16)(gMoneyButtonLoc.y + gMoneyButtonOffsets[4].y), gzMoneyAmounts[5] ); + else + mprintf( (UINT16)(gMoneyButtonLoc.x + gMoneyButtonOffsets[4].x), (UINT16)(gMoneyButtonLoc.y + gMoneyButtonOffsets[4].y ), gzMoneyAmounts[4] ); + + //if the player is removing money from the players account + if( gfAddingMoneyToMercFromPlayersAccount ) + { + //Display the 'Removing' + mprintf( gMoneyStats[ 0 ].sX, gMoneyStats[ 0 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_PLAYERS ] ); + //Display the 'REmaining' + mprintf( gMoneyStats[ 2 ].sX, gMoneyStats[ 2 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_AMOUNT_2_WITHDRAW ] ); + } + else + { + //Display the 'Removing' + mprintf( gMoneyStats[ 0 ].sX, gMoneyStats[ 0 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_AMOUNT ] ); + //Display the 'REmaining' + mprintf( gMoneyStats[ 2 ].sX, gMoneyStats[ 2 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_AMOUNT_2_SPLIT ] ); + } + + // if the player is taking money from their account + if( gfAddingMoneyToMercFromPlayersAccount ) + { + //Display the 'Amt removing' + mprintf( gMoneyStats[ 1 ].sX, gMoneyStats[ 1 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_BALANCE ] ); + //Display the 'REmaining amount' + mprintf( gMoneyStats[ 3 ].sX, gMoneyStats[ 3 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_TO_WITHDRAW ] ); + } + else + { + //Display the 'Amt removing' + mprintf( gMoneyStats[ 1 ].sX, gMoneyStats[ 1 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_REMAINING ] ); + //Display the 'REmaining amount' + mprintf( gMoneyStats[ 3 ].sX, gMoneyStats[ 3 ].sY, L"%s", gMoneyStatsDesc[ MONEY_DESC_TO_SPLIT ] ); + } + + //Display the total amount of money remaining + SetFontForeground( 5 ); + swprintf( pStr, L"%ld", gRemoveMoney.uiMoneyRemaining ); + InsertCommasForDollarFigure( pStr ); + InsertDollarSignInToString( pStr ); + FindFontRightCoordinates( gMoneyStats[ 4 ].sX, gMoneyStats[ 4 ].sY, ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); + + //Display the total amount of money removing + SetFontForeground( 5 ); + swprintf( pStr, L"%ld", gRemoveMoney.uiMoneyRemoving ); + InsertCommasForDollarFigure( pStr ); + InsertDollarSignInToString( pStr ); + FindFontRightCoordinates( gMoneyStats[ 5 ].sX, gMoneyStats[ 5 ].sY, ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + mprintf( usX, usY, pStr ); } else { - //Display the 'Removing' - mprintf( gMoneyStats[ 0 ].sX + gsInvDescX, gMoneyStats[ 0 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_AMOUNT ] ); - //Display the 'REmaining' - mprintf( gMoneyStats[ 2 ].sX + gsInvDescX, gMoneyStats[ 2 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_AMOUNT_2_SPLIT ] ); - } + for (INT8 x = 0; x < 4; x++) + { + DisableButton(guiMoneyButtonBtn[ x ]); + //Labels + SetFont( BLOCKFONT2 ); + SetFontShadow( DEFAULT_SHADOW ); + SetFontForeground( FONT_GRAY6 ); - // if the player is taking money from their account - if( gfAddingMoneyToMercFromPlayersAccount ) - { - //Display the 'Amt removing' - mprintf( gMoneyStats[ 1 ].sX + gsInvDescX, gMoneyStats[ 1 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_BALANCE ] ); - //Display the 'REmaining amount' - mprintf( gMoneyStats[ 3 ].sX + gsInvDescX, gMoneyStats[ 3 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_TO_WITHDRAW ] ); + //Display the 'Seperate text' + if( gfAddingMoneyToMercFromPlayersAccount ) + mprintf( (UINT16)(gMoneyButtonLoc.x + gMoneyButtonOffsets[4].x), (UINT16)(gMoneyButtonLoc.y + gMoneyButtonOffsets[4].y), gzMoneyAmounts[5] ); + else + mprintf( (UINT16)(gMoneyButtonLoc.x + gMoneyButtonOffsets[4].x), (UINT16)(gMoneyButtonLoc.y + gMoneyButtonOffsets[4].y ), gzMoneyAmounts[4] ); + } } - else - { - //Display the 'Amt removing' - mprintf( gMoneyStats[ 1 ].sX + gsInvDescX, gMoneyStats[ 1 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_REMAINING ] ); - //Display the 'REmaining amount' - mprintf( gMoneyStats[ 3 ].sX + gsInvDescX, gMoneyStats[ 3 ].sY + gsInvDescY, L"%s", gMoneyStatsDesc[ MONEY_DESC_TO_SPLIT ] ); - } - - //Display the total amount of money remaining - SetFontForeground( 5 ); - swprintf( pStr, L"%ld", gRemoveMoney.uiMoneyRemaining ); - InsertCommasForDollarFigure( pStr ); - InsertDollarSignInToString( pStr ); - if( guiCurrentItemDescriptionScreen != MAP_SCREEN ) - FindFontRightCoordinates( (INT16)(gMoneyStats[ 1 ].sX + gsInvDescX + gMoneyStats[ 1 ].sValDx), (INT16)(gMoneyStats[ 1 ].sY + gsInvDescY ), (UINT16)(ITEM_STATS_WIDTH-3) ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - else if(UsingEDBSystem() > 0) - FindFontRightCoordinates( (INT16)(gMoneyStats[ 4 ].sX + gsInvDescX + gMoneyStats[ 4 ].sValDx), (INT16)(gMoneyStats[ 4 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - else - FindFontRightCoordinates( (INT16)(gMoneyStats[ 1 ].sX + gsInvDescX + gMoneyStats[ 1 ].sValDx), (INT16)(gMoneyStats[ 1 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); - - //Display the total amount of money removing - SetFontForeground( 5 ); - swprintf( pStr, L"%ld", gRemoveMoney.uiMoneyRemoving ); - InsertCommasForDollarFigure( pStr ); - InsertDollarSignInToString( pStr ); - if( guiCurrentItemDescriptionScreen != MAP_SCREEN ) - FindFontRightCoordinates( (INT16)(gMoneyStats[ 3 ].sX + gsInvDescX + gMoneyStats[ 3 ].sValDx), (INT16)(gMoneyStats[ 3 ].sY + gsInvDescY), (UINT16)(ITEM_STATS_WIDTH-3) ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - else if(UsingEDBSystem() > 0) - FindFontRightCoordinates( (INT16)(gMoneyStats[ 5 ].sX + gsInvDescX + gMoneyStats[ 5 ].sValDx), (INT16)(gMoneyStats[ 5 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - else - FindFontRightCoordinates( (INT16)(gMoneyStats[ 3 ].sX + gsInvDescX + gMoneyStats[ 3 ].sValDx), (INT16)(gMoneyStats[ 3 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); - mprintf( usX, usY, pStr ); } else if ( Item[ gpItemDescObject->usItem ].usItemClass == IC_MONEY ) { @@ -4380,76 +5182,48 @@ void RenderItemDescriptionBox( ) else if ( ( InKeyRingPopup() == TRUE ) || ( Item[ gpItemDescObject->usItem ].usItemClass & IC_KEY ) ) { SetFontForeground( 6 ); + SetFontShadow( DEFAULT_SHADOW ); - if(UsingEDBSystem() > 0) + if(UsingEDBSystem() > 0 && gubDescBoxPage == 0) { // build description for keys .. the sector found swprintf( pStr, L"%s", sKeyDescriptionStrings[ 0 ] ); - mprintf( gWeaponStats[ 2 ].sX + gsInvDescX, gWeaponStats[ 2 ].sY + gsInvDescY, pStr ); + mprintf( gItemDescTextRegions[3].sLeft, gItemDescTextRegions[3].sTop, pStr ); swprintf( pStr, L"%s", sKeyDescriptionStrings[ 1 ] ); - if (UsingEDBSystem() == 1) - mprintf( gWeaponStats[ 5 ].sX + gsInvDescX, gWeaponStats[ 5 ].sY + gsInvDescY, pStr ); - else if (UsingEDBSystem() == 2) - mprintf( gWeaponStats[ 6 ].sX + gsInvDescX, gWeaponStats[ 6 ].sY + gsInvDescY, pStr ); + mprintf( gItemDescTextRegions[5].sLeft, gItemDescTextRegions[5].sTop, pStr ); } - else + else if(UsingEDBSystem() == 0) { // build description for keys .. the sector found swprintf( pStr, L"%s", sKeyDescriptionStrings[ 0 ] ); - mprintf( gWeaponStats[ 3 ].sX + gsInvDescX, gWeaponStats[ 3 ].sY + gsInvDescY, pStr ); + mprintf( gODBItemDescRegions[2][0].sLeft, gODBItemDescRegions[2][0].sTop, pStr ); swprintf( pStr, L"%s", sKeyDescriptionStrings[ 1 ] ); - mprintf( gWeaponStats[ 5 ].sX + gsInvDescX, gWeaponStats[ 5 ].sY + gsInvDescY , pStr ); + mprintf( gODBItemDescRegions[3][0].sLeft, gODBItemDescRegions[3][0].sTop, pStr ); } SetFontForeground( 5 ); GetShortSectorString( ( INT16 ) SECTORX( KeyTable[ (*gpItemDescObject)[gubItemDescStatusIndex]->data.key.ubKeyID ].usSectorFound ), ( INT16 ) SECTORY( KeyTable[ (*gpItemDescObject)[gubItemDescStatusIndex]->data.key.ubKeyID ].usSectorFound ), sTempString ); swprintf( pStr, L"%s", sTempString ); - if(UsingEDBSystem() > 0) + if(UsingEDBSystem() > 0 && gubDescBoxPage == 0) { - if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) - { - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ 15 ].sX + gsInvDescX + gMiscItemStatsEDB[ 15 ].sValDx), (INT16)(gMiscItemStatsEDB[ 15 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ 15 ].sY + gsInvDescY, pStr ); - } - else if (UsingEDBSystem() == 1) - { - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ 12 ].sX + gsInvDescX + gMiscItemStatsEDB[ 12 ].sValDx), (INT16)(gMiscItemStatsEDB[ 12 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ 12 ].sY + gsInvDescY, pStr ); - } - else if (UsingEDBSystem() == 2) - { - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ 13 ].sX + gsInvDescX + gMiscItemStatsEDB[ 13 ].sValDx), (INT16)(gMiscItemStatsEDB[ 13 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ 13 ].sY + gsInvDescY, pStr ); - } + FindFontRightCoordinates( gItemDescTextRegions[4].sLeft, gItemDescTextRegions[4].sTop, gItemDescTextRegions[4].sRight - gItemDescTextRegions[4].sLeft ,gItemDescTextRegions[4].sBottom - gItemDescTextRegions[4].sTop ,pStr, BLOCKFONT2, &sStrX, &usY); + mprintf( sStrX, usY, pStr ); } - else + else if (UsingEDBSystem() == 0) { - FindFontRightCoordinates( (INT16)(gWeaponStats[ 3 ].sX + gsInvDescX ), (INT16)(gWeaponStats[ 3 ].sY + gsInvDescY ), 110 ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + FindFontRightCoordinates( gODBItemDescRegions[2][7].sLeft, gODBItemDescRegions[2][7].sTop, gODBItemDescRegions[2][7].sRight - gODBItemDescRegions[2][7].sLeft ,gODBItemDescRegions[2][7].sBottom - gODBItemDescRegions[2][7].sTop ,pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); } swprintf( pStr, L"%d", KeyTable[ (*gpItemDescObject)[gubItemDescStatusIndex]->data.key.ubKeyID ].usDateFound ); - if(UsingEDBSystem() > 0) + if(UsingEDBSystem() > 0 && gubDescBoxPage == 0) { - if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) - { - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ 18 ].sX + gsInvDescX + gMiscItemStatsEDB[ 18 ].sValDx), (INT16)(gMiscItemStatsEDB[ 18 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ 18 ].sY + gsInvDescY, pStr ); - } - else if (UsingEDBSystem() == 1) - { - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ 15 ].sX + gsInvDescX + gMiscItemStatsEDB[ 15 ].sValDx), (INT16)(gMiscItemStatsEDB[ 13 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ 15 ].sY + gsInvDescY, pStr ); - } - else if (UsingEDBSystem() == 2) - { - FindFontRightCoordinates( (INT16)(gMiscItemStatsEDB[ 17 ].sX + gsInvDescX + gMiscItemStatsEDB[ 17 ].sValDx), (INT16)(gMiscItemStatsEDB[ 17 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gMiscItemStatsEDB[ 17 ].sY + gsInvDescY, pStr ); - } + FindFontRightCoordinates( gItemDescTextRegions[6].sLeft, gItemDescTextRegions[6].sTop, gItemDescTextRegions[6].sRight - gItemDescTextRegions[6].sLeft ,gItemDescTextRegions[6].sBottom - gItemDescTextRegions[6].sTop ,pStr, BLOCKFONT2, &sStrX, &usY); + mprintf( sStrX, usY, pStr ); } - else + else if (UsingEDBSystem() == 0) { - FindFontRightCoordinates( (INT16)(gWeaponStats[ 5 ].sX + gsInvDescX ), (INT16)(gWeaponStats[ 5 ].sY + gsInvDescY ), 110 ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &usX, &usY); + FindFontRightCoordinates( gODBItemDescRegions[3][7].sLeft, gODBItemDescRegions[3][7].sTop, gODBItemDescRegions[3][7].sRight - gODBItemDescRegions[3][7].sLeft ,gODBItemDescRegions[3][7].sBottom - gODBItemDescRegions[3][7].sTop ,pStr, BLOCKFONT2, &usX, &usY); mprintf( usX, usY, pStr ); } } @@ -4466,7 +5240,7 @@ void RenderItemDescriptionBox( ) DrawAmmoValues(gpItemDescObject,shotsLeft); else { - mprintf( gWeaponStats[ 0 ].sX + gsInvDescX, gWeaponStats[ 0 ].sY + gsInvDescY, L"%s", gWeaponStatsDesc[ 5 ] ); + mprintf( gODBItemDescRegions[0][0].sLeft, gODBItemDescRegions[0][0].sTop, L"%s", gWeaponStatsDesc[ 5 ] ); // Values SetFontForeground( 5 ); @@ -4474,8 +5248,8 @@ void RenderItemDescriptionBox( ) // Ammo swprintf( pStr, L"%d/%d", shotsLeft, Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex ].ubMagSize ); //Pulmu: Correct # of rounds for stacked ammo. uiStringLength=StringPixLength(pStr, ITEMDESC_FONT ); - FindFontRightCoordinates( (INT16)(gWeaponStats[ 0 ].sX + gsInvDescX + gWeaponStats[ 0 ].sValDx+6), (INT16)(gWeaponStats[ 0 ].sY + gsInvDescY ), ITEM_STATS_WIDTH ,ITEM_STATS_HEIGHT ,pStr, BLOCKFONT2, &sStrX, &usY); - mprintf( sStrX, gWeaponStats[ 0 ].sY + gsInvDescY, pStr ); + FindFontRightCoordinates( gODBItemDescRegions[0][0].sLeft, gODBItemDescRegions[0][0].sTop, gODBItemDescRegions[0][0].sRight - gODBItemDescRegions[0][0].sLeft ,gODBItemDescRegions[0][0].sBottom - gODBItemDescRegions[0][0].sTop ,pStr, BLOCKFONT2, &sStrX, &usY); + mprintf( sStrX, usY, pStr ); } } else if ( Item[ gpItemDescObject->usItem ].usItemClass & IC_EXPLOSV ) @@ -4698,12 +5472,28 @@ void DeleteItemDescriptionBox( ) UINT8 ubAPCost = 0; // check for change in attachments - unsigned int originalSize = gOriginalAttachments.size(); - unsigned int newSize = (*gpItemDescObject)[0]->attachments.size(); + //unsigned int originalSize = gOriginalAttachments.size(); + //unsigned int newSize = (*gpItemDescObject)[0]->attachments.size(); + + //WarmSteel size() is no longer sufficient, because the list contains null objects. + unsigned int originalSize = 0; + unsigned int newSize = 0; + attachmentList::iterator originalIter; + attachmentList::iterator newIter; + + for (originalIter = gOriginalAttachments.begin(), newIter = (*gpItemDescObject)[0]->attachments.begin(); + originalIter != gOriginalAttachments.end() && newIter != (*gpItemDescObject)[0]->attachments.end(); + ++originalIter, ++newIter){ + if(originalIter->exists()){ + originalSize++; + } + if(newIter->exists()){ + newSize++; + } + } + if (newSize != originalSize) { - attachmentList::iterator originalIter; - attachmentList::iterator newIter; //an attachment was changed, find the change for (originalIter = gOriginalAttachments.begin(), newIter = (*gpItemDescObject)[0]->attachments.begin(); originalIter != gOriginalAttachments.end() && newIter != (*gpItemDescObject)[0]->attachments.end(); @@ -4717,7 +5507,7 @@ void DeleteItemDescriptionBox( ) } if (newSize < originalSize) { //an attachment was removed, charge APs - ubAPCost = AttachmentAPCost(originalIter->usItem,gpItemDescObject->usItem); + ubAPCost = AttachmentAPCost(originalIter->usItem,gpItemDescObject, gpAttachSoldier ); // SANDRO - added argument } else { //an attachment was added charge APs @@ -4728,7 +5518,7 @@ void DeleteItemDescriptionBox( ) } else { - ubAPCost = AttachmentAPCost(newIter->usItem,gpItemDescObject->usItem); + ubAPCost = AttachmentAPCost(newIter->usItem,gpItemDescObject, gpAttachSoldier); // SANDRO - added argument } } } @@ -4744,7 +5534,10 @@ void DeleteItemDescriptionBox( ) DeleteVideoObjectFromIndex( guiItemDescBox ); if(UsingNewInventorySystem() == true && guiItemDescBoxBackground != 0) DeleteVideoObjectFromIndex( guiItemDescBoxBackground ); + if(UsingNewInventorySystem() == true && guiItemInfoLBEBackground != 0) + DeleteVideoObjectFromIndex( guiItemInfoLBEBackground ); DeleteVideoObjectFromIndex( guiMapItemDescBox ); + DeleteVideoObjectFromIndex( guiAttachmentSlot ); RenderBackpackButtons(0); /* CHRISL: Needed for new inventory backpack buttons */ DeleteVideoObjectFromIndex( guiBullet ); DeleteEnhancedDescBox( guiCurrentItemDescriptionScreen ); @@ -4760,22 +5553,75 @@ void DeleteItemDescriptionBox( ) RemoveButton( giMapInvDescButton ); } + // HEADROCK HAM 4: Remove TAB buttons for UDB + if (UsingEDBSystem() > 0) + { + if( guiCurrentItemDescriptionScreen == MAP_SCREEN ) + { + UnloadButtonImage( giMapInvDescTabButtonImage ); + } + else + { + UnloadButtonImage( giInvDescTabButtonImage ); + } + for (cnt = 0; cnt < 3; cnt++) + { + RemoveButton( giInvDescTabButton[cnt] ); + } + } + + // HEADROCK HAM 4: Remove ADVANCED buttons for UDB + if (UsingEDBSystem() > 0) + { + UnloadButtonImage( giInvDescAdvButtonUpImage ); + UnloadButtonImage( giInvDescAdvButtonDownImage ); + for (cnt = 0; cnt < 2; cnt++) + { + if ( giInvDescAdvButton[cnt] != -1 ) + { + RemoveButton( giInvDescAdvButton[cnt] ); + } + } + } + // Remove region MSYS_RemoveRegion( &gInvDesc); if( gpItemDescObject->usItem != MONEY ) { - for ( cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) + if (UsingNewAttachmentSystem()==true) { - MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); + // WANNE: Bugfix: Fixed CTD when closing sector inventory in strategy screen with open item description + if (gpItemDescObject[0].objectStack.size() == 0) + { + for ( cnt = 0; cnt < MAX_ATTACHMENTS; cnt++) + { + MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); + } + } + else + { + for ( cnt = 0; cnt < (INT32)(*gpItemDescObject)[0]->attachments.size(); cnt++ ) + { + MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); + } + } + } + else + { + // WANNE: Bugfix: Attachment regions were not removed when playing without NAS and when closing the description box + for (cnt = 0; cnt < OLD_MAX_ATTACHMENTS_101; cnt++) + { + MSYS_RemoveRegion( &gItemDescAttachmentRegions[cnt]); + } } } else { UnloadButtonImage( guiMoneyButtonImage ); UnloadButtonImage( guiMoneyDoneButtonImage ); - for ( cnt = 0; cnt < MAX_ATTACHMENTS; cnt++ ) + for ( cnt = 0; cnt < OLD_MAX_ATTACHMENTS_101; cnt++ ) { RemoveButton( guiMoneyButtonBtn[cnt] ); } @@ -4830,6 +5676,8 @@ void DeleteItemDescriptionBox( ) gfItemDescObjectIsAttachment = FALSE; gpItemDescObject = NULL; + gpItemDescPrevObject = NULL; + } @@ -5052,6 +5900,10 @@ void DrawItemTileCursor( ) if (GetMouseMapPos( &usMapPos) ) { + /*CHRISL: For some reason it's possible that gpItemPointerSoldier is not correctly set when we come into this function, but we require it to be set for + this function to work. So for now, let's set it using gusUIFullTargetID.*/ + if(gpItemPointerSoldier->exists() == false) + gpItemPointerSoldier = MercPtrs[ gusUIFullTargetID ]; if ( gfUIFullTargetFound ) { // Force mouse position to guy... @@ -5104,7 +5956,6 @@ void DrawItemTileCursor( ) // Get Pyth spaces away..... sDist = PythSpacesAway( gpItemPointerSoldier->sGridNo, gusCurMousePos ); - // If we are here and we are not selected, select! // ATE Design discussion propably needed here... if ( gpItemPointerSoldier->ubID != gusSelectedSoldier ) @@ -5164,7 +6015,7 @@ void DrawItemTileCursor( ) // If we are tossing... if ( sDist <= 1 && gfUIMouseOnValidCatcher == 0 || gfUIMouseOnValidCatcher == 4 ) { - gsCurrentActionPoints = APBPConstants[AP_PICKUP_ITEM]; + gsCurrentActionPoints = GetBasicAPsToPickupItem( gpItemPointerSoldier ); } else { @@ -5403,7 +6254,7 @@ BOOLEAN HandleItemPointerClick( INT32 usMapPos ) // Check if we have APs.... if ( !EnoughPoints( gpItemPointerSoldier, gsCurrentActionPoints, 0, TRUE ) ) { - if ( gfDontChargeAPsToPickup && gsCurrentActionPoints == APBPConstants[AP_PICKUP_ITEM] ) + if ( gfDontChargeAPsToPickup && gsCurrentActionPoints == GetBasicAPsToPickupItem( gpItemPointerSoldier ) ) { } @@ -5540,7 +6391,9 @@ BOOLEAN HandleItemPointerClick( INT32 usMapPos ) EndItemPointer( ); // If we are giving it to somebody not on our team.... - if ( MercPtrs[ ubSoldierID ]->ubProfile < FIRST_RPC || MercPtrs[ubSoldierID]->ubProfile >= GASTON || RPC_RECRUITED( MercPtrs[ ubSoldierID ] ) ) + //if ( MercPtrs[ ubSoldierID ]->ubProfile < FIRST_RPC || MercPtrs[ubSoldierID]->ubProfile >= GASTON || RPC_RECRUITED( MercPtrs[ ubSoldierID ] ) ) + //new profiles by Jazz + if ( gProfilesIMP[MercPtrs[ ubSoldierID ]->ubProfile].ProfilId == MercPtrs[ ubSoldierID ]->ubProfile || gProfilesAIM[MercPtrs[ ubSoldierID ]->ubProfile].ProfilId == MercPtrs[ ubSoldierID ]->ubProfile || gProfilesMERC[MercPtrs[ ubSoldierID ]->ubProfile].ProfilId == MercPtrs[ ubSoldierID ]->ubProfile || RPC_RECRUITED( MercPtrs[ ubSoldierID ] ) ) { } @@ -5566,7 +6419,7 @@ BOOLEAN HandleItemPointerClick( INT32 usMapPos ) if ( !gfDontChargeAPsToPickup ) { // Deduct points - DeductPoints( gpItemPointerSoldier, APBPConstants[AP_PICKUP_ITEM], 0 ); + DeductPoints( gpItemPointerSoldier, GetBasicAPsToPickupItem( gpItemPointerSoldier ), 0 ); } SoldierDropItem( gpItemPointerSoldier, gpItemPointer ); @@ -5582,7 +6435,7 @@ BOOLEAN HandleItemPointerClick( INT32 usMapPos ) if ( !gfDontChargeAPsToPickup ) { // Deduct points - DeductPoints( gpItemPointerSoldier, APBPConstants[AP_PICKUP_ITEM], 0 ); + DeductPoints( gpItemPointerSoldier, GetBasicAPsToPickupItem(gpItemPointerSoldier), 0 ); } // Play animation.... @@ -5620,7 +6473,7 @@ BOOLEAN HandleItemPointerClick( INT32 usMapPos ) if ( !gfDontChargeAPsToPickup ) { // Deduct points - DeductPoints( gpItemPointerSoldier, APBPConstants[AP_PICKUP_ITEM], 0 ); + DeductPoints( gpItemPointerSoldier, GetBasicAPsToPickupItem(gpItemPointerSoldier), 0 ); } SoldierDropItem( gpItemPointerSoldier, gpItemPointer ); @@ -6526,22 +7379,22 @@ UINT32 GetInterfaceGraphicForItem( INVTYPE *pItem ) // CHECK SUBCLASS if ( pItem->ubGraphicType == 0 ) { - TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oGUNSM.getVObjectForItem(pItem->ubGraphicNum) : guiGUNSM, + SGP_TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oGUNSM.getVObjectForItem(pItem->ubGraphicNum) : guiGUNSM, L"Failed to retrieve gun image" ); } else if ( pItem->ubGraphicType == 1 ) { - TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oP1ITEMS.getVObjectForItem(pItem->ubGraphicNum) : guiP1ITEMS, + SGP_TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oP1ITEMS.getVObjectForItem(pItem->ubGraphicNum) : guiP1ITEMS, L"Failed to retrieve P1 item image" ); } else if ( pItem->ubGraphicType == 2 ) { - TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oP2ITEMS.getVObjectForItem(pItem->ubGraphicNum) : guiP2ITEMS, + SGP_TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oP2ITEMS.getVObjectForItem(pItem->ubGraphicNum) : guiP2ITEMS, L"Failed to retrieve P2 item image" ); } else { - TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oP3ITEMS.getVObjectForItem(pItem->ubGraphicNum) : guiP3ITEMS, + SGP_TRYCATCH_RETHROW( id = g_bUsePngItemImages ? g_oP3ITEMS.getVObjectForItem(pItem->ubGraphicNum) : guiP3ITEMS, L"Failed to retrieve P3 item image" ); } return id; @@ -6587,6 +7440,8 @@ BOOLEAN LoadTileGraphicForItem( INVTYPE *pItem, UINT32 *puiVo ) DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("LoadTileGraphicForItem")); + const char* ext = g_bUsePngItemImages ? ".png" : ".sti"; + // CHECK SUBCLASS ubGraphic = pItem->ubGraphicNum; @@ -6597,50 +7452,50 @@ BOOLEAN LoadTileGraphicForItem( INVTYPE *pItem, UINT32 *puiVo ) if ( ubGraphic < 10 ) { - sprintf( zName, "gun0%d.sti", ubGraphic ); + sprintf( zName, "gun0%d", ubGraphic ); } else { - sprintf( zName, "gun%d.sti", ubGraphic ); + sprintf( zName, "gun%d", ubGraphic ); } } else if ( pItem->ubGraphicType == 1 ) { if ( ubGraphic < 10 ) { - sprintf( zName, "p1item0%d.sti", ubGraphic ); + sprintf( zName, "p1item0%d", ubGraphic ); } else { - sprintf( zName, "p1item%d.sti", ubGraphic ); + sprintf( zName, "p1item%d", ubGraphic ); } } else if ( pItem->ubGraphicType == 2 ) { if ( ubGraphic < 10 ) { - sprintf( zName, "p2item0%d.sti", ubGraphic ); + sprintf( zName, "p2item0%d", ubGraphic ); } else { - sprintf( zName, "p2item%d.sti", ubGraphic ); + sprintf( zName, "p2item%d", ubGraphic ); } } else { if ( ubGraphic < 10 ) { - sprintf( zName, "p3item0%d.sti", ubGraphic ); + sprintf( zName, "p3item0%d", ubGraphic ); } else { - sprintf( zName, "p3item%d.sti", ubGraphic ); + sprintf( zName, "p3item%d", ubGraphic ); } } //Load item VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; - sprintf( VObjectDesc.ImageFile, "BIGITEMS\\%s", zName ); + sprintf( VObjectDesc.ImageFile, "BIGITEMS\\%s%s", zName, ext ); CHECKF( AddVideoObject( &VObjectDesc, &uiVo) ); *puiVo = uiVo; @@ -6671,7 +7526,13 @@ void ItemDescCallback( MOUSE_REGION * pRegion, INT32 iReason ) //Only exit the screen if we are NOT in the money interface. Only the DONE button should exit the money interface. if( gpItemDescObject->usItem != MONEY ) { + OBJECTTYPE *pTemp = gpItemDescPrevObject; DeleteItemDescriptionBox( ); + if (pTemp != NULL) + { + InternalInitItemDescriptionBox( pTemp, gsInvDescX, gsInvDescY, 0, gpItemDescSoldier ); + } + } } } @@ -6688,7 +7549,12 @@ void ItemDescCallback( MOUSE_REGION * pRegion, INT32 iReason ) //Only exit the screen if we are NOT in the money interface. Only the DONE button should exit the money interface. // if( gpItemDescObject->usItem != MONEY ) { + OBJECTTYPE *pTemp = gpItemDescPrevObject; DeleteItemDescriptionBox( ); + if (pTemp != NULL) + { + InternalInitItemDescriptionBox( pTemp, gsInvDescX, gsInvDescY, 0, gpItemDescSoldier ); + } } } } @@ -8107,10 +8973,17 @@ void BtnMoneyButtonCallback(GUI_BUTTON *btn,INT32 reason) if( ubButton != M_DONE ) { RenderItemDescriptionBox( ); - for( i=0; iArea.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); @@ -8150,10 +9023,17 @@ void BtnMoneyButtonCallback(GUI_BUTTON *btn,INT32 reason) } RenderItemDescriptionBox( ); - for( i=0; iArea.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY); } @@ -8267,7 +9147,7 @@ void RemoveMoney() void GetHelpTextForItem( STR16 pzStr, OBJECTTYPE *pObject, SOLDIERTYPE *pSoldier, int subObject ) { - CHAR16 pStr[ 250 ]; + CHAR16 pStr[ 500 ]; UINT16 usItem = pObject->usItem; INT32 iNumAttachments = 0; INT16 sValue; @@ -8394,6 +9274,7 @@ void GetHelpTextForItem( STR16 pzStr, OBJECTTYPE *pObject, SOLDIERTYPE *pSoldier //Info for weapons //swprintf( pStr, L"%s (%s) [%d%%]\n%s %d\n%s %d\n%s %d (%d)\n%s %s\n%s %1.1f %s", + INT8 accuracy = (UsingNewCTHSystem()==true?Weapon[ usItem ].nAccuracy:Weapon[ usItem ].bAccuracy); #ifdef CHINESE swprintf( pStr, ChineseSpecString4, #else @@ -8405,12 +9286,12 @@ void GetHelpTextForItem( STR16 pzStr, OBJECTTYPE *pObject, SOLDIERTYPE *pSoldier AmmoCaliber[ Weapon[ usItem ].ubCalibre ], sValue, gWeaponStatsDesc[ 9 ], //Accuracy String - Weapon[ usItem ].bAccuracy, + accuracy, gWeaponStatsDesc[ 11 ], //Damage String GetDamage(pObject), gWeaponStatsDesc[ 10 ], //Range String - gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? GunRange( pObject )/10 : GunRange( pObject ), //Modified Range - gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? Weapon[ usItem ].usRange/10 : Weapon[ usItem ].usRange, //Gun Range + gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? GunRange( pObject, NULL )/10 : GunRange( pObject, NULL ), // SANDRO - added argument //Modified Range + gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? GetModifiedGunRange(usItem)/10 : GetModifiedGunRange(usItem), //Gun Range gWeaponStatsDesc[ 6 ], //AP String (Weapon[ usItem ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction( pObject )) / 100), // Ready AP's apStr, //AP's @@ -8451,6 +9332,7 @@ void GetHelpTextForItem( STR16 pzStr, OBJECTTYPE *pObject, SOLDIERTYPE *pSoldier } //Info for weapons + INT8 accuracy = (UsingNewCTHSystem()==true?Weapon[ usItem ].nAccuracy:Weapon[ usItem ].bAccuracy); #ifdef CHINESE swprintf( pStr, L"%s [%d%]\n%s %d\n%s %d\n%s %d (%d)\n%s %s\n%s %1.1f %s", @@ -8461,12 +9343,12 @@ void GetHelpTextForItem( STR16 pzStr, OBJECTTYPE *pObject, SOLDIERTYPE *pSoldier ItemNames[ usItem ], sValue, gWeaponStatsDesc[ 9 ], //Accuracy String - Weapon[ usItem ].bAccuracy, + accuracy, gWeaponStatsDesc[ 11 ], //Damage String GetDamage(pObject), gWeaponStatsDesc[ 10 ], //Range String - gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? GunRange( pObject )/10 : GunRange( pObject ), //Modified Range - gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? Weapon[ usItem ].usRange/10 : Weapon[ usItem ].usRange, //Gun Range + gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? GunRange( pObject, NULL )/10 : GunRange( pObject, NULL ), // SANDRO - added argument //Modified Range + gGameSettings.fOptions[ TOPTION_SHOW_WEAPON_RANGE_IN_TILES ] ? GetModifiedGunRange(usItem)/10 : GetModifiedGunRange(usItem), //Gun Range gWeaponStatsDesc[ 6 ], //AP String apStr, //AP's gWeaponStatsDesc[ 12 ], //Weight String @@ -8633,24 +9515,37 @@ void GetHelpTextForItem( STR16 pzStr, OBJECTTYPE *pObject, SOLDIERTYPE *pSoldier // Add attachment string.... + CHAR16 attachString[ 300 ]; + memset(attachString,0,sizeof(attachString)); for (attachmentList::iterator iter = (*pObject)[subObject]->attachments.begin(); iter != (*pObject)[subObject]->attachments.end(); ++iter) { - iNumAttachments++; + if(iter->exists()){ - if ( iNumAttachments == 1 ) - { - wcscat( pStr, L"\n[" ); - } - else - { - wcscat( pStr, L", " ); - } + //Break off if it's too long. + if(wcslen(attachString)>270){ + wcscat( attachString, L"\n...." ); + break; + } - wcscat( pStr, ItemNames[ iter->usItem ] ); + iNumAttachments++; + + if ( iNumAttachments == 1 ) + { + swprintf( attachString, L"\n \n%s:\n", Message[ STR_ATTACHMENTS ] ); + } + else + { + wcscat( attachString, L"\n" ); + } + + wcscat( attachString, ItemNames[ iter->usItem ] ); + } } + if ( iNumAttachments > 0 ) { - wcscat( pStr, pMessageStrings[ MSG_END_ATTACHMENT_LIST ] ); + wcscat( pStr, attachString); + //wcscat( pStr, pMessageStrings[ MSG_END_ATTACHMENT_LIST ] ); } } @@ -9037,3 +9932,174 @@ void DeletePool(ITEM_POOL *pItemPool) MemFree(pItemPoolToDelete); } } + +void ItemDescTabButtonCallback( GUI_BUTTON *btn, INT32 reason ) +{ + switch (btn->UserData[0]) + { + case 0: + gubDescBoxPage = 0; + InternalInitEDBTooltipRegion( gpItemDescObject, guiCurrentItemDescriptionScreen ); + RenderItemDescriptionBox(); + MarkAButtonDirty( giItemDescAmmoButton ); // Required for tactical screen + ItemDescTabButtonOn( 0 ); + ItemDescTabButtonOff( 1 ); + ItemDescTabButtonOff( 2 ); + break; + case 1: + gubDescBoxPage = 1; + InternalInitEDBTooltipRegion( gpItemDescObject, guiCurrentItemDescriptionScreen ); + RenderItemDescriptionBox(); + MarkAButtonDirty( giItemDescAmmoButton ); // Required for tactical screen + ItemDescTabButtonOff( 0 ); + ItemDescTabButtonOn( 1 ); + ItemDescTabButtonOff( 2 ); + break; + case 2: + gubDescBoxPage = 2; + InternalInitEDBTooltipRegion( gpItemDescObject, guiCurrentItemDescriptionScreen ); + RenderItemDescriptionBox(); + MarkAButtonDirty( giItemDescAmmoButton ); // Required for tactical screen + ItemDescTabButtonOff( 0 ); + ItemDescTabButtonOff( 1 ); + ItemDescTabButtonOn( 2 ); + break; + } +} + +void ItemDescTabButtonOn( UINT8 ubItemDescTabButtonIndex ) +{ + Assert( ubItemDescTabButtonIndex < 3 ); + + // if button doesn't exist, return + if ( giInvDescTabButton[ ubItemDescTabButtonIndex ] == -1 ) + { + return; + } + + Assert( giInvDescTabButton[ ubItemDescTabButtonIndex ] < MAX_BUTTONS ); + + ButtonList[ giInvDescTabButton[ ubItemDescTabButtonIndex ] ]->uiFlags |= BUTTON_CLICKED_ON; + + MarkAButtonDirty( giInvDescTabButton[ ubItemDescTabButtonIndex ] ); +} + +void ItemDescTabButtonOff( UINT8 ubItemDescTabButtonIndex ) +{ + Assert( ubItemDescTabButtonIndex < 3 ); + + // if button doesn't exist, return + if ( giInvDescTabButton[ ubItemDescTabButtonIndex ] == -1 ) + { + return; + } + + Assert( giInvDescTabButton[ ubItemDescTabButtonIndex ] < MAX_BUTTONS ); + + ButtonList[ giInvDescTabButton[ ubItemDescTabButtonIndex ] ]->uiFlags &= ~(BUTTON_CLICKED_ON); + + MarkAButtonDirty( giInvDescTabButton[ ubItemDescTabButtonIndex ] ); +} + +void ItemDescAdvButtonCallback( GUI_BUTTON *btn, INT32 reason ) +{ + if (reason == MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + switch (btn->UserData[0]) + { + case 0: + gubDescBoxLine--; + InternalInitEDBTooltipRegion( gpItemDescObject, guiCurrentItemDescriptionScreen ); + RenderItemDescriptionBox(); + // Required for tactical screen + MarkAButtonDirty( giItemDescAmmoButton ); + for (INT8 x = 0; x < 3; x++) + { + if (giInvDescTabButton[x] != -1) + { + // HEADROCK HAM 4: Makes sure the Tab Buttons are always redrawn on top. + MarkAButtonDirty( giInvDescTabButton[ x ] ); + } + } + ItemDescAdvButtonOff( 0 ); + ItemDescTabButtonOff( 1 ); + ItemDescAdvButtonCheck(); + break; + case 1: + gubDescBoxLine++; + InternalInitEDBTooltipRegion( gpItemDescObject, guiCurrentItemDescriptionScreen ); + RenderItemDescriptionBox(); + // Required for tactical screen + MarkAButtonDirty( giItemDescAmmoButton ); + for (INT8 x = 0; x < 3; x++) + { + if (giInvDescTabButton[x] != -1) + { + // HEADROCK HAM 4: Makes sure the Tab Buttons are always redrawn on top. + MarkAButtonDirty( giInvDescTabButton[ x ] ); + } + } + ItemDescTabButtonOff( 0 ); + ItemDescTabButtonOff( 1 ); + ItemDescAdvButtonCheck(); + break; + } + } +} + +void ItemDescAdvButtonOn( UINT8 ubItemDescAdvButtonIndex ) +{ + Assert( ubItemDescAdvButtonIndex < 2 ); + + // if button doesn't exist, return + if ( giInvDescAdvButton[ ubItemDescAdvButtonIndex ] == -1 ) + { + return; + } + + Assert( giInvDescAdvButton[ ubItemDescAdvButtonIndex ] < MAX_BUTTONS ); + + ButtonList[ giInvDescAdvButton[ ubItemDescAdvButtonIndex ] ]->uiFlags |= BUTTON_CLICKED_ON; + + MarkAButtonDirty( giInvDescAdvButton[ 0 ] ); + MarkAButtonDirty( giInvDescAdvButton[ 1 ] ); +} + +void ItemDescAdvButtonOff( UINT8 ubItemDescAdvButtonIndex ) +{ + Assert( ubItemDescAdvButtonIndex < 2 ); + + // if button doesn't exist, return + if ( giInvDescAdvButton[ ubItemDescAdvButtonIndex ] == -1 ) + { + return; + } + + Assert( giInvDescAdvButton[ ubItemDescAdvButtonIndex ] < MAX_BUTTONS ); + + ButtonList[ giInvDescAdvButton[ ubItemDescAdvButtonIndex ] ]->uiFlags &= ~(BUTTON_CLICKED_ON); + + MarkAButtonDirty( giInvDescAdvButton[ 0 ] ); + MarkAButtonDirty( giInvDescAdvButton[ 1 ] ); +} + +void ItemDescAdvButtonCheck( void ) +{ + if (gubDescBoxLine <= 0) + { + DisableButton( giInvDescAdvButton[0] ); + } + else + { + EnableButton( giInvDescAdvButton[0] ); + } + + if (NUM_UDB_ADV_LINES < gubDescBoxTotalAdvLines - gubDescBoxLine) + { + EnableButton( giInvDescAdvButton[1] ); + } + else + { + DisableButton( giInvDescAdvButton[1] ); + } +} diff --git a/Tactical/Interface Items.h b/Tactical/Interface Items.h index 2fc6c668..9173c533 100644 --- a/Tactical/Interface Items.h +++ b/Tactical/Interface Items.h @@ -10,6 +10,7 @@ #define SM_INV_SLOT_WIDTH 30 #define SM_INV_SLOT_HEIGHT 23 #define ATTACH_SLOT_WIDTH 32 +#define ATTACH_SLOT_BIG_WIDTH 64 #define VEST_INV_SLOT_WIDTH 43 #define VEST_INV_SLOT_HEIGHT 24 #define LEGS_INV_SLOT_WIDTH 43 @@ -17,6 +18,30 @@ #define HEAD_INV_SLOT_WIDTH 43 #define HEAD_INV_SLOT_HEIGHT 24 +#define NUM_UDB_GEN_LINES 12 +#define NUM_UDB_ADV_LINES 12 + +// HEADROCK HAM 4: These rectangle definitions are used in UDB to determine locations for icons, data, and tooltip +// regions. They replace the plethora of region data provided in EDB. +typedef struct +{ + INT16 sLeft; + INT16 sTop; + INT16 sRight; + INT16 sBottom; +} INV_DESC_REGIONS; + +extern INV_DESC_REGIONS gItemDescLBEBackground[4]; // Coordinates for displaying LBE background image +extern INV_DESC_REGIONS gItemDescGenHeaderRegions[3]; // Header text regions for various parts of the General Tab +extern INV_DESC_REGIONS gItemDescGenIndexRegions[3][4]; // Index text regions for various parts of the General Tab +extern INV_DESC_REGIONS gItemDescGenRegions[NUM_UDB_GEN_LINES * 2][4]; // Data regions, 4 sub-columns each +extern INV_DESC_REGIONS gItemDescGenSecondaryRegions[26]; // Secondary data regions, 3x5 for now (possible 3x6?) +extern INV_DESC_REGIONS gItemDescTextRegions[7]; // Main description regions +extern INV_DESC_REGIONS gItemDescAdvIndexRegions[1][4]; +extern INV_DESC_REGIONS gItemDescAdvRegions[NUM_UDB_ADV_LINES][4]; // Advanced data regions, 4 sub-columns each + +// ODB arrays +extern INV_DESC_REGIONS gODBItemDescRegions[4][8]; // Four regions of eight sub-regions each. //CHRISL: moved from Interface Items.cpp typedef struct @@ -54,7 +79,8 @@ void ItemDescCallback( MOUSE_REGION * pRegion, INT32 iReason ); #define INV_BAR_DY 21 #define ITEM_STATS_WIDTH 26 #define ITEM_STATS_HEIGHT 8 -#define EXCEPTIONAL_DAMAGE 40 +#define EXCEPTIONAL_GUN_DAMAGE 40 +#define EXCEPTIONAL_MELEE_DAMAGE 40 #define EXCEPTIONAL_WEIGHT 20 #define EXCEPTIONAL_RANGE 400 #define EXCEPTIONAL_MAGAZINE 50 @@ -81,16 +107,13 @@ extern INT16 ITEMDESC_NAME_X; extern INT16 ITEMDESC_NAME_Y; extern INT16 ITEMDESC_ITEM_X; extern INT16 ITEMDESC_ITEM_Y; -extern INT16 ITEMDESC_DESC_START_X; -extern INT16 ITEMDESC_DESC_START_Y; -extern INT16 ITEMDESC_PROS_START_X; -extern INT16 ITEMDESC_PROS_START_Y; -extern INT16 ITEMDESC_CONS_START_X; -extern INT16 ITEMDESC_CONS_START_Y; -extern INT16 ITEMDESC_DESC_WIDTH; extern INT16 ITEMDESC_ITEM_STATUS_X; extern INT16 ITEMDESC_ITEM_STATUS_Y; extern INT16 ITEMDESC_ITEM_STATUS_HEIGHT; +extern INT16 ITEMDESC_AMMO_X; +extern INT16 ITEMDESC_AMMO_Y; +extern INT16 ITEMDESC_DONE_X; +extern INT16 ITEMDESC_DONE_Y; // A STRUCT USED INTERNALLY FOR INV SLOT REGIONS typedef struct @@ -211,7 +234,9 @@ BOOLEAN InitKeyItemDescriptionBox( SOLDIERTYPE *pSoldier, UINT8 ubPosition, INT1 void RenderItemDescriptionBox( ); void HandleItemDescriptionBox( BOOLEAN *pfDirty ); void DeleteItemDescriptionBox( ); - +extern BOOLEAN UseNASDesc(OBJECTTYPE *pObject); +INT16 sNASXCorrection(OBJECTTYPE * pObject); +INT16 sNASYCorrection(OBJECTTYPE * pObject); BOOLEAN InItemStackPopup( ); BOOLEAN InitItemStackPopup( SOLDIERTYPE *pSoldier, UINT8 ubPosition, INT16 sInvX, INT16 sInvY, INT16 sInvWidth, INT16 sInvHeight ); diff --git a/Tactical/Interface Panels.cpp b/Tactical/Interface Panels.cpp index b119bc70..4efed5ae 100644 --- a/Tactical/Interface Panels.cpp +++ b/Tactical/Interface Panels.cpp @@ -76,6 +76,8 @@ #include "Campaign.h" #endif +//legion by Jazz +#include "Interface Utils.h" //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; @@ -367,6 +369,7 @@ typedef enum DONE_IMAGES, MAPSCREEN_IMAGES, BACKPACK_IMAGES, + //HOP_IMAGES, //legion by Jazz NUM_SM_BUTTON_IMAGES }; @@ -435,10 +438,14 @@ UINT16 gusOldItemIndex; UINT16 gusNewItemIndex; BOOLEAN gfDeductPoints; - - - - +// HEADROCK HAM 4: This variable tells the program what "page" of the description box we are currently looking at. +// By saving this in memory, we tell the DescBox which background and values to draw, and make sure that we end up +// on the same page every time we open the description box. UDB buttons allow switching between pages. +UINT8 gubDescBoxPage; +// Record which line we're looking at. This only applied to the Advanced tab in description boxes. +UINT8 gubDescBoxLine; +// Record how many lines this item has to display. This only applies to the Advanced tab. +UINT8 gubDescBoxTotalAdvLines; INT32 iSMPanelButtons[ NUM_SM_BUTTONS ]; INT32 iTEAMPanelButtons[ NUM_TEAM_BUTTONS ]; @@ -464,6 +471,8 @@ MOUSE_REGION gTEAM_FirstHandInv[ NUMBER_OF_SOLDIERS_PER_SQUAD ]; MOUSE_REGION gTEAM_SecondHandInv[ NUMBER_OF_SOLDIERS_PER_SQUAD ]; MOUSE_REGION gTEAM_EnemyIndicator[ NUMBER_OF_SOLDIERS_PER_SQUAD ]; +MOUSE_REGION gSM_SELMERCCamoRegion; // Added by Sandro + BOOLEAN gfTEAM_HandInvDispText[ NUMBER_OF_SOLDIERS_PER_SQUAD ][ NUM_INV_SLOTS ]; BOOLEAN gfSM_HandInvDispText[ NUM_INV_SLOTS ]; @@ -501,7 +510,9 @@ INT8 gbZipperButPos[2][2] = 1, 0 }; - +//Legion by Jazz +void BtnOknoCallback(GUI_BUTTON *btn,INT32 reason); +void BtnFenceCallback(GUI_BUTTON *btn,INT32 reason); // Mouse button and region callbacks //void BtnPositionCallback( GUI_BUTTON *btn, INT32 reason ); @@ -561,7 +572,7 @@ void UpdateSelectedSoldier( UINT16 usSoldierID, BOOLEAN fSelect ); void CheckForFacePanelStartAnims( SOLDIERTYPE *pSoldier, INT16 sPanelX, INT16 sPanelY ); void HandleSoldierFaceFlash( SOLDIERTYPE *pSoldier, INT16 sFaceX, INT16 sFaceY ); BOOLEAN PlayerExistsInSlot( UINT8 ubID ); -void UpdateStatColor( UINT32 uiTimer, BOOLEAN fUpdate ); +void UpdateStatColor( UINT32 uiTimer, BOOLEAN fIncrease, BOOLEAN fDamaged ); // SADNRO - added argument extern void UpdateItemHatches(); @@ -795,6 +806,10 @@ void UpdateSMPanel( ) INT8 bDirection; UINT8 ubStanceState; + //jump window by Jazz + //BOOLEAN fNearLowerLevelOkno; + //BOOLEAN fNearHeigherLevelOkno; + if (TileIsOutOfBounds(gpSMCurrentMerc->sGridNo)) { return; @@ -940,9 +955,47 @@ void UpdateSMPanel( ) DisableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); + + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //DisableButton( iSMPanelButtons[ HOP_BUTTON ] ); //Legion by Jazz + //} GetMercClimbDirection( gpSMCurrentMerc->ubID, &fNearLowerLevel, &fNearHeigherLevel ); + +//--------------------- Legion----------------- +/* +if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + { + + if ( gpSMCurrentMerc->pathing.bLevel == 0 ) + { + GetMercOknoDirection( gpSMCurrentMerc->ubID, &fNearLowerLevelOkno, &fNearHeigherLevelOkno ); //Legion by JAzz + if ( fNearLowerLevelOkno || fNearHeigherLevelOkno ) + { + if ( fNearLowerLevelOkno ) + { + if ( EnoughPoints( gpSMCurrentMerc, GetAPsToJumpThroughWindows( gpSMCurrentMerc, TRUE ), 0, FALSE ) ) + { + EnableButton( iSMPanelButtons[ HOP_BUTTON ] ); + } + } + + if ( fNearHeigherLevelOkno ) + { + if ( EnoughPoints( gpSMCurrentMerc, GetAPsToJumpThroughWindows( gpSMCurrentMerc, FALSE ), 0, FALSE ) ) + { + EnableButton( iSMPanelButtons[ HOP_BUTTON ] ); + } + } + } + } + } +*/ + //--------- + if ( fNearLowerLevel || fNearHeigherLevel ) { if ( fNearLowerLevel ) @@ -962,6 +1015,27 @@ void UpdateSMPanel( ) } } + //----------------------------Legion by Jazz------------------------------ + //DisableButton + /* + if (gGameExternalOptions.fCanJumpThroughWindows == TRUE ) + { + if ( FindOknoDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) && gpSMCurrentMerc->pathing.bLevel == 0 ) + { + EnableButton( iSMPanelButtons[ HOP_BUTTON ] ); + } + } + */ + if (gGameExternalOptions.fCanClimbOnWalls == TRUE) + { + if ( FindFenceDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) ) + { + EnableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); + } + + } + //------------------------------------------ + if ( FindFenceJumpDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) ) { EnableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); @@ -1040,6 +1114,11 @@ void UpdateSMPanel( ) // If not selected ( or dead ), disable/gray some buttons if ( gusSelectedSoldier != gpSMCurrentMerc->ubID || ( gpSMCurrentMerc->stats.bLife < OKLIFE ) || (gTacticalStatus.ubCurrentTeam != gbPlayerNum) || gfSMDisableForItems ) { + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //DisableButton( iSMPanelButtons[ HOP_BUTTON ] ); //Legion by Jazz + //} DisableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); DisableButton( iSMPanelButtons[ BURSTMODE_BUTTON ] ); DisableButton( iSMPanelButtons[ STANCEUP_BUTTON ] ); @@ -1110,7 +1189,7 @@ void ReevaluateItemHatches( SOLDIERTYPE *pSoldier, BOOLEAN fAllValid ) //if( guiCurrentScreen != MAP_SCREEN ) { // Check attachments, override to valid placement if valid merge... - if ( ValidAttachment( gpItemPointer->usItem, pSoldier->inv[ cnt ].usItem ) ) + if ( ValidAttachment( gpItemPointer->usItem, &(pSoldier->inv[ cnt ]) ) ) { gbInvalidPlacementSlot[ cnt ] = FALSE; } @@ -1289,6 +1368,11 @@ void EnableSMPanelButtons( BOOLEAN fEnable , BOOLEAN fFromItemPickup ) // only enable the following if NOT in shopkeeper's interface if ( !(guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE ) ) { + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //EnableButton( iSMPanelButtons[ HOP_BUTTON ] ); //Legion by JAzz + //} EnableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); EnableButton( iSMPanelButtons[ BURSTMODE_BUTTON ] ); EnableButton( iSMPanelButtons[ STANCEUP_BUTTON ] ); @@ -1332,6 +1416,11 @@ void EnableSMPanelButtons( BOOLEAN fEnable , BOOLEAN fFromItemPickup ) } else { + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //DisableButton( iSMPanelButtons[ HOP_BUTTON ] ); //Legion by Jazz + //} DisableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); DisableButton( iSMPanelButtons[ BURSTMODE_BUTTON ] ); DisableButton( iSMPanelButtons[ STANCEUP_BUTTON ] ); @@ -2059,6 +2148,11 @@ BOOLEAN InitializeSMPanel( ) MSYS_NO_CURSOR, MSYS_NO_CALLBACK, SelectedMercButtonCallback ); MSYS_AddRegion( &gSM_SELMERCBarsRegion ); + // Added by SANDRO - define region for camo tooltip window + MSYS_DefineRegion( &gSM_SELMERCCamoRegion, ( SM_CAMMO_X + 2), ( SM_CAMMO_Y ), + (SM_CAMMO_X + 28), (SM_CAMMO_Y + 10), MSYS_PRIORITY_NORMAL, + MSYS_NO_CURSOR, MSYS_NO_CALLBACK, SelectedMercButtonCallback ); + MSYS_AddRegion( &gSM_SELMERCCamoRegion ); // CHRISL: Setup default coords if((UsingNewInventorySystem() == true)) @@ -2090,7 +2184,9 @@ BOOLEAN InitializeSMPanel( ) BOOLEAN CreateSMPanelButtons( ) { -CHAR8 ubString[48]; + CHAR8 ubString[48]; + //CHAR8 ubString2[48]; //legion DisableButton + //CHAR8 ubString3[48]; //legion // CHRISL: Reset backpack buttons as well giSMStealthImages = giSMZipperImages = giSMDropPackImages = -1; @@ -2099,6 +2195,14 @@ CHAR8 ubString[48]; gfAllDisabled = FALSE; FilenameForBPP("INTERFACE\\inventory_buttons.sti", ubString); + + //Legion by Jazz + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + // FilenameForBPP("INTERFACE\\inventory_buttons_WINDOW_2.sti", ubString2); //LEGION + //} + //----------------------- // Load button Graphics iSMPanelImages[ STANCEUP_IMAGES ] = LoadButtonImage(ubString,-1,0,-1,10,-1 ); @@ -2112,8 +2216,21 @@ CHAR8 ubString[48]; iSMPanelImages[ LOOK_IMAGES ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ] ,-1,2,-1,12,-1 ); iSMPanelImages[ TALK_IMAGES ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ] ,-1,6,-1,16,-1 ); iSMPanelImages[ MUTE_IMAGES ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ] ,-1,5,-1,15,-1 ); + + //Legion by Jazz + //DisableButton + /* + if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + { + iSMPanelImages[ OPTIONS_IMAGES ] = LoadButtonImage(ubString2,-1,0,-1,1,-1 ); //legion + } + else + { iSMPanelImages[ OPTIONS_IMAGES ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ] ,-1,24,-1,25,-1 ); - + } + */ + iSMPanelImages[ OPTIONS_IMAGES ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ] ,-1,24,-1,25,-1 ); + iBurstButtonImages[ WM_NORMAL ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ], -1, 7, -1, -1, -1 ); iBurstButtonImages[ WM_BURST ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ], -1, 17, -1, -1, -1 ); iBurstButtonImages[ WM_AUTOFIRE ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ], -1, 17, -1, -1, -1 ); @@ -2121,6 +2238,12 @@ CHAR8 ubString[48]; iBurstButtonImages[ WM_ATTACHED_GL_BURST ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ], -1, 17, -1, -1, -1 ); iBurstButtonImages[ WM_ATTACHED_GL_AUTO ] = UseLoadedButtonImage( iSMPanelImages[ STANCEUP_IMAGES ], -1, 17, -1, -1, -1 ); + //Legion by JAzz + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + // iSMPanelImages[ HOP_IMAGES ] = LoadButtonImage(ubString2,-1,2,-1,3,-1 ); + //} FilenameForBPP("INTERFACE\\invadd-ons.sti", ubString); // Load button Graphics @@ -2140,6 +2263,29 @@ CHAR8 ubString[48]; // SET BUTTONS TO -1 memset( iSMPanelButtons, -1, sizeof( iSMPanelButtons ) ); + + + //Legion by Jazz + //DisableButton + /*if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + { + + if (UsingNewInventorySystem() == true) + { + iSMPanelButtons[ HOP_BUTTON ] = QuickCreateButton( iSMPanelImages[ HOP_IMAGES ], SM_BURSTMODEB_X-30, SM_BURSTMODEB_Y, + BUTTON_TOGGLE, MSYS_PRIORITY_HIGH - 1, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnOknoCallback ); + } + else + { + iSMPanelButtons[ HOP_BUTTON ] = QuickCreateButton( iSMPanelImages[ HOP_IMAGES ], SM_BURSTMODEB_X-98, SM_BURSTMODEB_Y+35, + BUTTON_TOGGLE, MSYS_PRIORITY_HIGH - 1, + DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnOknoCallback ); + } + } + */ + //----------------------- + iSMPanelButtons[ SM_MAP_SCREEN_BUTTON ] = QuickCreateButton( iSMPanelImages[ MAPSCREEN_IMAGES ], SM_MAPSCREEN_X, SM_MAPSCREEN_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH - 1, @@ -2385,6 +2531,8 @@ BOOLEAN ShutdownSMPanel( ) MSYS_RemoveRegion( &gSM_SELMERCMoneyRegion ); MSYS_RemoveRegion( &gSM_SELMERCEnemyIndicatorRegion ); + MSYS_RemoveRegion( &gSM_SELMERCCamoRegion ); // added - SANDRO + HandleMouseOverSoldierFaceForContMove( gpSMCurrentMerc, FALSE ); MSYS_RemoveRegion( &gViewportRegion ); @@ -2515,6 +2663,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sAgilityGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sAgilityGain+1)) / SubpointsPerPoint(AGILAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_AGI_Y-1); ClipRect.iBottom = (SM_AGI_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_AGI_X; @@ -2526,6 +2675,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sDexterityGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sDexterityGain+1)) / SubpointsPerPoint(DEXTAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_DEX_Y-1); ClipRect.iBottom = (SM_DEX_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_DEX_X; @@ -2537,6 +2687,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sStrengthGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sStrengthGain+1)) / SubpointsPerPoint(STRAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_STR_Y-1); ClipRect.iBottom = (SM_STR_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_STR_X; @@ -2548,6 +2699,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sWisdomGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sWisdomGain+1)) / SubpointsPerPoint(WISDOMAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_WIS_Y-1); ClipRect.iBottom = (SM_WIS_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_WIS_X; @@ -2559,6 +2711,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMarksmanshipGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMarksmanshipGain+1)) / SubpointsPerPoint(MARKAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_MRKM_Y-1); ClipRect.iBottom = (SM_MRKM_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_MRKM_X; @@ -2570,6 +2723,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sLeadershipGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sLeadershipGain+1)) / SubpointsPerPoint(LDRAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_CHAR_Y-1); ClipRect.iBottom = (SM_CHAR_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_CHAR_X; @@ -2581,6 +2735,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMechanicGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMechanicGain+1)) / SubpointsPerPoint(MECHANAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_MECH_Y-1); ClipRect.iBottom = (SM_MECH_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_MECH_X; @@ -2592,6 +2747,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExplosivesGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExplosivesGain+1)) / SubpointsPerPoint(EXPLODEAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_EXPL_Y-1); ClipRect.iBottom = (SM_EXPL_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_EXPL_X; @@ -2603,6 +2759,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMedicalGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sMedicalGain+1)) / SubpointsPerPoint(MEDICALAMT,0); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_MED_Y-1); ClipRect.iBottom = (SM_MED_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_MED_X; @@ -2614,6 +2771,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExpLevelGain) { ubBarWidth = (SM_STATS_WIDTH * (gMercProfiles[ gpSMCurrentMerc->ubProfile ].sExpLevelGain+1)) / SubpointsPerPoint(EXPERAMT, gpSMCurrentMerc->stats.bExpLevel); + ubBarWidth = __max(0, __min(ubBarWidth, SM_STATS_WIDTH)); ClipRect.iTop = (SM_EXPLVL_Y-1); ClipRect.iBottom = (SM_EXPLVL_Y-1) + SM_STATS_HEIGHT; ClipRect.iLeft = SM_EXPLVL_X; @@ -2675,61 +2833,61 @@ void RenderSMPanel( BOOLEAN *pfDirty ) mprintf( SM_CAMMO_PERCENT_X, SM_CAMMO_PERCENT_Y, L"%%" ); #endif - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeAgilityTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & AGIL_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeAgilityTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & AGIL_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_AGILITY] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bAgility ); FindFontRightCoordinates(SM_AGI_X, SM_AGI_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeDexterityTime,( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & DEX_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeDexterityTime,( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & DEX_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_DEXTERITY] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bDexterity ); FindFontRightCoordinates(SM_DEX_X, SM_DEX_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeStrengthTime, ( BOOLEAN )( gpSMCurrentMerc->usValueGoneUp & STRENGTH_INCREASE?TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeStrengthTime, ( BOOLEAN )( gpSMCurrentMerc->usValueGoneUp & STRENGTH_INCREASE?TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_STRENGTH] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bStrength ); FindFontRightCoordinates(SM_STR_X, SM_STR_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeLeadershipTime, ( BOOLEAN )( gpSMCurrentMerc->usValueGoneUp & LDR_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeLeadershipTime, ( BOOLEAN )( gpSMCurrentMerc->usValueGoneUp & LDR_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_LEADERSHIP] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bLeadership ); FindFontRightCoordinates(SM_CHAR_X, SM_CHAR_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeWisdomTime,( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & WIS_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeWisdomTime,( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & WIS_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_WISDOM] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bWisdom ); FindFontRightCoordinates(SM_WIS_X, SM_WIS_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeLevelTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & LVL_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeLevelTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & LVL_INCREASE? TRUE: FALSE ), FALSE ); swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bExpLevel ); FindFontRightCoordinates(SM_EXPLVL_X, SM_EXPLVL_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeMarksmanshipTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & MRK_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeMarksmanshipTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & MRK_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_MARKSMANSHIP] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bMarksmanship ); FindFontRightCoordinates(SM_MRKM_X, SM_MRKM_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeExplosivesTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & EXP_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeExplosivesTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & EXP_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_EXPLOSIVES] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bExplosive ); FindFontRightCoordinates(SM_EXPL_X, SM_EXPL_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeMechanicalTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & MECH_INCREASE ? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeMechanicalTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & MECH_INCREASE ? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_MECHANICAL] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bMechanical ); FindFontRightCoordinates(SM_MECH_X, SM_MECH_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); mprintf( usX, usY , sString ); - UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeMedicalTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & MED_INCREASE? TRUE: FALSE ) ); + UpdateStatColor( gpSMCurrentMerc->timeChanges.uiChangeMedicalTime, ( BOOLEAN ) ( gpSMCurrentMerc->usValueGoneUp & MED_INCREASE? TRUE: FALSE ), ( BOOLEAN ) ( ( gGameOptions.fNewTraitSystem && ( gpSMCurrentMerc->ubCriticalStatDamage[DAMAGED_STAT_MEDICAL] > 0 )) ? TRUE : FALSE)); // SANDRO swprintf( sString, L"%2d", gpSMCurrentMerc->stats.bMedical ); FindFontRightCoordinates(SM_MED_X, SM_MED_Y ,SM_STATS_WIDTH ,SM_STATS_HEIGHT ,sString, BLOCKFONT2, &usX, &usY); @@ -2796,6 +2954,42 @@ void RenderSMPanel( BOOLEAN *pfDirty ) if ( *pfDirty != DIRTYLEVEL0 ) { + /////////////////////////////////////////////////////////////////////// + // SANDRO - added a tooltip window showing exact camo percentage for every type + // ******************************************************************* + CHAR16 pStrCamo[400]; + swprintf( pStrCamo, L"" ); + swprintf( pStr, L""); + if ((gpSMCurrentMerc->bCamo + gpSMCurrentMerc->wornCamo) > 0 ) + { + swprintf( pStrCamo, L"\n%d/%d%s %s", gpSMCurrentMerc->bCamo, gpSMCurrentMerc->wornCamo, L"%", gzMiscItemStatsFasthelp[ 21 ]); + wcscat( pStr, pStrCamo); + swprintf( pStrCamo, L"" ); + } + if ((gpSMCurrentMerc->urbanCamo + gpSMCurrentMerc->wornUrbanCamo) > 0 ) + { + swprintf( pStrCamo, L"\n%d/%d%s %s", gpSMCurrentMerc->urbanCamo, gpSMCurrentMerc->wornUrbanCamo, L"%", gzMiscItemStatsFasthelp[ 22 ]); + wcscat( pStr, pStrCamo); + swprintf( pStrCamo, L"" ); + } + if ((gpSMCurrentMerc->desertCamo + gpSMCurrentMerc->wornDesertCamo) > 0 ) + { + swprintf( pStrCamo, L"\n%d/%d%s %s", gpSMCurrentMerc->desertCamo, gpSMCurrentMerc->wornDesertCamo, L"%", gzMiscItemStatsFasthelp[ 23 ]); + wcscat( pStr, pStrCamo); + swprintf( pStrCamo, L"" ); + } + if ((gpSMCurrentMerc->snowCamo + gpSMCurrentMerc->wornSnowCamo) > 0 ) + { + swprintf( pStrCamo, L"\n%d/%d%s %s", gpSMCurrentMerc->snowCamo, gpSMCurrentMerc->wornSnowCamo, L"%", gzMiscItemStatsFasthelp[ 24 ] ); + wcscat( pStr, pStrCamo); + swprintf( pStrCamo, L"" ); + } + + SetRegionFastHelpText( &(gSM_SELMERCCamoRegion), pStr ); + SetRegionHelpEndCallback( &gSM_SELMERCCamoRegion, SkiHelpTextDoneCallBack ); + + ///////////////////////////////////////////////////////////////////////////////////////// + // UPdate stats! if ( gpSMCurrentMerc->stats.bLife != 0 ) { @@ -2881,10 +3075,14 @@ void RenderSMPanel( BOOLEAN *pfDirty ) // Render clock // CHRISL: If we're in NIV mode, don't render the clock on the SM panel if(UsingNewInventorySystem() == false) + { RenderClock( INTERFACE_CLOCK_X, INTERFACE_CLOCK_Y ); - CreateMouseRegionForPauseOfClock( INTERFACE_CLOCK_X, INTERFACE_CLOCK_Y ); + CreateMouseRegionForPauseOfClock( INTERFACE_CLOCK_X, INTERFACE_CLOCK_Y ); + } + // CHRISL: Change function call to include X,Y coordinates. RenderTownIDString( LOCATION_NAME_X, LOCATION_NAME_Y ); + }//XXXj in tactical bug is: NIV pushes town name +Y and boom else { @@ -2921,11 +3119,16 @@ void RenderSMPanel( BOOLEAN *pfDirty ) } -void UpdateStatColor( UINT32 uiTimer, BOOLEAN fIncrease ) +void UpdateStatColor( UINT32 uiTimer, BOOLEAN fIncrease, BOOLEAN fDamaged ) // SANDRO - added argument { if ( gpSMCurrentMerc->stats.bLife >= OKLIFE ) { - if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + uiTimer) && ( uiTimer != 0 ) ) + // SANDRO - if damaged stat we could regain, show in red until repaired + if( fDamaged ) + { + SetFontForeground( FONT_RED ); + } + else if( ( GetJA2Clock() < CHANGE_STAT_RECENTLY_DURATION + uiTimer) && ( uiTimer != 0 ) ) { if( fIncrease ) { @@ -3063,6 +3266,34 @@ void SMInvClickCamoCallback( MOUSE_REGION * pRegion, INT32 iReason ) { if ( fGoodAPs ) { + if (gGameExternalOptions.fShowCamouflageFaces == TRUE ) + { + if ( gpSMCurrentMerc->bCamo > 0 ) + { + gCamoFace[gpSMCurrentMerc->ubProfile].gCamoface = TRUE; + DeleteSoldierFace( gpSMCurrentMerc );// remove face + gpSMCurrentMerc->iFaceIndex = InitSoldierFace( gpSMCurrentMerc );// create new face + } + if ( gpSMCurrentMerc->urbanCamo > 0 ) + { + gCamoFace[gpSMCurrentMerc->ubProfile].gUrbanCamoface = TRUE; + DeleteSoldierFace( gpSMCurrentMerc );// remove face + gpSMCurrentMerc->iFaceIndex = InitSoldierFace( gpSMCurrentMerc );// create new face + } + if ( gpSMCurrentMerc->desertCamo > 0) + { + gCamoFace[gpSMCurrentMerc->ubProfile].gDesertCamoface = TRUE; + DeleteSoldierFace( gpSMCurrentMerc );// remove face + gpSMCurrentMerc->iFaceIndex = InitSoldierFace( gpSMCurrentMerc );// create new face + } + if ( gpSMCurrentMerc->snowCamo > 0) + { + gCamoFace[gpSMCurrentMerc->ubProfile].gSnowCamoface = TRUE; + DeleteSoldierFace( gpSMCurrentMerc );// remove face + gpSMCurrentMerc->iFaceIndex = InitSoldierFace( gpSMCurrentMerc );// create new face + } + } + // Dirty fInterfacePanelDirty = DIRTYLEVEL2; @@ -3442,7 +3673,7 @@ void SMInvClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) if ( uiHandPos == HANDPOS || uiHandPos == SECONDHANDPOS || uiHandPos == HELMETPOS || uiHandPos == VESTPOS || uiHandPos == LEGPOS ) { //if ( ValidAttachmentClass( usNewItemIndex, usOldItemIndex ) ) - if ( ValidAttachment( usNewItemIndex, usOldItemIndex ) ) + if ( ValidAttachment( usNewItemIndex, &(gpSMCurrentMerc->inv[uiHandPos]) ) ) { // it's an attempt to attach; bring up the inventory panel if ( !InItemDescriptionBox( ) ) @@ -3658,6 +3889,10 @@ BOOLEAN ChangeZipperStatus(SOLDIERTYPE *pSoldier, BOOLEAN newStatus) //Set AP cost based on what we're doing sAPCost = (newStatus) ? APBPConstants[AP_CLOSE_ZIPPER] : APBPConstants[AP_OPEN_ZIPPER]; + // SANDRO - ambidextrous bonus to handle things faster + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + sAPCost = (INT16)((sAPCost * (100 - gSkillTraitValues.ubAMWorkBackpackAPsReduction) / 100) + 0.5); + //Are we currently in combat? if(gTacticalStatus.uiFlags & INCOMBAT) { @@ -3830,7 +4065,7 @@ void MergeMessageBoxCallBack( UINT8 ubExitValue ) { //ADB see what happens here DebugBreakpoint(); - gpSMCurrentMerc->inv[ gubHandPos ].AttachObject( gpItemPointerSoldier, gpItemPointer ); + gpSMCurrentMerc->inv[ gubHandPos ].AttachObject( gpItemPointerSoldier, gpItemPointer, FALSE ); // re-evaluate repairs gfReEvaluateEveryonesNothingToDo = TRUE; @@ -4205,6 +4440,18 @@ void BtnClimbCallback(GUI_BUTTON *btn,INT32 reason) { gpSMCurrentMerc->BeginSoldierClimbUpRoof( ); } + + //---------------Legion by JAzz----------- + + if (gGameExternalOptions.fCanClimbOnWalls == TRUE) + { + if ( FindFenceDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) ) + { + gpSMCurrentMerc->BeginSoldierFence( ); + } + } + + //------------------------------------------ if ( FindFenceJumpDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) ) { @@ -4686,7 +4933,7 @@ BOOLEAN InitializeTEAMPanelCoords( ) */ // CHRISL: New definitions for the team panel clock and location coordinates INTERFACE_CLOCK_TM_X = ( SCREEN_WIDTH - 86 ); - INTERFACE_CLOCK_TM_Y = ( 98 + INTERFACE_START_Y ); + INTERFACE_CLOCK_TM_Y = ( 99 + INTERFACE_START_Y ); LOCATION_NAME_TM_X = ( SCREEN_WIDTH - 92 ); LOCATION_NAME_TM_Y = ( 65 + INTERFACE_START_Y ); @@ -6770,7 +7017,8 @@ void KeyRingSlotInvClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) BOOLEAN fOKToGo = FALSE; BOOLEAN fDeductPoints = FALSE; - if( ( gpItemPointer->usItem < FIRST_KEY ) || ( gpItemPointer->usItem > KEY_32 ) ) + // WANNE: Instead of checking the item number for a key, check the itemclass!!! + if (Item[gpItemPointer->usItem].usItemClass != IC_KEY) { return; } @@ -6944,6 +7192,11 @@ void KeyRingSlotInvClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) void DisableSMPpanelButtonsWhenInShopKeeperInterface( BOOLEAN fDontDrawButtons ) { //Go through the buttons that will be under the ShopKeepers ATM panel and disable them + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //DisableButton( iSMPanelButtons[ HOP_BUTTON ] ); //Legion by Jazz + //} DisableButton( iSMPanelButtons[ STANCEUP_BUTTON ] ); DisableButton( iSMPanelButtons[ UPDOWN_BUTTON ] ); DisableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); @@ -6962,6 +7215,11 @@ void DisableSMPpanelButtonsWhenInShopKeeperInterface( BOOLEAN fDontDrawButtons ) //Make sure the mapscreen button is disabled DisableButton( iSMPanelButtons[ SM_MAP_SCREEN_BUTTON ] ); + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //DisableButton( iSMPanelButtons[ HOP_BUTTON ] ); //legion by Jazz + //} DisableButton( iSMPanelButtons[ STANCEUP_BUTTON ] ); DisableButton( iSMPanelButtons[ UPDOWN_BUTTON ] ); DisableButton( iSMPanelButtons[ CLIMB_BUTTON ] ); @@ -6982,6 +7240,11 @@ void DisableSMPpanelButtonsWhenInShopKeeperInterface( BOOLEAN fDontDrawButtons ) //ATM: //Go through the buttons that will be under the ShopKeepers ATM panel and disable them + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //ButtonList[ iSMPanelButtons[ HOP_BUTTON ] ]->uiFlags &= ~BUTTON_DIRTY; //Legion by Jazz + //} ButtonList[ iSMPanelButtons[ STANCEUP_BUTTON ] ]->uiFlags &= ~BUTTON_DIRTY; ButtonList[ iSMPanelButtons[ UPDOWN_BUTTON ] ]->uiFlags &= ~BUTTON_DIRTY; ButtonList[ iSMPanelButtons[ CLIMB_BUTTON ] ]->uiFlags &= ~BUTTON_DIRTY; @@ -7006,7 +7269,12 @@ void DisableSMPpanelButtonsWhenInShopKeeperInterface( BOOLEAN fDontDrawButtons ) //Make sure the mapscreen button is disabled ButtonList[ iSMPanelButtons[ SM_MAP_SCREEN_BUTTON ] ]->uiFlags &= ~BUTTON_ENABLED; - + + //DisableButton + //if (gGameExternalOptions.fCanJumpThroughWindows == TRUE) + //{ + //ButtonList[ iSMPanelButtons[ HOP_BUTTON ] ]->uiFlags |= BUTTON_FORCE_UNDIRTY; //legion by Jazz + //} ButtonList[ iSMPanelButtons[ STANCEUP_BUTTON ] ]->uiFlags |= BUTTON_FORCE_UNDIRTY; ButtonList[ iSMPanelButtons[ UPDOWN_BUTTON ] ]->uiFlags |= BUTTON_FORCE_UNDIRTY; ButtonList[ iSMPanelButtons[ CLIMB_BUTTON ] ]->uiFlags |= BUTTON_FORCE_UNDIRTY; @@ -7189,6 +7457,120 @@ void GoToMapScreenFromTactical( void ) gfEnteringMapScreen = TRUE; } +//-------------Legion by Jazz----------------------------------- +void BtnOknoCallback(GUI_BUTTON *btn,INT32 reason) +{ + INT8 bDirection; + + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + + if ( gpSMCurrentMerc->pathing.bLevel == 1 ) + { + return; + } + + + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + } + else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + if ( FindWindowJumpDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) ) + { + gpSMCurrentMerc->BeginSoldierClimbWindow( ); + } + + } + else if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + } + +} + +void BtnFenceCallback(GUI_BUTTON *btn,INT32 reason) +{ + BOOLEAN fNearHeigherLevelFence; + BOOLEAN fNearLowerLevelFence; + INT8 bDirection; + + if (!(btn->uiFlags & BUTTON_ENABLED)) + return; + + if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) + { + btn->uiFlags |= BUTTON_CLICKED_ON; + } + else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + + GetMercFenceDirection( gpSMCurrentMerc->ubID, &fNearLowerLevelFence, &fNearHeigherLevelFence ); + + + if ( FindFenceDirection( gpSMCurrentMerc, gpSMCurrentMerc->sGridNo, gpSMCurrentMerc->ubDirection, &bDirection ) ) + { + gpSMCurrentMerc->BeginSoldierFence( ); + } + + } + else if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE ) + { + btn->uiFlags &= (~BUTTON_CLICKED_ON ); + } + +} + +//----LEGION 2--------- +BOOLEAN HandleKlerykPistolet( SOLDIERTYPE *pSoldier, UINT32 uiHandPos, UINT16 usReplaceItem ) +{ + BOOLEAN fRefuse = FALSE; + + if ( pSoldier->ubProfile == 57 ) + { + if ( uiHandPos == HANDPOS || uiHandPos == SECONDHANDPOS ) + { + if ( usReplaceItem == NOTHING ) + { + fRefuse = TRUE; + } + else + { //legion + // Do we have nothing or the leather vest or kevlar leather vest? + if ( usReplaceItem == 4520 ) //zoty pistolet items.xml + { + // This is good.... + fRefuse = FALSE; + } + else + { + fRefuse = TRUE; + } + } + + if ( fRefuse ) + { + // Say quote! + TacticalCharacterDialogue( pSoldier, 85 ); + return( TRUE ); + } + } + } + + return( FALSE ); +} + + +//----------- + + +//--------------------------------------------- + // Moved to Weapons.cpp by ADB, rev 1513 /*void HandleTacticalEffectsOfEquipmentChange( SOLDIERTYPE *pSoldier, UINT32 uiInvPos, UINT16 usOldItem, UINT16 usNewItem ) diff --git a/Tactical/Interface Panels.h b/Tactical/Interface Panels.h index bb0de3bc..7e98e1de 100644 --- a/Tactical/Interface Panels.h +++ b/Tactical/Interface Panels.h @@ -18,6 +18,7 @@ typedef enum MUTE_BUTTON, SM_DONE_BUTTON, SM_MAP_SCREEN_BUTTON, + //HOP_BUTTON, //Legion by Jazz NUM_SM_BUTTONS }; @@ -47,6 +48,7 @@ extern int INTERFACE_CLOCK_Y; extern int LOCATION_NAME_X; extern int LOCATION_NAME_Y; + BOOLEAN CreateSMPanelButtons( ); void RemoveSMPanelButtons( ); BOOLEAN InitializeSMPanel( ); @@ -155,4 +157,13 @@ UINT8 FindNextMercInTeamPanel( SOLDIERTYPE *pSoldier, BOOLEAN fGoodForLessOKLife // CHRISL: New callback functions for backpack buttons BOOLEAN ChangeDropPackStatus(SOLDIERTYPE *pSoldier, BOOLEAN newStatus); +// HEADROCK HAM 4: This variable tells the program what "page" of the description box we are currently looking at. +// By saving this in memory, we tell the DescBox which background and values to draw, and make sure that we end up +// on the same page every time we open the description box. UDB buttons allow switching between pages. +extern UINT8 gubDescBoxPage; +// Record which line we're looking at. This only applied to the Advanced tab in description boxes. +extern UINT8 gubDescBoxLine; +// Record how many lines there are for the current item in the Advanced tab. +extern UINT8 gubDescBoxTotalAdvLines; + #endif \ No newline at end of file diff --git a/Tactical/Interface Utils.cpp b/Tactical/Interface Utils.cpp index 16c9447d..fe75ee35 100644 --- a/Tactical/Interface Utils.cpp +++ b/Tactical/Interface Utils.cpp @@ -362,7 +362,7 @@ void DrawItemUIBarEx( OBJECTTYPE *pObject, UINT8 ubStatus, INT16 sXPos, INT16 sY { sValue = 0; OBJECTTYPE* pAttachment = (*pObject)[iter]->GetAttachmentAtIndex( ubStatus - DRAW_ITEM_STATUS_ATTACHMENT1 ); - if (pAttachment) { + if (pAttachment->exists()) { sValue = (*pAttachment)[iter]->data.objectStatus; } } diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index ffda5003..b5cc6988 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -56,6 +56,10 @@ #include "gamesettings.h" #include "Squads.h" #include "message.h" + #include "strategicmap.h" + #include "Queen Command.h" + // HEADROCK HAM 4: Included for new CTH indicator + #include "weapons.h" #endif @@ -83,6 +87,10 @@ int INV_INTERFACE_START_Y;// = ( SCREEN_HEIGHT - INV_INTERFACE_HEIGHT ); #define BUTTON_PANEL_WIDTH 78 #define BUTTON_PANEL_HEIGHT 76 +HIDDEN_NAMES_VALUES zHiddenNames[500]; //legion2 Jazz +ENEMY_NAMES_VALUES zEnemyName[500]; +ENEMY_RANK_VALUES zEnemyRank[500]; +CIV_NAMES_VALUES zCivGroupName[NUM_CIV_GROUPS]; BOOLEAN gfInMovementMenu = FALSE; INT32 giMenuAnchorX, giMenuAnchorY; @@ -90,7 +98,15 @@ INT32 giMenuAnchorX, giMenuAnchorY; #define PROG_BAR_START_X 5 -#define PROG_BAR_START_Y 2 +//*ddd +//#define PROG_BAR_START_Y 2 + +//**ddd{ +// 0 +//#define fSmallSizeProgressbar 1 +INT32 HEIGHT_PROGRESSBAR, PROG_BAR_START_Y; +//ddd} + BOOLEAN gfProgBarActive = FALSE; UINT8 gubProgNumEnemies = 0; @@ -99,6 +115,8 @@ UINT8 gubProgCurEnemy = 0; UINT32 guiPORTRAITICONS; +UINT32 guiPORTRAITICONS_NV; //legion +UINT32 guiPORTRAITICONS_GAS_MASK; //legion typedef struct { @@ -189,32 +207,6 @@ typedef enum INT32 iIconImages[ NUM_ICON_IMAGES ]; -typedef enum -{ - WALK_ICON, - SNEAK_ICON, - RUN_ICON, - CRAWL_ICON, - LOOK_ICON, - ACTIONC_ICON, - TALK_ICON, - HAND_ICON, - - OPEN_DOOR_ICON, - EXAMINE_DOOR_ICON, - LOCKPICK_DOOR_ICON, - BOOT_DOOR_ICON, - UNTRAP_DOOR_ICON, - USE_KEY_ICON, - USE_KEYRING_ICON, - EXPLOSIVE_DOOR_ICON, - USE_CROWBAR_ICON, - - CANCEL_ICON, - NUM_ICONS -}; - - INT32 iActionIcons[ NUM_ICONS ]; // GLOBAL INTERFACE SURFACES @@ -249,6 +241,13 @@ UINT16 gsDownArrowY; UINT32 giUpArrowRect; UINT32 giDownArrowRect; +// HEADROCK HAM 4: Rectangles for the various CTH displays. +RECT MagRect; +RECT AimRect; +RECT ModeRect; +RECT APRect; +// HEADROCK HAM 4: Externed this value which tracks whether we've clicked out final aiming click yet. +extern BOOLEAN gfDisplayFullCountRing; void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sWidth, INT16 sHeight ); void PopupDoorOpenMenu( BOOLEAN fClosingDoor ); @@ -289,6 +288,18 @@ BOOLEAN InitializeTacticalInterface( ) InitializeSMPanelCoordsOld(); } +//*ddd{ + if( gGameExternalOptions.fSmallSizeProgressbar ) + { + HEIGHT_PROGRESSBAR = 7; + PROG_BAR_START_Y = 0; + } + else{ + HEIGHT_PROGRESSBAR = 20; + PROG_BAR_START_Y = 2; + } +//*ddd} + /* OK i need to initialize coords here * Isnt it cool * any questions? joker @@ -360,7 +371,7 @@ BOOLEAN InitializeTacticalInterface( ) if( !AddVideoObject( &VObjectDesc, &guiHATCH ) ) AssertMsg(0, "Missing INTERFACE\\hatch.sti" ); - THROWIFFALSE( RegisterItemImages(), L"Registering Item Images failed" ); + SGP_THROW_IFFALSE( RegisterItemImages(), L"Registering Item Images failed" ); // CHRISL: // LOAD INTERFACE POCKET SILHOUETTES @@ -401,18 +412,67 @@ BOOLEAN InitializeTacticalInterface( ) VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; - FilenameForBPP("INTERFACE\\portraiticons.sti", VObjectDesc.ImageFile); - if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) - AssertMsg(0, "Missing INTERFACE\\portraiticons.sti" ); + + //legion 2 jazz + if (gGameExternalOptions.fShowTacticalFaceIcons == TRUE) + { + //additional face icons (legion 2) + if (gGameExternalOptions.bTacticalFaceIconStyle == 0) + { + FilenameForBPP("INTERFACE\\portraiticons_a.sti", VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons_a.sti" ); + } + else if (gGameExternalOptions.bTacticalFaceIconStyle == 1) + { + FilenameForBPP("INTERFACE\\portraiticons_b.sti", VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons_b.sti" ); + } + else if (gGameExternalOptions.bTacticalFaceIconStyle == 2) + { + FilenameForBPP("INTERFACE\\portraiticons_c.sti", VObjectDesc.ImageFile); + + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons_c.sti" ); + } + else if (gGameExternalOptions.bTacticalFaceIconStyle == 3) + { + FilenameForBPP("INTERFACE\\portraiticons_d.sti", VObjectDesc.ImageFile); + + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons_d.sti" ); + } + } + else + { + // JA2 classic face icons + FilenameForBPP("INTERFACE\\portraiticons.sti", VObjectDesc.ImageFile); + + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons.sti" ); + } + + + //legion + if (gGameExternalOptions.fShowTacticalFaceGear == TRUE) + { + FilenameForBPP("INTERFACE\\portraiticons_NV.sti", VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS_NV ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons_NV.sti" ); + + FilenameForBPP("INTERFACE\\portraiticons_GAS_MASK.sti", VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS_GAS_MASK ) ) + AssertMsg(0, "Missing INTERFACE\\portraiticons_GAS_MASK.sti" ); + } // LOAD RADIO VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\radio.sti", VObjectDesc.ImageFile); - if( !AddVideoObject( &VObjectDesc, &guiRADIO ) ) - // AssertMsg(0, "Missing INTERFACE\\bracket.sti" ); + if( !AddVideoObject( &VObjectDesc, &guiRADIO ) ) AssertMsg(0, "Missing INTERFACE\\radio.sti" ); // LOAD RADIO2 @@ -1463,6 +1523,40 @@ void GetSoldierAboveGuyPositions( SOLDIERTYPE *pSoldier, INT16 *psX, INT16 *psY, } } +void DrawCTHPixelToBuffer( UINT16 *pBuffer, UINT32 uiPitch, INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom, INT16 sPixelX, INT16 sPixelY, UINT16 usColor ) +{ + /////////////////////////////////////////////////////////// + // HEADROCK HAM 4: + // + // This is a specialized drawing function that's used for the CTH indicator. It makes sure that the + // pixel is drawn only within the allowed region (the Tactical Viewport), and never drawn in regions + // reserved for other parts of the CTH indicator. + + if (sPixelX < sLeft || sPixelX > sRight || sPixelY < sTop || sPixelY > (sBottom-1)) + { + return; + } + // Do not draw in other CTH rects! + if ((sPixelX >= MagRect.left && sPixelX <= MagRect.right) && (sPixelY >= MagRect.top && sPixelY <= MagRect.bottom)) + { + return; + } + if ((sPixelX >= AimRect.left && sPixelX <= AimRect.right) && (sPixelY >= AimRect.top && sPixelY <= AimRect.bottom)) + { + return; + } + if ((sPixelX >= ModeRect.left && sPixelX <= ModeRect.right) && (sPixelY >= ModeRect.top && sPixelY <= ModeRect.bottom)) + { + return; + } + if ((sPixelX >= APRect.left && sPixelX <= APRect.right) && (sPixelY >= APRect.top && sPixelY <= APRect.bottom)) + { + return; + } + + + pBuffer[sPixelX + uiPitch*sPixelY] = usColor; +} //QUOTE_SYSTEM_STRUCT soldierTTInfo; @@ -1474,10 +1568,12 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) INT32 iBack; TILE_ELEMENT TileElem; CHAR16 *pStr; + //CHAR16 *pStr2; CHAR16 NameStr[ 50 ]; UINT16 usGraphicToUse = THIRDPOINTERS1; BOOLEAN fRaiseName = FALSE; BOOLEAN fDoName = TRUE; + UINT16 iCounter2; GetSoldier( &pSoldier, usSoldierID ); @@ -1692,21 +1788,84 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) { if ( fRaiseName ) { - swprintf( NameStr, L"%s", pSoldier->name ); + + + //legion2 jazz + if (pSoldier->ubBodyType == ROBOTNOWEAPON && pSoldier->bTeam == ENEMY_TEAM ) + { + swprintf( NameStr, zGrod[0] ); + } + else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) + { + swprintf( NameStr,L"???" ); + } + else + { + swprintf( NameStr, L"%s", pSoldier->name ); + } + + //Legion + if (pSoldier->ubBodyType == TANK_NE || pSoldier->ubBodyType == TANK_NW) + { + swprintf( NameStr, pVehicleStrings[4] ); + } + else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) + { + swprintf( NameStr,L"???" ); + } + else + { + swprintf( NameStr, L"%s", pSoldier->name ); + } + //------- + + //swprintf( NameStr, L"%s", pSoldier->name ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos - 10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); } else { + + //legion Jazz + if (pSoldier->ubBodyType == ROBOTNOWEAPON && pSoldier->bTeam == ENEMY_TEAM ) + { + swprintf( NameStr, zGrod[0] ); + } + else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) + { + swprintf( NameStr,L"???" ); + } + else + { swprintf( NameStr, L"%s", pSoldier->name ); + } + + //Legion + if (pSoldier->ubBodyType == TANK_NE || pSoldier->ubBodyType == TANK_NW) + { + swprintf( NameStr, pVehicleStrings[4] ); + } + else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) + { + swprintf( NameStr,L"???" ); + } + else + { + swprintf( NameStr, L"%s", pSoldier->name ); + } + //--------------- + + //swprintf( NameStr, L"%s", pSoldier->name ); FindFontCenterCoordinates( sXPos, sYPos, (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); } } - if ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON || RPC_RECRUITED( pSoldier ) || AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) +// if ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON || RPC_RECRUITED( pSoldier ) || AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) + //new profiles by Jazz + if ( gProfilesIMP[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesAIM[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesMERC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || RPC_RECRUITED( pSoldier ) || AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )) { // Adjust for bars! @@ -1769,6 +1928,88 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 10 ), (INT16)(80 ), 1, pStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, pStr ); mprintf( sX, sY, pStr ); + + //----------------- + if (gGameExternalOptions.fEnemyNames == TRUE && gGameExternalOptions.fEnemyRank == FALSE) + { + for( iCounter2 = 0; iCounter2 < 500; iCounter2++ ) + { + if (zEnemyName[iCounter2].Enabled == 1) + { + + if ((gWorldSectorX == zEnemyName[iCounter2].SectorX && gWorldSectorY == zEnemyName[iCounter2].SectorY )) + { + if (NumEnemiesInSector( zEnemyName[iCounter2].SectorX , zEnemyName[iCounter2].SectorY ) && pSoldier->ubProfile == NO_PROFILE && pSoldier->bTeam == 1 ) + { + + swprintf(NameStr, zEnemyName[iCounter2].szCurGroup); + + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); + + //legion2 + FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); + gprintfdirty( sX, sY, NameStr ); + mprintf( sX, sY, NameStr ); + + } + } + } + } + } + + if (gGameExternalOptions.fEnemyNames == FALSE && gGameExternalOptions.fEnemyRank == TRUE) + { + for( iCounter2 = 1; iCounter2 < 13; iCounter2++ ) + { + if (zEnemyRank[iCounter2].Enabled == 1) + { + + if ( zEnemyRank[iCounter2].Stats == 0 && zEnemyRank[iCounter2].ExpLevel > 0 && pSoldier->ubProfile == NO_PROFILE && pSoldier->bTeam == 1 && pSoldier->stats.bExpLevel == zEnemyRank[iCounter2].ExpLevel ) + { + + swprintf(NameStr, zEnemyRank[iCounter2].szCurRank); + + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); + + //legion2 + FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); + gprintfdirty( sX, sY, NameStr ); + mprintf( sX, sY, NameStr ); + } + } + } + + } + + + if (gGameExternalOptions.fCivGroupName == TRUE) + { + for( iCounter2 = 1; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if (zCivGroupName[iCounter2].Enabled == 1) + { + if (pSoldier->ubProfile == NO_PROFILE && pSoldier->ubCivilianGroup == iCounter2 ) + { + + swprintf(NameStr, zCivGroupName[iCounter2].szCurGroup); + + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); + + //legion2 + FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); + gprintfdirty( sX, sY, NameStr ); + mprintf( sX, sY, NameStr ); + } + } + } + } + //------------ } } } @@ -1802,10 +2043,886 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) FindFontCenterCoordinates( sXPos, sYPos, (INT16)(80 ), 1, pStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, pStr ); mprintf( sX, sY, pStr ); + + //----------------- + if (gGameExternalOptions.fEnemyNames == TRUE && gGameExternalOptions.fEnemyRank == FALSE) + { + for( iCounter2 = 0; iCounter2 < 500; iCounter2++ ) + { + if (zEnemyName[iCounter2].Enabled == 1 ) + { + + if ((gWorldSectorX == zEnemyName[iCounter2].SectorX && gWorldSectorY == zEnemyName[iCounter2].SectorY )) + { + if (NumEnemiesInSector( zEnemyName[iCounter2].SectorX , zEnemyName[iCounter2].SectorY ) && pSoldier->ubProfile == NO_PROFILE && pSoldier->bTeam == 1 ) + { + + swprintf(NameStr, zEnemyName[iCounter2].szCurGroup); + + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); + + //legion2 + FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); + gprintfdirty( sX, sY, NameStr ); + mprintf( sX, sY, NameStr ); + + } + } + } + } + } + + if (gGameExternalOptions.fEnemyNames == FALSE && gGameExternalOptions.fEnemyRank == TRUE) + { + for( iCounter2 = 1; iCounter2 < 13; iCounter2++ ) + { + if (zEnemyRank[iCounter2].Enabled == 1) + { + + if ( zEnemyRank[iCounter2].Stats == 0 && zEnemyRank[iCounter2].ExpLevel > 0 && pSoldier->ubProfile == NO_PROFILE && pSoldier->bTeam == 1 && pSoldier->stats.bExpLevel == zEnemyRank[iCounter2].ExpLevel ) + { + + swprintf(NameStr, zEnemyRank[iCounter2].szCurRank); + + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); + + //legion2 + FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); + gprintfdirty( sX, sY, NameStr ); + mprintf( sX, sY, NameStr ); + } + } + } + + } + + if (gGameExternalOptions.fCivGroupName == TRUE) + { + for( iCounter2 = 1; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if (zCivGroupName[iCounter2].Enabled == 1) + { + + if (pSoldier->ubProfile == NO_PROFILE && pSoldier->ubCivilianGroup == iCounter2 ) + { + swprintf(NameStr, zCivGroupName[iCounter2].szCurGroup); + + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_YELLOW ); + + //legion2 + FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); + gprintfdirty( sX, sY, NameStr ); + mprintf( sX, sY, NameStr ); + } + } + } + } + //------------ } } +BOOLEAN DrawCTHIndicator() +{ + //////////////////////////////////////////// + // HEADROCK HAM 4: NCTH Indicator + // + // The NCTH shooting system is radically different from the old CTH, and as a result it requires a completely + // new indicator to show hit-probability. The "Hit Percentage" bar we've all gotten used to in JA2 1.13 is not + // doable in NCTH since the hit probability is unknown before the bullet reaches the target distance. Instead, + // we use a sort of "reticle" to show the margin of error for our current shot. + // + // The CTH indicator is made up of several parts: + // 1. Outer Circle: This circle shows the margin of error that we would have if Muzzle Accuracy was 0%. In other + // words, it indicates the "worst" possible shot with the gun we're holding, given the target's distance. + // This circle only gets larger or smaller if the shooter moves closer or further from the target (or + // changes weapons...). + // 2. Inner Circle+Crosshairs: This indicator shows the margin of error for the shot given all the bonuses from + // Base CTH and extra aiming clicks. It is a visual representation of where our bullet may end up once fired. + // The bullet can end up anywhere within this smaller circle. The circle gets larger or smaller as we change + // the number of applied aiming clicks, add magnification bonuses from a scope, change stance, etcetera. + // 3. Additional indicators: These are floating graphical and numerical indicators showing various important + // data, such as how many aiming clicks we've applied (and how many we can apply), how many bullets we're + // going to fire (in burst/auto mode), and how many APs it's going to cost us. These are generally just + // relocation and redesign of existing indicators on the OCTH cursor. + if (gCTHDisplay.MuzzleSwayPercentage < 0 || gCTHDisplay.MuzzleSwayPercentage > 99 || gCTHDisplay.FinalMagFactor < 1.0) + { + // Obviously Uninitialized. + return 0; + } + + INT32 iBack; + + // Find the shooter. + SOLDIERTYPE *pSoldier; + GetSoldier( &pSoldier, gusSelectedSoldier ); + + // Create a Background Rect for us to draw our indicator on. With NCTH, the size and position of this rectangle + // is equal exactly to the size of the tactical screen viewport. Unlike the OCTH indicator, the NCTH one can grow + // so large as to fill the entire screen. + INT16 sLeft = gsVIEWPORT_START_X; + INT16 sTop = gsVIEWPORT_WINDOW_START_Y; + INT16 sRight = gsVIEWPORT_END_X; + INT16 sBottom = gsVIEWPORT_WINDOW_END_Y; + + iBack = RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sLeft, sTop, sRight, sBottom); + + if ( iBack != -1 ) + { + SetBackgroundRectFilled( iBack ); + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: New CTH, Aperture Size + // + // As explained above, the most important part of the new indicator is the Aperture circle/crosshairs. + // These indicate the size of the "margin of error" for our current shot. The more accurate we are, + // the smaller the circle will be. + // + // The player uses this to determine whether the shot has a good likelyhood to hit the target. + // If the circle is the same size or smaller than the target itself, then hit probability is 100%. + // The larger it gets, the less hit probability there will be. When adding extra aiming clicks, + // the circle gets proportionally smaller. The idea is to try to make it as small as the target + // (if possible) to ensure a hit. + // + // Shot aperture is calculated using the CTH formula (CalcChanceToHitGun). Scopes and lasers + // can help decrease the size of the aperture further. + ///////////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////// + // Define colors + UINT8 ColorsRed[10] = { 255, 255, 255, 255, 255, 255, 255, 255, 173, 0 }; + UINT8 ColorsGreen[10] = { 0, 50, 81, 101, 133, 174, 211, 243, 255, 255 }; + + // Select the color of the indicator circles + UINT16 usCApertureBar; + if (pSoldier->bDoAutofire && fAutofireBulletsMode) + { + // When autofire bullets mode is selected, the CTH display goes greyish. This indicates to the player + // that the aiming levels have been set, and further right-clicks will only add bullets to the volley. + usCApertureBar = Get16BPPColor( FROMRGB( 180, 180, 180 ) ); + } + else + { + // Indicator changes color from red to yellow to green, based on how well the gun is aimed. + usCApertureBar = Get16BPPColor( FROMRGB( ColorsRed[gCTHDisplay.MuzzleSwayPercentage/10], ColorsGreen[gCTHDisplay.MuzzleSwayPercentage/10], 0 ) ); // Crosshair color shifts from red (longshot) to green (Accurate shot) + } + + UINT16 usCApertureBorder = Get16BPPColor( FROMRGB( 10, 10, 10 ) ); // Boundaries in dark color. + + ////////////////////////////////// + // Calculate Aperture + + // Calculate the center point of the shooter, in world coordinates. + FLOAT dStartX = (FLOAT) CenterX( gCTHDisplay.iShooterGridNo ); + FLOAT dStartY = (FLOAT) CenterY( gCTHDisplay.iShooterGridNo ); + + // Calculate the center point of the target, in world coordinates. + FLOAT dEndX = (FLOAT) CenterX( gCTHDisplay.iTargetGridNo ); + FLOAT dEndY = (FLOAT) CenterY( gCTHDisplay.iTargetGridNo ); + + // Calculate a delta: the difference between the shooter and target. + FLOAT dDeltaX = dEndX - dStartX; + FLOAT dDeltaY = dEndY - dStartY; + + // Calculate the distance of the shot, using Pythagorean Theorem + DOUBLE d2DDistance = sqrt( (DOUBLE) (dDeltaX * dDeltaX + dDeltaY * dDeltaY )); + // Round it upwards. + INT32 iDistance = (INT32) d2DDistance; + if ( d2DDistance != iDistance ) + { + iDistance += 1; + d2DDistance = (FLOAT) ( iDistance); + } + + // Calculate the Distance Ratio. This will increase or decrease the size of the Shooting Aperture based + // on both distance and Magnification Factor. + FLOAT iDistanceRatio = (FLOAT)(d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + FLOAT iFinalRatio = iDistanceRatio / gCTHDisplay.FinalMagFactor; + + /////////////////////////////////////////////////////////// + // Now we calculate the Aperture size. This is done using the same method as the shooting formula uses. + + // Calculate the maximum angle of any shot. + DOUBLE ddMaxAngleRadians = (gGameCTHConstants.DEGREES_MAXIMUM_APERTURE * 6.283) / 360; + + // Calculate the size of a "normal" aperture. This is how wide a shot can go at 1x Normal Distance. + FLOAT iBasicAperture = (FLOAT)((sin(ddMaxAngleRadians) * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE) * 2); // The *2 compensates for the difference between CellXY and ScreenXY + + // Calculate the Maximum Aperture. This is the margin of error for the "worst" shot we can have given the + // target's actual distance. This will later be used to draw the Outer Circle around the target. + FLOAT iMaxAperture = iBasicAperture * iDistanceRatio; + + // Calculate the aperture for our shot by applying both distance and scope magnification (which work against each + // other) to the size of a normal aperture. + FLOAT iAperture = iBasicAperture * iFinalRatio; + + // Apply CTH to the aperture to find out how much smaller it's become thanks to skills and extra aiming. + UINT8 actualPct = __min(gCTHDisplay.MuzzleSwayPercentage,99); + iAperture = ((100 - actualPct) * iAperture) / 100; + + ///////////////////////////////////////////// + // Factor in Gun Accuracy. Note that I may remove this at a later time. + + INT16 sAccuracy = GetGunAccuracy( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ); + + sAccuracy = __max(0, sAccuracy); + sAccuracy = __min(100, sAccuracy); + + FLOAT iBulletDev = (gGameCTHConstants.MAX_BULLET_DEV * (100-sAccuracy)) / 100; + iBulletDev *= iDistanceRatio; + + // Since bullet dev is only affected by distance, we add it last as a flat modifier. + iBasicAperture += iBulletDev; + iMaxAperture += iBulletDev; + iAperture += iBulletDev; + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Calculate Screen Positions + // + // Aperture Size has to be translated into on-screen size. We also want to track the position of the + // mouse so that our indicator moves with it like a cursor. + + // Z Offset is used to move the indicator up or down. It's currently set to 0 since it's not required ATM. + FLOAT zOffset = 0; + + // Calculate the position of the mouse cursor and store it. + INT16 sStartScreenX; + INT16 sStartScreenY; + + POINT MousePos; + GetCursorPos(&MousePos); + ScreenToClient(ghWindow, &MousePos); // In window coords! + + sStartScreenX = (INT16)MousePos.x; + sStartScreenY = (INT16)MousePos.y; + + // Define regions for the various indicators. We need to do this now because the Aperture Circles will want to + // avoid being drawn within these regions, otherwise they might make them harder to see. + + MagRect.left = sStartScreenX-50; MagRect.top = sStartScreenY-15; MagRect.right = sStartScreenX-20; MagRect.bottom = sStartScreenY-5; + APRect.left = sStartScreenX+22; APRect.top = sStartScreenY-15; APRect.right = sStartScreenX+52; APRect.bottom = sStartScreenY-5; + AimRect.left = sStartScreenX-35; AimRect.top = sStartScreenY+22; AimRect.right = sStartScreenX+35; AimRect.bottom = sStartScreenY+30; + ModeRect.left = sStartScreenX-28; ModeRect.top = sStartScreenY+31; ModeRect.right = sStartScreenX+28; ModeRect.bottom = sStartScreenY+41; + + //////////////////////////////////////////////////////////////////////////////////////// + // DRAW ADDITIONAL COMPONENTS: + // + // We now draw additional indicators on top of the circles. There are four indicators: + // + // 1. AP Cost: The current AP cost for the shot has been moved from the center of the + // targeting cursor to avoid obscuring the meeting point of the aperture crosshairs. + // It is now displayed in the top right, together with the word "AP". + // 2. MAG Factor: The current Magnification or Projection factor for the shot is displayed + // in the top-left, followed by an "x". Its color indicates whether we are using the + // full potential of our aiming device. + // 3. Aiming Pips: The circles on the old indicator shows how many aiming clicks we've + // placed into the shot. Now that the circles are used to indicate shot probability, + // the aiming clicks are displayed with a series of pips below the targeting cursor + // which fill up as we add levels. + // 4. Bullet Count: This indicator, now below the Aiming Pips indicator, shows the number + // of bullets queues up for a Burst/Autofire volley. For autofire, it starts out by + // displaying grey bullets showing how many we CAN add, then fills up with colored + // bullets as we add them to the volley. A "+" sign is added if space for bullets runs out. + + CHAR16 pStr[10]; + + INT16 curX = 0; + INT16 curY = 0; + + ///////////////////////////////////////// + // Load image STI + UINT32 guiCTHImage; + VOBJECT_DESC VObjectDesc; + + VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; + if(UsingNewCTHSystem() == true) + FilenameForBPP("CURSORS\\CUR_CTH_NCTH.sti", VObjectDesc.ImageFile); + else + FilenameForBPP("CURSORS\\CUR_CTH.sti", VObjectDesc.ImageFile); + CHECKF(AddVideoObject(&VObjectDesc, &guiCTHImage)); + + /////////////// AP COST FOR CURRENT SHOT + { + // Create a pointer to the Frame Buffer which we are going to draw directly into. + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_MCOLOR_WHITE ); + + // Find coordinates, using the full string ("XX AP") + swprintf( pStr, L"%d %s", gsCurrentActionPoints, gzNCTHlabels[ 1 ] ); + FindFontCenterCoordinates( (INT16)APRect.left, (INT16)APRect.top, (INT16)APRect.right-(INT16)APRect.left, 10, pStr, TINYFONT1, &curX, &curY); + // Find width of this string. + UINT16 usTotalWidth = StringPixLength ( pStr, TINYFONT1 ); + + // Cut string to just the number of APs + swprintf( pStr, L"%d", gsCurrentActionPoints ); + // Find out how wide this string is + UINT16 usWidth = StringPixLength( pStr, TINYFONT1 ); + // Draw to screen + gprintfdirty( curX, curY, pStr ); + mprintf( curX, curY, pStr); + + // Draw the "AP" label 4 pixels forward. + SetFontForeground(FONT_MCOLOR_LTYELLOW); + swprintf( pStr, L"%s", gzNCTHlabels[ 1 ] ); + curX += usWidth + 4; + gprintfdirty( curX, curY, pStr ); + mprintf( curX, curY, pStr); + + // Redefine area size based on total width plus a margin of 2 pixels. + usTotalWidth = usTotalWidth + 6; + INT16 sCenter = (INT16)((APRect.right + APRect.left) / 2); + APRect.left = sCenter - (usTotalWidth / 2); + APRect.right = sCenter + (usTotalWidth / 2); + } + + /////////////// MAG FACTOR + { + SetFont( TINYFONT1 ); + + // Find coordinates, using full string ("X.X x") + swprintf( pStr, L"%1.1f x", gCTHDisplay.FinalMagFactor ); + FindFontCenterCoordinates( (INT16)MagRect.left, (INT16)MagRect.top, (INT16)MagRect.right-(INT16)MagRect.left, 10, pStr, TINYFONT1, &curX, &curY); + // Find width of this string. + UINT16 usTotalWidth = StringPixLength ( pStr, TINYFONT1 ); + + // Cut string to just the float + swprintf( pStr, L"%1.1f", gCTHDisplay.FinalMagFactor ); + // Record the width of the float + UINT16 usWidth = StringPixLength( pStr, TINYFONT1 ); + + //////////////////////////// + // We change the color of this indicator based on whether or not our optical devices are working + // at full potential. Remember that scopes below their best range give out penalties! + + // If using a scope below its optimal range... + if (gCTHDisplay.ScopeMagFactor > 1.0 && gCTHDisplay.ScopeMagFactor > gCTHDisplay.FinalMagFactor) + { + // If within projection range... + if (gCTHDisplay.ProjectionFactor > 1.0 && gCTHDisplay.ProjectionFactor >= iDistanceRatio ) + { + SetFontForeground( FONT_ORANGE ); + } + // If only using a scope... + else + { + SetRGBFontForeground( 255, 150, 150 ); // Bright Pink + } + } + // If using a scope above its range, or a laser below its range + else if ((gCTHDisplay.ScopeMagFactor > 1.0 && gCTHDisplay.ScopeMagFactor <= iDistanceRatio) || + (gCTHDisplay.ProjectionFactor > 1.0 && gCTHDisplay.ProjectionFactor >= iDistanceRatio) ) + { + SetRGBFontForeground( 100,255,100 ); // True Light Green + } + // In all other circumstances... + else + { + SetFontForeground( FONT_MCOLOR_WHITE ); + } + + // Print the float + gprintfdirty( curX, curY, pStr ); + mprintf( curX, curY, pStr); + + // Add an "x" 4 pixels forward. + SetFontForeground( FONT_MCOLOR_LTYELLOW ); + swprintf( pStr, L"x" ); + curX += usWidth + 4; + gprintfdirty( curX, curY, pStr ); + mprintf( curX, curY, pStr); + + // Redefine area size based on total width plus a margin of 2 pixels. + usTotalWidth = usTotalWidth + 6; + INT16 sCenter = (INT16)((MagRect.right + MagRect.left) / 2); + MagRect.left = sCenter - (usTotalWidth / 2); + MagRect.right = sCenter + (usTotalWidth / 2); + } + + //////////////////// BURST/AUTO LABEL AND BULLETS + if (pSoldier->bDoBurst) + { + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_MCOLOR_WHITE ); + + //////////////////////////////////////////////////////////////////////////////// + // We need to calculate how many bullets to display, and how much space they + // take, so that we can center them horizontally on the CTH indicator. + // This works slightly differently for Autofire and Burst. + + UINT8 ubNumBullets = 0; + UINT8 ubBulletWidth = 4; + UINT8 ubTotalWidth = 0; + UINT32 uiMaxAutofire = 0; + UINT32 uiMaxBulletsToDisplay = 0; + UINT32 uiSpacesToDisplay = 0; + + if (pSoldier->bDoAutofire) + { + // Number of COLORED bullets to display is the number of bullets we want to fire. + ubNumBullets = pSoldier->bDoAutofire; + + // How many bullets are left in the gun? + UINT32 uiBulletsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + + UINT32 uiCurBullet = uiBulletsLeft; + while( uiCurBullet > 0 ) + { + // We work backwards from the total number of bullets left, to find out the number of bullets + // that can be fired given the current number of APs left. + + // Store Soldier Autofire variable into a temp. We do this to fool the AP Calculation formula. + UINT8 TempDoAutofire = pSoldier->bDoAutofire; + pSoldier->bDoAutofire = uiCurBullet; + + //Get AP cost to fire this many bullets + INT16 sAPCosts = CalcTotalAPsToAttack( pSoldier, gCTHDisplay.iTargetGridNo, TRUE, pSoldier->aiData.bShownAimTime); + + // Switch back. + pSoldier->bDoAutofire = TempDoAutofire; + + // Have we reached a number of bullets that can be fired with the current APs? + if( !uiMaxAutofire && EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + // Set it. + uiMaxAutofire = uiCurBullet; + } + + //Decrement until zero. + uiCurBullet--; + } + + // Display no more than X bullets on screen! + uiMaxBulletsToDisplay = __min(uiMaxAutofire, 15); + + // Calculate how many spaces to display. Currently, a space is displayed after every 5 bullets. + uiSpacesToDisplay = (uiMaxBulletsToDisplay-1) / 5; + + // Calculate the total width of this display in pixels. Spaces and bullets have the same width. + ubTotalWidth = ubBulletWidth * (uiMaxBulletsToDisplay + uiSpacesToDisplay); + } + else + { + // Number of COLORED bullets to display is the number of bullets we want to fire. + ubNumBullets = GetShotsPerBurst( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ); + + // Display no more than X bullets on screen! + uiMaxBulletsToDisplay = __min(ubNumBullets, 15); + + // Calculate how many spaces to display. Currently, a space is displayed after every 5 bullets. + uiSpacesToDisplay = (uiMaxBulletsToDisplay-1) / 5; + + // Calculate the total width of this display in pixels. Spaces and bullets have the same width. + ubTotalWidth = ubBulletWidth * (uiMaxBulletsToDisplay + uiSpacesToDisplay); + } + + // Tracks the number of spaces we've drawn on screen so far. + UINT16 usNumSpacesShown = 0; + + // AUTO FIRE + if (pSoldier->bDoAutofire) + { + // Draw greyed-out bullets, indicating how many bullets CAN be added to the volley given our + // current remaining APs. + for (UINT8 x = 0; x < (uiMaxBulletsToDisplay); x++) + { + // Find starting point for drawing + INT16 sLeft = (((INT16)ModeRect.left + (INT16)ModeRect.right)/2) - (ubTotalWidth/2); + INT16 sTop = (INT16)ModeRect.top; + + // If we've drawn 5,10,15,etc. bullets, add a space. + if (x > 0 && x%5 == 0) + { + usNumSpacesShown++; + } + + // Offset adds up the number of bullets and spaces we've already drawn. + INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); + + // Draw a bullet here! + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 8, sLeft + sCurOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + + // If the number of bullets that can be fired is greater than the number of bullets we can display, + // and we've just now drawn the last displayable bullet, then... + if (x == uiMaxBulletsToDisplay-1 && uiMaxBulletsToDisplay < uiMaxAutofire) + { + // Draw a shaded plus sign at the end. + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 9, sLeft + sCurOffset + ubBulletWidth, sTop+2, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + + // Draw colored bullets. These show how many bullets we've set to fire with the current volley. + usNumSpacesShown = 0; + for (UINT8 x = 0; x < ubNumBullets; x++) + { + // Set start point for drawing + INT16 sLeft = (((INT16)ModeRect.left + (INT16)ModeRect.right)/2) - (ubTotalWidth/2); + INT16 sTop = (INT16)ModeRect.top; + + // Calculate offset based on the number of bullets and spaces already drawn. + INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); + + // If we're drawing more bullets than can be displayed on-screen... + if (x == uiMaxBulletsToDisplay) + { + // Draw a colored plus sign at the end. + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 10, sLeft + sCurOffset, sTop+2, VO_BLT_SRCTRANSPARENCY, NULL ); + // Set x to NumBullets to end the loop + x = ubNumBullets; + } + else + { + // If we've drawn 5,10,15,etc. bullets, increase the number of spaces drawn. + if (x > 0 && x%5 == 0) + { + usNumSpacesShown++; + } + // Recalculate offset to take any new spaces into account. + INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); + // Draw a colored bullet here. + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 7, sLeft + sCurOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + + // Redefine area size based on total width plus a margin of 2 pixels. + ubTotalWidth = ubTotalWidth + 6; + INT16 sCenter = (INT16)((ModeRect.right + ModeRect.left) / 2); + ModeRect.left = sCenter - (ubTotalWidth / 2); + ModeRect.right = sCenter + (ubTotalWidth / 2); + + } + // BURST FIRE + else + { + // Draw colored bullets. These show how many bullets we've set to fire with the current burst. + usNumSpacesShown = 0; + UINT16 usTotalWidth = 0; + UINT8 x; + for (x = 0; x < ubNumBullets; x++) + { + // Set start point for drawing + INT16 sLeft = (((INT16)ModeRect.left + (INT16)ModeRect.right)/2) - (ubTotalWidth/2); + INT16 sTop = (INT16)ModeRect.top; + + // Calculate offset based on the number of bullets and spaces already drawn. + INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); + + // If we're drawing more bullets than can be displayed on-screen... + if (x == uiMaxBulletsToDisplay) + { + // Draw a colored plus sign at the end. + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 10, sLeft + sCurOffset, sTop+2, VO_BLT_SRCTRANSPARENCY, NULL ); + // Set x to NumBullets to end the loop + x = ubNumBullets; + usTotalWidth += 5; + } + else + { + // If we've drawn 5,10,15,etc. bullets, increase the number of spaces drawn. + if (x > 0 && x%5 == 0) + { + usNumSpacesShown++; + } + // Recalculate offset to take any new spaces into account. + INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); + // Draw a colored bullet here. + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 7, sLeft + sCurOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + usTotalWidth += ubBulletWidth * ((x+1)+usNumSpacesShown)+4; + INT16 sCenter = (INT16)((ModeRect.right + ModeRect.left) / 2); + ModeRect.left = sCenter - (ubTotalWidth / 2); + ModeRect.right = sCenter + (ubTotalWidth / 2); + } + } + + /////////////// SINGLE-SHOT. + else + { + // Draw a label that says "SINGLE" instead of bullets. + SetFont( TINYFONT1 ); + SetFontBackground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_MCOLOR_WHITE ); + + swprintf( pStr, gzNCTHlabels[ 0 ] ); + FindFontCenterCoordinates( (INT16)ModeRect.left, (INT16)ModeRect.top, (INT16)ModeRect.right-(INT16)ModeRect.left, 10, pStr, TINYFONT1, &curX, &curY); + gprintfdirty( curX, curY, pStr ); + mprintf( curX, curY, pStr); + + UINT16 usTotalWidth = StringPixLength( pStr, TINYFONT1 ) + 6; + INT16 sCenter = (INT16)((ModeRect.right + ModeRect.left) / 2); + ModeRect.left = sCenter - (usTotalWidth / 2); + ModeRect.right = sCenter + (usTotalWidth / 2); + } + + /////////////// AIM LEVELS + { + // Calculate number of allowed aiming levels on this gun. + INT8 ubAllowedLevels = AllowedAimingLevels( pSoldier, gCTHDisplay.iTargetGridNo ); + + // Number of ticks to display, and the number of spaces between them. + UINT8 ubNumTicks = ((ubAllowedLevels-1)*2)+1; + UINT8 ubNumSpaces = ubNumTicks-1; + + // Width of the tick image plus (or minus) a mandatory margin. + UINT8 ubAimTickWidth = 5; + + // Total width of the aiming display if using no extra spacing and MAXIMUM allowed aiming levels (currently 8) + UINT8 ubAimMaxTotalWidth = ubAimTickWidth * ((8 * 2)-1); + + // Total width of the aiming display if using no extra spacing and as many levels as allowed by the gun. + UINT8 ubAimPlainWidth = ubAimTickWidth * ubNumTicks; + + // Find the largest space width possible without exceeding the maximum width. We do this by + // finding the difference between MaxTotal width and Plain width, and dividing it by the number of spaces + // we've got. + UINT8 ubAimFinalOffset = 0; + UINT8 ubAimFinalWidth = 0; + if (ubNumSpaces > 0) + { + UINT8 ubAimBestOffset = (ubAimMaxTotalWidth - ubAimPlainWidth) / ubNumSpaces; + + // Final offset is whichever is smallest - the largest width, or the width of a single tick. + ubAimFinalOffset = __min(ubAimBestOffset, ubAimTickWidth); + } + // else leave at 0 + + ubAimFinalOffset += ubAimTickWidth; + + // Final width of the entire display, taking all ticks and spaces into account. + ubAimFinalWidth = ubAimTickWidth + (ubAimFinalOffset * ubNumSpaces); + + // Find offset from center. + UINT8 ubAimLeftOffset = ubAimFinalWidth / 2; + + // Find starting coordinates for this display + sTop = (INT16)AimRect.top; + sLeft = (INT16)((AimRect.left+AimRect.right)/2) - ubAimLeftOffset; + + // Draw empty ticks. + for (UINT8 x = 0; x < (ubAllowedLevels*2)-1; x++) + { + INT16 sOffset = x * ubAimFinalOffset; + if (gfDisplayFullCountRing) + { + if (ubAllowedLevels - abs((ubAllowedLevels-(x+1))) >= pSoldier->aiData.bShownAimTime) + { + // Red empty tick - unusable aim level with current AP! + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 6, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + // Orange empty tick - Used aim tick. + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 4, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + else + { + // grey empty tick + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 0, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + + // Draw Filled Ticks + if (pSoldier->aiData.bShownAimTime) + { + // Tick on the left + INT16 sNewLeft = sLeft + (ubAimFinalOffset * (pSoldier->aiData.bShownAimTime-1)); + if (gfDisplayFullCountRing) + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + + // Tick on the right + sNewLeft = sLeft + (ubAimFinalOffset * (ubNumSpaces-(pSoldier->aiData.bShownAimTime-1))); + if (gfDisplayFullCountRing) + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + } + + ubAimFinalWidth += 6; + INT16 sCenter = (INT16)((AimRect.right + AimRect.left) / 2); + AimRect.left = sCenter - (ubAimFinalWidth / 2); + AimRect.right = sCenter + (ubAimFinalWidth / 2); + + } + + // Delete CTH indicator STIs from memory. + DeleteVideoObjectFromIndex( guiCTHImage ); + + /////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Drawing the CTH indicator to the Frame Buffer + // + // Early on I ran into issues concerning drawing this indicator on the screen. At first I naturally + // wanted to draw it on the Cursor Buffer, the same way as the old indicator. Unfortunately, + // the size of the Cursor Buffer is quite limited (~35x35 pixels) and is governed by the size of the STIs used + // for the mouse cursor itself. After much trial and error, it became obvious that it was impossible to draw + // a large indicator (as required by the NCTH system) directly onto the mouse buffer. + // + // Fortunately, I found out that it was possible to draw into the Frame Buffer instead, without leaving + // graphical glitches behind. I could also dynamically define the area to draw into as I pleased. Furthermore, + // I managed to make this drawing behave the same as a mouse cursor would, by having it follow the mouse + // position. + // + // The end result is a bit of an ugly workaround: We're drawing what is essentially a mouse cursor without referring + // to ANY part of the mouse cursor system (except the location of the mouse). This is the only way I could make it + // work, and so far it works flawlessly. + + // Create a pointer to the Frame Buffer which we are going to draw directly into. + UINT32 uiPitch; + UINT16 *ptrBuf = (UINT16*)LockVideoSurface( FRAME_BUFFER, &uiPitch ); + uiPitch >>= 1; + + /////////////////////////////////////////////////////////////////////////////// + // Begin drawing + + sLeft = gsVIEWPORT_START_X; + sTop = gsVIEWPORT_WINDOW_START_Y; + sRight = gsVIEWPORT_END_X; + sBottom = gsVIEWPORT_WINDOW_END_Y; + + INT16 lastY = 0; + INT16 diffY = 0; + UINT32 uiAperture = __max(2,(UINT32)iAperture); + UINT32 uiMaxAperture = __max(2,(UINT32)iMaxAperture); + UINT32 uiApertureBarLength = 10; + + INT32 cnt = 0; + + // Vertical bias makes the circle "flatter" and "wider" in prone and crouched stance. + FLOAT dVerticalBias = gGameCTHConstants.VERTICAL_BIAS; + switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight) + { + case ANIM_STAND: + dVerticalBias = 1.0; + break; + case ANIM_PRONE: + // no change + break; + case ANIM_CROUCH: + dVerticalBias = 1.0f + ((dVerticalBias - 1.0f) * 0.66f); + break; + } + + // Circumference tells us how many pixels to draw, hopefully. + FLOAT RADIANS_IN_CIRCLE = (FLOAT)(PI * 2); + INT32 Circ = 0; + + Circ = (INT32)((iMaxAperture * RADIANS_IN_CIRCLE) * dVerticalBias); + // Draw outer circle + for (INT32 iCurPoint = 0; iCurPoint < Circ; iCurPoint++) + { + curX = (INT16)(iMaxAperture * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + curY = (INT16)((iMaxAperture * dVerticalBias) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + INT16 firstX = curX; + INT16 firstY = curY; + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBar ); + + // Draw a border circle which is 1 point wider + curX = (INT16)((iMaxAperture+1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + curY = (INT16)(((iMaxAperture * dVerticalBias)+1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + + if (curX != firstX || curY != firstY) + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); + + // Draw a border circle which is 1 point narrower + curX = (INT16)((iMaxAperture-1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + curY = (INT16)(((iMaxAperture * dVerticalBias)-1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + + if (curX != firstX || curY != firstY) + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); + } + + Circ = (INT32)((iAperture * RADIANS_IN_CIRCLE) * dVerticalBias); + // Draw inner circle + for (INT32 iCurPoint = 0; iCurPoint < Circ; iCurPoint++) + { + curX = (INT16)(iAperture * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + curY = (INT16)((iAperture * dVerticalBias) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + INT16 firstX = curX; + INT16 firstY = curY; + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBar ); + + // Draw a border circle which is 1 point wider + curX = (INT16)((iAperture+1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + curY = (INT16)(((iAperture * dVerticalBias)+1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + + if (curX != firstX || curY != firstY) + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); + + // Draw a border circle which is 1 point narrower + curX = (INT16)((iAperture-1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + curY = (INT16)(((iAperture * dVerticalBias)-1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); + + if (curX != firstX || curY != firstY) + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); + } + + // Aperture Crosshairs + for (INT16 cnt = (INT16)(iAperture); cnt <= (INT16)(iAperture + uiApertureBarLength); cnt++) + { + // Horizontal Aperture Crosshairs + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, sStartScreenY+(INT16)zOffset, usCApertureBar ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, sStartScreenY+(INT16)zOffset, usCApertureBar ); + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY+1)+(INT16)zOffset, usCApertureBar ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY+1)+(INT16)zOffset, usCApertureBar ); + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY-1)+(INT16)zOffset, usCApertureBar ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY-1)+(INT16)zOffset, usCApertureBar ); + + // Darker borders + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY+2)+(INT16)zOffset, usCApertureBorder ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY+2)+(INT16)zOffset, usCApertureBorder ); + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY-2)+(INT16)zOffset, usCApertureBorder ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY-2)+(INT16)zOffset, usCApertureBorder ); + + } + for (INT16 cnt = (INT16)(iAperture * dVerticalBias); cnt <= (INT16)((iAperture * dVerticalBias) + uiApertureBarLength); cnt++) + { + // Vertical Aperture Crosshairs + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBar ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBar ); + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+1, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBar ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+1, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBar ); + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-1, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBar ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-1, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBar ); + + // Darker borders + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+2, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBorder ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+2, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBorder ); + + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-2, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBorder ); + DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-2, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBorder ); + } + + // Unlock the Frame Buffer. + UnLockVideoSurface( FRAME_BUFFER ); + + return (TRUE); +} void RenderOverlayMessage( VIDEO_OVERLAY *pBlitter ) { @@ -2303,11 +3420,11 @@ void PopupDoorOpenMenu( BOOLEAN fClosingDoor ) } else { - swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ LOCKPICK_DOOR_ICON ], APBPConstants[AP_PICKLOCK] ); + swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ LOCKPICK_DOOR_ICON ], GetAPsToPicklock( gOpenDoorMenu.pSoldier ) ); // SANDRO } SetButtonFastHelpText( iActionIcons[ LOCKPICK_DOOR_ICON ], zDisp ); - if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_PICKLOCK], APBPConstants[BP_PICKLOCK], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) + if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToPicklock( gOpenDoorMenu.pSoldier ), APBPConstants[BP_PICKLOCK], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) // SANDRO { DisableButton( iActionIcons[ LOCKPICK_DOOR_ICON ] ); } @@ -2335,11 +3452,11 @@ void PopupDoorOpenMenu( BOOLEAN fClosingDoor ) } else { - swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ EXPLOSIVE_DOOR_ICON ], APBPConstants[AP_EXPLODE_DOOR] ); + swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ EXPLOSIVE_DOOR_ICON ], GetAPsToBombDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } SetButtonFastHelpText( iActionIcons[ EXPLOSIVE_DOOR_ICON ], zDisp ); - if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_EXPLODE_DOOR], APBPConstants[BP_EXPLODE_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) + if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToBombDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_EXPLODE_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) // SANDRO { DisableButton( iActionIcons[ EXPLOSIVE_DOOR_ICON ] ); } @@ -2369,7 +3486,7 @@ void PopupDoorOpenMenu( BOOLEAN fClosingDoor ) } else { - swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ CANCEL_ICON + 1 ], APBPConstants[AP_OPEN_DOOR] ); + swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ CANCEL_ICON + 1 ], GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } } else @@ -2380,12 +3497,12 @@ void PopupDoorOpenMenu( BOOLEAN fClosingDoor ) } else { - swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ OPEN_DOOR_ICON ], APBPConstants[AP_OPEN_DOOR] ); + swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ OPEN_DOOR_ICON ], GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } } SetButtonFastHelpText( iActionIcons[ OPEN_DOOR_ICON ], zDisp ); - if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_OPEN_DOOR], APBPConstants[BP_OPEN_DOOR], FALSE ) ) + if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_OPEN_DOOR], FALSE ) ) // SANDRO { DisableButton( iActionIcons[ OPEN_DOOR_ICON ] ); } @@ -2456,11 +3573,11 @@ void PopupDoorOpenMenu( BOOLEAN fClosingDoor ) } else { - swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ UNTRAP_DOOR_ICON ], APBPConstants[AP_UNTRAP_DOOR] ); + swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ UNTRAP_DOOR_ICON ], GetAPsToUntrapDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } SetButtonFastHelpText( iActionIcons[ UNTRAP_DOOR_ICON ], zDisp ); - if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_UNTRAP_DOOR], APBPConstants[BP_UNTRAP_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) + if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToUntrapDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_UNTRAP_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) // SANDRO { DisableButton( iActionIcons[ UNTRAP_DOOR_ICON ] ); } @@ -2577,7 +3694,8 @@ void BtnDoorMenuCallback(GUI_BUTTON *btn,INT32 reason) { // Open door normally... // Check APs - if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_OPEN_DOOR], APBPConstants[BP_OPEN_DOOR], FALSE ) ) + // SANDRO - changed APs for opening dorrs calc + if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_OPEN_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); @@ -2635,7 +3753,7 @@ void BtnDoorMenuCallback(GUI_BUTTON *btn,INT32 reason) if ( uiBtnID == iActionIcons[ LOCKPICK_DOOR_ICON ] ) { // Lockpick - if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_PICKLOCK], APBPConstants[BP_PICKLOCK], FALSE ) ) + if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToPicklock( gOpenDoorMenu.pSoldier ), APBPConstants[BP_PICKLOCK], FALSE ) ) // SANDRO { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); @@ -2669,7 +3787,7 @@ void BtnDoorMenuCallback(GUI_BUTTON *btn,INT32 reason) if ( uiBtnID == iActionIcons[ EXPLOSIVE_DOOR_ICON ] ) { // Explode - if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_EXPLODE_DOOR], APBPConstants[BP_EXPLODE_DOOR], FALSE ) ) + if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToBombDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_EXPLODE_DOOR], FALSE ) ) // SANDRO { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); @@ -2686,7 +3804,7 @@ void BtnDoorMenuCallback(GUI_BUTTON *btn,INT32 reason) if ( uiBtnID == iActionIcons[ UNTRAP_DOOR_ICON ] ) { // Explode - if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_UNTRAP_DOOR], APBPConstants[BP_UNTRAP_DOOR], FALSE ) ) + if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToUntrapDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_UNTRAP_DOOR], FALSE ) ) // SANDRO { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); @@ -2965,10 +4083,40 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) FLOAT dNumStepsPerEnemy, dLength, dCurSize; INT16 iProgBarLength = SCREEN_WIDTH - 13; - + //*ddd{ + STR fn; + //*ddd} memset( &VObjectDesc, 0, sizeof( VObjectDesc ) ); VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; + //* ddd { + switch (iResolution) + { + case 0: //640 + fn = "INTERFACE\\rect.sti"; + break; + case 1: //800 + if (gGameExternalOptions.fSmallSizeProgressbar) + fn = "INTERFACE\\rect_800x600Thin.sti"; + else + fn = "INTERFACE\\rect_800x600.sti"; + break; + case 2: + fn = "INTERFACE\\rect_1024x768.sti"; + break; + default: + AssertMsg( 0, "Invalid resolution"); + return; + break; + }//switch + FilenameForBPP(fn, VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &uiBAR ) ) { sprintf(fn, "Missing %s", fn); + AssertMsg(0, fn ); } + //*ddd } + + + //* crappy code commented ddd + /* if (iResolution == 0) { FilenameForBPP("INTERFACE\\rect.sti", VObjectDesc.ImageFile); @@ -2983,11 +4131,38 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) } if( !AddVideoObject( &VObjectDesc, &uiBAR ) ) - AssertMsg(0, "Missing INTERFACE\\rect.sti" ); + AssertMsg(0, "Missing INTERFACE\\rect.sti" ); + */ //if ( gGameOptions.fTurnTimeLimit ) //{ + //* ddd { + switch (iResolution) + { + case 0: //640 + fn = "INTERFACE\\timebargreen.sti"; + break; + case 1: //800 + if (gGameExternalOptions.fSmallSizeProgressbar) + fn = "INTERFACE\\timebargreen_800x600Thin.sti"; + else + fn = "INTERFACE\\timebargreen_800x600.sti"; + break; + case 2: + fn = "INTERFACE\\timebargreen_1024x768.sti"; + break; + default: + AssertMsg( 0, "Invalid resolution"); + return; + break; + }//switch + FilenameForBPP(fn, VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &uiPLAYERBAR ) ){ sprintf(fn, "Missing %s", fn); + AssertMsg(0, fn ); } + //*ddd } + + /* commented if (iResolution == 0) { FilenameForBPP("INTERFACE\\timebargreen.sti", VObjectDesc.ImageFile); @@ -2999,6 +4174,10 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) FilenameForBPP("INTERFACE\\timebargreen_800x600.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &uiPLAYERBAR ) ) AssertMsg(0, "Missing INTERFACE\\timebargreen_800x600.sti" ); + if (SMALL_SIZE_PROGRESSBAR) + fn = "INTERFACE\\timebargreen_800x600Thin.sti"; + else + fn = "INTERFACE\\timebargreen_800x600.sti"; } else if (iResolution == 2) { @@ -3006,7 +4185,40 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) if( !AddVideoObject( &VObjectDesc, &uiPLAYERBAR ) ) AssertMsg(0, "Missing INTERFACE\\timebargreen_1024x768.sti" ); } + else + { + AssertMsg( 0, "Invalid resolution"); + return; + } + */ + + //* ddd { + switch (iResolution) + { + case 0: //640 + fn = "INTERFACE\\timebaryellow.sti"; + break; + case 1: //800 + if (gGameExternalOptions.fSmallSizeProgressbar) + fn = "INTERFACE\\timebaryellow_800x600Thin.sti"; + else + fn = "INTERFACE\\timebaryellow_800x600.sti"; + break; + case 2: + fn = "INTERFACE\\timebaryellow_1024x768.sti"; + break; + default: + AssertMsg( 0, "Invalid resolution"); + return; + break; + }//switch + FilenameForBPP(fn, VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &uiINTBAR ) ){ sprintf(fn, "Missing %s", fn); + AssertMsg(0, fn ); } + //*ddd } + + /* if (iResolution == 0) { FilenameForBPP("INTERFACE\\timebaryellow.sti", VObjectDesc.ImageFile); @@ -3021,13 +4233,26 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) } else if (iResolution == 2) { - FilenameForBPP("INTERFACE\\timebaryellow_1024x768.sti", VObjectDesc.ImageFile); - if( !AddVideoObject( &VObjectDesc, &uiINTBAR ) ) - AssertMsg(0, "Missing INTERFACE\\timebaryellow_1024x768.sti" ); + //*ddd FilenameForBPP("INTERFACE\\timebaryellow_1024x768.sti", VObjectDesc.ImageFile); + //*ddd if( !AddVideoObject( &VObjectDesc, &uiINTBAR ) ) + //*ddd AssertMsg(0, "Missing INTERFACE\\timebaryellow_1024x768.sti" ); + fn = "INTERFACE\\timebaryellow_1024x768.sti"; } + else + { + AssertMsg( 0, "Invalid resolution"); + return; + } + + FilenameForBPP(fn, VObjectDesc.ImageFile); + if( !AddVideoObject( &VObjectDesc, &uiINTBAR ) ) + AssertMsg(0, String( "Missing %s", VObjectDesc.ImageFile) ); + */ // Change dest buffer - SetFontDestBuffer( uiSurface , 0, 0, SCREEN_WIDTH , 20, FALSE ); + //*ddd + //SetFontDestBuffer( uiSurface , 0, 0, SCREEN_WIDTH , 20, FALSE ); + SetFontDestBuffer( uiSurface , 0, 0, SCREEN_WIDTH , HEIGHT_PROGRESSBAR, FALSE ); SetFont( TINYFONT1 ); switch( ubType ) @@ -3052,7 +4277,7 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) BltVideoObjectFromIndex( uiSurface, uiINTBAR, 0, 0, 0, VO_BLT_SRCTRANSPARENCY, NULL ); SetFontBackground( FONT_MCOLOR_BLACK ); - SetFontForeground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_MCOLOR_WHITE ); SetFontShadow( NO_SHADOW ); uiBarToUseInUpDate = uiINTBAR; break; @@ -3069,7 +4294,7 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) // BltVideoObjectFromIndex( uiSurface, uiPLAYERBAR, 13, 0, 0, VO_BLT_SRCTRANSPARENCY, NULL ); //} SetFontBackground( FONT_MCOLOR_BLACK ); - SetFontForeground( FONT_MCOLOR_BLACK ); + SetFontForeground( FONT_MCOLOR_WHITE ); SetFontShadow( NO_SHADOW ); uiBarToUseInUpDate = uiPLAYERBAR; break; @@ -3194,7 +4419,12 @@ void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) } // Draw text.... - FindFontCenterCoordinates( SCREEN_WIDTH/2, 7, 1, 1, psString, TINYFONT1, &sX, &sY ); + //*ddd FindFontCenterCoordinates( SCREEN_WIDTH/2, 7, 1, 1, psString, TINYFONT1, &sX, &sY ); + if(gGameExternalOptions.fSmallSizeProgressbar) + FindFontCenterCoordinates( SCREEN_WIDTH/2, 2, 1, 1, psString, TINYFONT1, &sX, &sY ); + else + FindFontCenterCoordinates( SCREEN_WIDTH/2, 7, 1, 1, psString, TINYFONT1, &sX, &sY ); + mprintf( sX, sY, psString ); // Change back... @@ -3344,7 +4574,8 @@ void HandleTopMessages( ) } // Set redner viewport value - gsVIEWPORT_WINDOW_START_Y = 20; + //* ddd gsVIEWPORT_WINDOW_START_Y = 20; + gsVIEWPORT_WINDOW_START_Y = HEIGHT_PROGRESSBAR; // Check if we have scrolled... if ( gTopMessage.sWorldRenderX != gsRenderCenterX || gTopMessage.sWorldRenderY != gsRenderCenterY ) @@ -3359,9 +4590,15 @@ void HandleTopMessages( ) // Redner! BltFx.SrcRect.iLeft = 0; - BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; + //* ddd BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; + if(gGameExternalOptions.fSmallSizeProgressbar) + BltFx.SrcRect.iTop = 0; + else + BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; + BltFx.SrcRect.iRight = SCREEN_WIDTH ; - BltFx.SrcRect.iBottom = 20; + //*ddd BltFx.SrcRect.iBottom = 20; + BltFx.SrcRect.iBottom = HEIGHT_PROGRESSBAR; BltVideoSurface( FRAME_BUFFER, gTopMessage.uiSurface, 0, 0, 0, @@ -3369,15 +4606,22 @@ void HandleTopMessages( ) // Save to save buffer.... BltFx.SrcRect.iLeft = 0; - BltFx.SrcRect.iTop = 0; + //* ddd BltFx.SrcRect.iTop = 0; + if(gGameExternalOptions.fSmallSizeProgressbar) + BltFx.SrcRect.iTop = 0; + else + BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; + BltFx.SrcRect.iRight = SCREEN_WIDTH; - BltFx.SrcRect.iBottom = 20; + //*ddd BltFx.SrcRect.iBottom = 20; + BltFx.SrcRect.iBottom = HEIGHT_PROGRESSBAR; BltVideoSurface( guiSAVEBUFFER, FRAME_BUFFER, 0, 0, 0, VS_BLT_SRCSUBRECT, &BltFx ); - InvalidateRegion( 0, 0, SCREEN_WIDTH, 20 ); + //*ddd InvalidateRegion( 0, 0, SCREEN_WIDTH, 20 ); + InvalidateRegion( 0, 0, SCREEN_WIDTH, HEIGHT_PROGRESSBAR ); gfTopMessageDirty = FALSE; } diff --git a/Tactical/Interface.h b/Tactical/Interface.h index 01b0c80e..9d242e89 100644 --- a/Tactical/Interface.h +++ b/Tactical/Interface.h @@ -7,6 +7,80 @@ #define MAX_UICOMPOSITES 4 +enum +{ + WALK_ICON, + SNEAK_ICON, + RUN_ICON, + CRAWL_ICON, + LOOK_ICON, + ACTIONC_ICON, + TALK_ICON, + HAND_ICON, + + OPEN_DOOR_ICON, + EXAMINE_DOOR_ICON, + LOCKPICK_DOOR_ICON, + BOOT_DOOR_ICON, + UNTRAP_DOOR_ICON, + USE_KEY_ICON, + USE_KEYRING_ICON, + EXPLOSIVE_DOOR_ICON, + USE_CROWBAR_ICON, + + CANCEL_ICON, + NUM_ICONS +}; + +#define MAX_ENEMY_NAMES_CHARS 128 + +typedef struct +{ + UINT16 uiIndex; // add + BOOLEAN Hidden; //add + +} HIDDEN_NAMES_VALUES; + +extern HIDDEN_NAMES_VALUES zHiddenNames[500]; + +typedef struct +{ + UINT16 uiIndex; + BOOLEAN Enabled; + UINT16 ExpLevel; + UINT16 Stats; + UINT16 StatsMin; + UINT16 StatsMax; + CHAR16 szCurRank[MAX_ENEMY_NAMES_CHARS]; + +} ENEMY_RANK_VALUES; + +extern ENEMY_RANK_VALUES zEnemyRank[500]; + +typedef struct +{ + UINT16 uiIndex; // add + BOOLEAN Enabled; //add + UINT16 SectorX; //add + UINT16 SectorY; //add + CHAR16 szCurGroup[MAX_ENEMY_NAMES_CHARS]; + +} ENEMY_NAMES_VALUES; + +extern ENEMY_NAMES_VALUES zEnemyName[500]; + +typedef struct +{ + UINT16 uiIndex; // add + BOOLEAN Enabled; //add + BOOLEAN Loyalty; + BOOLEAN AddToBattle; + CHAR16 szCurGroup[MAX_ENEMY_NAMES_CHARS]; + +} CIV_NAMES_VALUES; + +extern CIV_NAMES_VALUES zCivGroupName[NUM_CIV_GROUPS]; + extern int INTERFACE_WIDTH; // 640 extern int INTERFACE_HEIGHT; // 120 extern int INV_INTERFACE_HEIGHT; // 140 @@ -84,11 +158,15 @@ extern UINT32 guiSILHOUETTE; extern UINT32 guiCOMPANEL; extern UINT32 guiCOMPANELB; extern UINT32 guiRADIO; -extern UINT32 guiPORTRAITICONS; +extern UINT32 guiPORTRAITICONS; // Default JA2 portrait icons (+ additional headgear icons from legion) extern UINT32 guiBURSTACCUM; extern UINT32 guiITEMPOINTERHATCHES; +//legion +extern UINT32 guiPORTRAITICONS_NV; //legion: NV-Face Graphic +extern UINT32 guiPORTRAITICONS_GAS_MASK; //legion: GASMASK-Face Graphic + extern MOUSE_REGION gViewportRegion; extern MOUSE_REGION gRadarRegion; extern MOUSE_REGION gBottomPanalRegion; @@ -146,9 +224,11 @@ void HandleInterfaceBackgrounds( ); void BeginOverlayMessage( UINT32 uiFont, STR16 pFontString, ... ); void EndOverlayMessage( ); - void DrawSelectedUIAboveGuy( UINT16 usSoldierID ); +// HEADROCK HAM 4: Draw the CTH indicator, using values grabbed from the global CTH array +BOOLEAN DrawCTHIndicator(); + void CreateCurrentTacticalPanelButtons( ); void RemoveCurrentTacticalPanelButtons( ); void SetCurrentTacticalPanelCurrentMerc( UINT8 ubID ); diff --git a/Tactical/InterfaceItemImages.cpp b/Tactical/InterfaceItemImages.cpp index 76e6195d..ccf6ff76 100644 --- a/Tactical/InterfaceItemImages.cpp +++ b/Tactical/InterfaceItemImages.cpp @@ -4,7 +4,7 @@ #include "vobject.h" #include "utilities.h" -#include "VFS/vfs.h" +#include extern void WriteMessageToFile( const STR16 pString ); @@ -34,7 +34,7 @@ UINT32 MDItemVideoObjects::getVObjectForItem(UINT32 key) { return it->second; } - THROWEXCEPTION(BuildString().add(L"Item key [").add(key).add(L"] not registered").get()); + SGP_THROW(_BS(L"Item key not registered : ") << key << _BS::wget); } void MDItemVideoObjects::registerItem(UINT32 key, vfs::Path const& sFileName) @@ -42,7 +42,7 @@ void MDItemVideoObjects::registerItem(UINT32 key, vfs::Path const& sFileName) std::map::iterator it = m_mapVObjects.find(key); if(it != m_mapVObjects.end()) { - THROWEXCEPTION(BuildString().add(L"Item image [").add(key).add(L"] already registered").get()); + SGP_THROW(_BS(L"Item image already registered : ") << key << _BS::wget); } // LOAD INTERFACE GUN PICTURES UINT32 uiVObject; @@ -51,7 +51,7 @@ void MDItemVideoObjects::registerItem(UINT32 key, vfs::Path const& sFileName) FilenameForBPP(const_cast(sFileName.to_string().c_str()), VObjectDesc.ImageFile); if(! AddVideoObject( &VObjectDesc, &uiVObject )) { - THROWEXCEPTION( BuildString().add(L"Could not add video object for file \"").add(sFileName).get() ); + SGP_THROW(_BS(L"Could not add video object for file \"") << sFileName << _BS::wget); } m_mapVObjects.insert(std::make_pair(key,uiVObject)); } @@ -70,7 +70,7 @@ bool MDItemVideoObjects::registerItemsFromFilePattern(vfs::Path const& sFilePatt wss.str(it.value()->getName().c_wcs()); if( !(wss >> item) ) { - std::wstring err = BuildString().add(L"Could not extract item number from file \"").add(wss.str()).add(L"\"").get(); + std::wstring err = _BS(L"Could not extract item number from file \"") << wss.str() << L"\"" << _BS::wget; WriteMessageToFile( const_cast(err.c_str()) ); continue; } @@ -78,10 +78,9 @@ bool MDItemVideoObjects::registerItemsFromFilePattern(vfs::Path const& sFilePatt { this->registerItem(item, it.value()->getPath()); } - catch(CBasicException& ex) + catch(std::exception& ex) { - RETHROWEXCEPTION( BuildString().add(L"Registering item from file \"").add(wss.str()).add(L"\" failed").get().c_str(), - &ex ); + SGP_RETHROW( _BS(L"Registering item from file \"") << wss.str() << L"\" failed" << _BS::wget, ex ); } } return true; diff --git a/Tactical/InterfaceItemImages.h b/Tactical/InterfaceItemImages.h index 5dd3d373..1d8c3c62 100644 --- a/Tactical/InterfaceItemImages.h +++ b/Tactical/InterfaceItemImages.h @@ -2,8 +2,8 @@ #define _ITERFACEITEMIMAGES_H_ #include "Types.h" -#include "VFS/vfs_types.h" -#include "VFS/vfs_path.h" +#include +#include #include class MDItemVideoObjects diff --git a/Tactical/Inventory Choosing.cpp b/Tactical/Inventory Choosing.cpp index 79674650..8e89cf30 100644 --- a/Tactical/Inventory Choosing.cpp +++ b/Tactical/Inventory Choosing.cpp @@ -273,10 +273,54 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 // So in the same time when admins hold crappy weapons, elites get stuff up to nearly 6 level // in Drassen counter-attack. In this situation it is very hard to make balanced xml-file(IMHO). // Made in optional form - if ( gGameExternalOptions.fSlowProgressForEnemyItemsChoice ) - bEquipmentModifier = ( CalcDifficultyModifier( bSoldierClass ) / 10 ); - else - bEquipmentModifier = bEquipmentRating + ( ( CalcDifficultyModifier( bSoldierClass ) / 10 ) - 5 ); + + // SANDRO - new behaviour of progress setting + bEquipmentModifier = bEquipmentRating + ( ( CalcDifficultyModifier( bSoldierClass ) / 10 ) - 5 ); + switch( gGameOptions.ubProgressSpeedOfItemsChoices ) + { + case ITEM_PROGRESS_VERY_SLOW: + // On "Very Slow", at the beginning of the game, the modifier is -5 and goes up to -1 at +-100% game progress + bEquipmentModifier -= (1 + (4 - (HighestPlayerProgressPercentage() / 25) )); + break; + case ITEM_PROGRESS_SLOW: + // On "Slow", it's -3 until hit at least 10% game progress, then -2 till 40%, then -1 till 80% + if (HighestPlayerProgressPercentage() < 10 ) + bEquipmentModifier -= 3; + else if (HighestPlayerProgressPercentage() < 40 ) + bEquipmentModifier -= 2; + else if (HighestPlayerProgressPercentage() < 80 ) + bEquipmentModifier -= 1; + break; + case ITEM_PROGRESS_NORMAL: + // Nothing needed here + break; + case ITEM_PROGRESS_FAST: + // On "Fast", it's just +1 at the beginning and rise up through out the game + if (HighestPlayerProgressPercentage() < 25 ) + bEquipmentModifier += 1; + else if (HighestPlayerProgressPercentage() < 60 ) + bEquipmentModifier += 2; + else if (HighestPlayerProgressPercentage() < 90 ) + bEquipmentModifier += 3; + else + bEquipmentModifier += 4; + break; + case ITEM_PROGRESS_VERY_FAST: + // "Very Fast" just make everyone loaded with top gear quickly + if (HighestPlayerProgressPercentage() < 10 ) + bEquipmentModifier += 2; + else if (HighestPlayerProgressPercentage() < 25 ) + bEquipmentModifier += 3; + else if (HighestPlayerProgressPercentage() < 50 ) + bEquipmentModifier += 4; + else if (HighestPlayerProgressPercentage() < 80 ) + bEquipmentModifier += 5; + else + bEquipmentModifier += 6; + break; + default: + break; + } switch( bSoldierClass ) { @@ -287,12 +331,14 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 // civilians get nothing, anyone who should get something should be preassigned by Linda break; + // SANDRO - I've split the item choosing below, so the item choices for militia can be + // handled differently than for enemies. case SOLDIER_CLASS_ADMINISTRATOR: - case SOLDIER_CLASS_GREEN_MILITIA: - if ( gGameExternalOptions.fSlowProgressForEnemyItemsChoice ) - bRating = bEquipmentModifier - ( bSoldierClass == SOLDIER_CLASS_GREEN_MILITIA ); - else - bRating = BAD_ADMINISTRATOR_EQUIPMENT_RATING + bEquipmentModifier; + //if ( gGameOptions.fSlowProgressForEnemyItemsChoice ) + // bRating = bEquipmentModifier - ( bSoldierClass == SOLDIER_CLASS_ADMINISTRATOR ); + //else + bRating = BAD_ADMINISTRATOR_EQUIPMENT_RATING + bEquipmentModifier; + bRating = (INT8)max( MIN_EQUIPMENT_CLASS, min( MAX_EQUIPMENT_CLASS, bRating ) ); bWeaponClass = bRating; @@ -305,7 +351,7 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 bHelmetClass = bRating; // no leggings - if( Random( 2 ) ) + if( Chance( 30 ) ) bKnifeClass = bRating; bAmmoClips = (INT8)(3 + Random( 2 )); @@ -325,6 +371,53 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 bGrenades = 1, bGrenadeClass = bRating; } + if( ( bRating > MIN_EQUIPMENT_CLASS ) && bRating < MAX_EQUIPMENT_CLASS ) + { //Randomly decide if there is to be an upgrade of guns vs armour (one goes up, the other down) + switch( Random( 5 ) ) + { + case 0: bWeaponClass++, bVestClass--; break; //better gun, worse armour + case 1: bWeaponClass--, bVestClass++; break; //worse gun, better armour + } + } + break; + case SOLDIER_CLASS_GREEN_MILITIA: + + bRating = BAD_ADMINISTRATOR_EQUIPMENT_RATING + bEquipmentModifier; + + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Militia equipment quality bonus + if ( gGameExternalOptions.bGreenMilitiaEquipmentQualityModifier != 0 ) + bRating += gGameExternalOptions.bGreenMilitiaEquipmentQualityModifier; + /////////////////////////////////////////////////////////////////////////////////////////// + + bRating = (INT8)max( MIN_EQUIPMENT_CLASS, min( MAX_EQUIPMENT_CLASS, bRating ) ); + + bWeaponClass = bRating; + //Headrocktest, remove for release + //bLBEClass = bRating; + + //Note: in some cases the class of armour and/or helmet won't be high enough to make + // the lowest level. + bVestClass = bRating; + bHelmetClass = bRating; + + if( Chance( 15 ) ) + bKnifeClass = bRating; + + bAmmoClips = (INT8)(3 + Random( 2 )); + + if( bRating >= GOOD_ADMINISTRATOR_EQUIPMENT_RATING ) + { + bAmmoClips++; + + bMiscClass = bRating; + } + + if( bRating >= GREAT_ADMINISTRATOR_EQUIPMENT_RATING ) + { + bGrenades = 1, bGrenadeClass = bRating; + } + if( ( bRating > MIN_EQUIPMENT_CLASS ) && bRating < MAX_EQUIPMENT_CLASS ) { //Randomly decide if there is to be an upgrade of guns vs armour (one goes up, the other down) switch( Random( 5 ) ) @@ -336,11 +429,10 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 break; case SOLDIER_CLASS_ARMY: - case SOLDIER_CLASS_REG_MILITIA: //army guys tend to have a broad range of equipment - if ( gGameExternalOptions.fSlowProgressForEnemyItemsChoice ) - bRating = bEquipmentModifier - ( bSoldierClass == SOLDIER_CLASS_REG_MILITIA ); - else + //if ( gGameOptions.fSlowProgressForEnemyItemsChoice ) + // bRating = bEquipmentModifier - ( bSoldierClass == SOLDIER_CLASS_ARMY ); + //else bRating = BAD_ARMY_EQUIPMENT_RATING + bEquipmentModifier; bRating = (INT8)max( MIN_EQUIPMENT_CLASS, min( MAX_EQUIPMENT_CLASS, bRating ) ); @@ -350,12 +442,14 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 bGrenadeClass = bRating; // Headrock: Added LBE set to Coolness Rating bLBEClass = bRating; + //WarmSteel - attachments don't need to be as high a class, controversional and might be better to externalize? + bAttachClass = bRating*3/8; - if( ( bRating >= GOOD_ARMY_EQUIPMENT_RATING ) && ( Random( 100 ) < 33 ) ) + if( ( bRating >= GOOD_ARMY_EQUIPMENT_RATING ) && Chance(33) ) { fAttachment = TRUE; - bAttachClass = bRating; + bAttachClass = bRating*5/8; } bAmmoClips = (INT8)(3 + Random( 2 )); @@ -384,12 +478,12 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 } } - if( Random( 2 ) ) + if( Chance( 35 ) ) bKnifeClass = bRating; // Headrock: Chance for soldier to carry better LBE - if( Chance( 50 ) ) - bLBEClass++; + //if( Chance( 50 ) ) + // bLBEClass++; if( ( bRating > MIN_EQUIPMENT_CLASS ) && bRating < MAX_EQUIPMENT_CLASS ) { @@ -454,12 +548,115 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 } } break; + case SOLDIER_CLASS_REG_MILITIA: + + bRating = BAD_ARMY_EQUIPMENT_RATING + bEquipmentModifier; + + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Militia equipment quality bonus + if ( gGameExternalOptions.bRegularMilitiaEquipmentQualityModifier != 0 ) + bRating += gGameExternalOptions.bRegularMilitiaEquipmentQualityModifier; + /////////////////////////////////////////////////////////////////////////////////////////// + + bRating = (INT8)max( MIN_EQUIPMENT_CLASS, min( MAX_EQUIPMENT_CLASS, bRating ) ); + + bWeaponClass = bRating; + bVestClass = bRating; + bHelmetClass = bRating; + bGrenadeClass = bRating; + //WarmSteel - attachments don't need to be as high a class, controversional and might be better to externalize? + bAttachClass = bRating*3/8; + + + if( ( bRating >= GOOD_ARMY_EQUIPMENT_RATING ) && Chance(33) ) + { + fAttachment = TRUE; + bAttachClass = bRating*5/8; + } + + bAmmoClips = (INT8)(3 + Random( 2 )); + + if( bRating >= AVERAGE_ARMY_EQUIPMENT_RATING ) + { + bGrenades = (INT8)Random( 2 ); + bKitClass = bRating; + bMiscClass = bRating; + } + + if( bRating >= GOOD_ARMY_EQUIPMENT_RATING ) + { + bGrenades++; + } + + if( bRating >= GREAT_ARMY_EQUIPMENT_RATING ) + { + bGrenades++; + + bLeggingClass = bRating; + + if ( Chance( 25 ) ) + { + bBombClass = bRating; + } + } + + if( Chance( 20 ) ) + bKnifeClass = bRating; + + if( ( bRating > MIN_EQUIPMENT_CLASS ) && bRating < MAX_EQUIPMENT_CLASS ) + { + switch( Random( 7 ) ) + { + case 3: bWeaponClass++, bVestClass--; break; //better gun, worse armour + case 4: bWeaponClass--, bVestClass++; break; //worse gun, better armour + case 5: bVestClass++, bHelmetClass--; break; //better armour, worse helmet + case 6: bVestClass--, bHelmetClass++; break; //worse armour, better helmet + } + } + + // if well-enough equipped, 1/5 chance of something really special + if( ( bRating >= GREAT_ARMY_EQUIPMENT_RATING ) && ( Random( 100 ) < 20 ) ) + { + //give this man a special weapon! No mortars if underground, however + ubMaxSpecialWeaponRoll = ( !IsAutoResolveActive() && ( gbWorldSectorZ != 0 ) ) ? 6 : 7; + switch ( Random ( ubMaxSpecialWeaponRoll ) ) + { + case 0: + case 1: + case 2: + if ( pp->bExpLevel >= 3 ) + { + //grenade launcher + fGrenadeLauncher = TRUE; + bGrenades = 3 + (INT8)(Random( 3 )); //3-5 + } + break; + + case 3: + case 4: + if ( pp->bExpLevel >= 4 ) + { + // LAW rocket launcher + fLAW = TRUE; + } + break; + case 5: + if ( pp->bExpLevel >= 5 ) + { + // RPG rocket launcher + fRPG = TRUE; + bGrenades = 2 + (INT8)(Random( 3 )); //2-4 + bGrenadeClass = RPG_GRENADE_CLASS; + } + break; + } + } + break; case SOLDIER_CLASS_ELITE: - case SOLDIER_CLASS_ELITE_MILITIA: - if ( gGameExternalOptions.fSlowProgressForEnemyItemsChoice ) - bRating = bEquipmentModifier - ( bSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ); - else + //if ( gGameOptions.fSlowProgressForEnemyItemsChoice ) + // bRating = bEquipmentModifier - ( bSoldierClass == SOLDIER_CLASS_ELITE ); + //else bRating = BAD_ELITE_EQUIPMENT_RATING + bEquipmentModifier; bRating = (INT8)max( MIN_EQUIPMENT_CLASS, min( MAX_EQUIPMENT_CLASS, bRating ) ); @@ -467,7 +664,7 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 bHelmetClass = bRating; bVestClass = bRating; bLeggingClass = bRating; - bAttachClass = bRating; + bAttachClass = bRating*7/8; bGrenadeClass = bRating; bKitClass = bRating; bMiscClass = bRating; @@ -483,13 +680,13 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 bAmmoClips = (INT8)(3 + Random( 2 )); bGrenades = (INT8)(2 + Random( 3 )); - if( ( bRating >= AVERAGE_ELITE_EQUIPMENT_RATING ) && ( Random( 100 ) < 75 ) ) + if( ( bRating >= AVERAGE_ELITE_EQUIPMENT_RATING ) && Chance(75) ) { fAttachment = TRUE; bAttachClass = bRating; } - if( Random( 2 ) ) + if( Chance( 35 ) ) bKnifeClass = bRating; if( ( bRating > MIN_EQUIPMENT_CLASS ) && bRating < MAX_EQUIPMENT_CLASS ) @@ -549,6 +746,106 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 } } break; + case SOLDIER_CLASS_ELITE_MILITIA: + + bRating = BAD_ELITE_EQUIPMENT_RATING + bEquipmentModifier; + + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Militia equipment quality bonus + if ( gGameExternalOptions.bVeteranMilitiaEquipmentQualityModifier != 0 ) + bRating += gGameExternalOptions.bVeteranMilitiaEquipmentQualityModifier; + /////////////////////////////////////////////////////////////////////////////////////////// + + bRating = (INT8)max( MIN_EQUIPMENT_CLASS, min( MAX_EQUIPMENT_CLASS, bRating ) ); + + bWeaponClass = bRating; + bHelmetClass = bRating; + bVestClass = bRating; + bLeggingClass = bRating; + bAttachClass = bRating*7/8; + bGrenadeClass = bRating; + bKitClass = bRating; + bMiscClass = bRating; + + if ( Chance( 25 ) ) + { + bBombClass = bRating; + } + + bAmmoClips = (INT8)(3 + Random( 2 )); + bGrenades = (INT8)(2 + Random( 3 )); + + if( ( bRating >= AVERAGE_ELITE_EQUIPMENT_RATING ) && Chance(75) ) + { + fAttachment = TRUE; + bAttachClass = bRating; + } + + if( Chance( 25 ) ) + bKnifeClass = bRating; + + if( ( bRating > MIN_EQUIPMENT_CLASS ) && bRating < MAX_EQUIPMENT_CLASS ) + { + UINT32 uiRange = ((UsingNewInventorySystem() == false)) ? Random(10) : Random(11); + switch( uiRange ) + { + case 4: bWeaponClass++, bVestClass--; break; + case 5: bWeaponClass--, bVestClass--; break; + case 6: bVestClass++, bHelmetClass--; break; + case 7: bGrenades += 2; break; + case 8: bHelmetClass++; break; + case 9: bVestClass++; break; + case 10: bWeaponClass++; break; + //case 11: bLBEClass++; break; + } + } + + // if well-enough equipped, 1/3 chance of something really special + if( ( bRating >= GOOD_ELITE_EQUIPMENT_RATING ) && ( Random( 100 ) < 60 ) ) + { + //give this man a special weapon! No mortars if underground, however + ubMaxSpecialWeaponRoll = ( !IsAutoResolveActive() && ( gbWorldSectorZ != 0 ) ) ? 4 : 5; + switch ( Random ( ubMaxSpecialWeaponRoll ) ) + { + case 0: + //grenade launcher + fGrenadeLauncher = TRUE; + bGrenades = 4 + (INT8)(Random( 4 )); //4-7 + break; + case 1: + case 2: + // LAW rocket launcher + fLAW = TRUE; + break; + case 3: + // RPG rocket launcher + fRPG = TRUE; + bGrenades = 3 + (INT8)(Random( 5 )); //3-7 + bGrenadeClass = RPG_GRENADE_CLASS; + break; + case 4: + // one per team maximum! + if ( guiMortarsRolledByTeam < MAX_MORTARS_PER_TEAM ) + { + //mortar + fMortar = TRUE; + guiMortarsRolledByTeam++; + + // the grenades will actually represent mortar shells in this case + bGrenades = 3 + (INT8)(Random( 5 )); //3-7 + bGrenadeClass = MORTAR_GRENADE_CLASS; + } + else + { + // RPG rocket launcher + fRPG = TRUE; + bGrenades = 3 + (INT8)(Random( 5 )); //3-7 + bGrenadeClass = RPG_GRENADE_CLASS; + } + break; + } + } + break; } for ( i = 0; i < pp->Inv.size(); i++ ) @@ -638,17 +935,22 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 //Now actually choose the equipment! ChooseWeaponForSoldierCreateStruct( pp, bWeaponClass, bAmmoClips, bAttachClass, fAttachment ); // Headrock: This is where the program calls LBE choosing - ChooseLBEsForSoldierCreateStruct( pp, bLBEClass ); + if ( SOLDIER_CLASS_ENEMY( bSoldierClass )) // BUT ONLY FOR ENEMIES, NOT MILITIA - SANDRO + { + if (Chance(50)) // Make EDB gear rare + ChooseLBEsForSoldierCreateStruct( pp, bLBEClass ); + } ChooseSpecialWeaponsForSoldierCreateStruct( pp, bKnifeClass, fGrenadeLauncher, fLAW, fMortar, fRPG ); ChooseGrenadesForSoldierCreateStruct( pp, bGrenades, bGrenadeClass, fGrenadeLauncher ); ChooseArmourForSoldierCreateStruct( pp, bHelmetClass, bVestClass, bLeggingClass ); ChooseFaceGearForSoldierCreateStruct( pp ); - ChooseKitsForSoldierCreateStruct( pp, bKitClass ); + if (Chance(65)) + { ChooseKitsForSoldierCreateStruct( pp, bKitClass ); } // Kits not so often - SANDRO ChooseMiscGearForSoldierCreateStruct( pp, bMiscClass ); ChooseBombsForSoldierCreateStruct( pp, bBombClass ); //ADB why is this here twice? // Headrock: This is where the program calls LBE choosing - ChooseLBEsForSoldierCreateStruct( pp, bLBEClass ); + //ChooseLBEsForSoldierCreateStruct( pp, bLBEClass ); // SANDRO - removed duplicated ChooseLocationSpecificGearForSoldierCreateStruct( pp ); RandomlyChooseWhichItemsAreDroppable( pp, bSoldierClass ); @@ -729,147 +1031,7 @@ void ChooseWeaponForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bWeaponC // the weapon class here ranges from 1 to 11, so subtract 1 to get a gun level usGunIndex = SelectStandardArmyGun( (UINT8) (bWeaponClass - 1)); - //sniper rifles get sniper scopes - if ( Weapon[usGunIndex].ubWeaponType == GUN_SN_RIFLE ) - { - usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass,TRUE); - if ( usScopeIndex == 0 ) - { - // find any one that works - usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass,FALSE); - } - } - //Choose attachment - if( bAttachClass && ( fAttachment )) - { - usAttachIndex = PickARandomAttachment(ATTACHMENTS,usGunIndex,bAttachClass,FALSE); - - if ( Item[usGunIndex].defaultattachment > 0 ) - { - - if ( Item[usGunIndex].defaultattachment == usAttachIndex ) - usAttachIndex = 0; - else - { - //check for incompatibilities - for(i = 0;i 0 ) - { - if ( Item[usGunIndex].defaultattachment == usScopeIndex ) - usScopeIndex = 0; - else - { - //check for incompatibilities w/scope - for(i = 0;i 0 ) - { - //check for incompatibilities with scope - for(i = 0;i 0 && Random(2) ) - { - usAttachIndex2 = PickARandomAttachment(ATTACHMENTS,usGunIndex,bAttachClass,FALSE); - - //check for incompatibilities with 1st attachment - for(i = 0;iusItemClass == IC_MISC && pItem->ubCoolness <= bAttachClass && ValidAttachment( i, usGunIndex ) ) - // usNumMatches++; - // } - // if( !usNumMatches ) - // { - // bAttachClass--; - // } - //} - //if( usNumMatches ) - //{ - - // else - // { - // usRandom = (UINT16)Random( usNumMatches ); - // for( i = 0; i < MAXITEMS; i++ ) - // { - // if ( Item[i].usItemClass == 0 ) - // break; - // pItem = &Item[ i ]; - // if( pItem->usItemClass == IC_MISC && pItem->ubCoolness <= bAttachClass && ) - // { - // if( usRandom ) - // usRandom--; - // else - // { - // usAttachIndex = i; - // break; - // } - // } - // } - // } - //} -#endif //obsoleteCode - } + //WarmSteel - Removed the attachment check here. why check twice anyway? //Now, we have chosen all of the correct items. Now, we will assign them into the slots. //Because we are dealing with enemies, automatically give them full ammo in their weapon. switch( pp->ubSoldierClass ) @@ -907,34 +1069,135 @@ void ChooseWeaponForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bWeaponC pp->Inv[ HANDPOS ][0]->data.ubImprintID = (NO_PROFILE + 1); } - if( (pp->Inv[ HANDPOS ].fFlags & OBJECT_NO_OVERWRITE) ) - { //slot locked, so don't add any attachments to it! - usAttachIndex = 0; - } - DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ChooseWeaponForSoldierCreateStruct: Gun Created"); + if( !(pp->Inv[ HANDPOS ].fFlags & OBJECT_NO_OVERWRITE) ) + { //slot not locked, so add attachments to it + if(UsingNewAttachmentSystem()==false){ + if ( Weapon[usGunIndex].ubWeaponType == GUN_SN_RIFLE ) + { + usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass,TRUE); + if ( usScopeIndex == 0 ) + { + // find any one that works + usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass,FALSE); + } + } - if( usScopeIndex > 0 && ValidItemAttachment(&(pp->Inv[ HANDPOS ]),usScopeIndex,TRUE,FALSE) ) - { - DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create Scope %d",usScopeIndex)); - CreateItem( usScopeIndex, 100, &gTempObject ); - gTempObject.fFlags |= OBJECT_UNDROPPABLE; - pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject ); - } - if( usAttachIndex > 0 && ValidItemAttachment(&(pp->Inv[ HANDPOS ]),usAttachIndex,TRUE,FALSE)) - { - DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create Attachment %d",usAttachIndex)); - CreateItem( usAttachIndex, 100, &gTempObject ); - gTempObject.fFlags |= OBJECT_UNDROPPABLE; - pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject ); - } - if( usAttachIndex2 > 0 && ValidItemAttachment(&(pp->Inv[ HANDPOS ]),usAttachIndex2,TRUE,FALSE)) - { - DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create 2nd Attachment %d",usAttachIndex2)); - CreateItem( usAttachIndex2, 100, &gTempObject ); - gTempObject.fFlags |= OBJECT_UNDROPPABLE; - pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject ); + if( ValidItemAttachment(&(pp->Inv[ HANDPOS ]),usScopeIndex,TRUE,FALSE) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create Scope %d",usScopeIndex)); + CreateItem( usScopeIndex, 100, &gTempObject ); + gTempObject.fFlags |= OBJECT_UNDROPPABLE; + pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject, FALSE ); + } else { + usScopeIndex = 0; + } + + //Choose attachment + if( bAttachClass && ( fAttachment )) + usAttachIndex = PickARandomAttachment(ATTACHMENTS,usGunIndex,bAttachClass,FALSE); + + if( ValidItemAttachment(&(pp->Inv[ HANDPOS ]),usAttachIndex,TRUE,FALSE)) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create Attachment %d",usAttachIndex)); + CreateItem( usAttachIndex, 100, &gTempObject ); + gTempObject.fFlags |= OBJECT_UNDROPPABLE; + pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject, FALSE ); + } else { + usAttachIndex = 0; + } + + //check for chance of second attachment + if ( ( bAttachClass - Item[usAttachIndex].ubCoolness ) > 0 && Random(2) ) + usAttachIndex2 = PickARandomAttachment(ATTACHMENTS,usGunIndex,bAttachClass,FALSE); + + + if( ValidItemAttachment(&(pp->Inv[ HANDPOS ]),usAttachIndex2,TRUE,FALSE)) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create 2nd Attachment %d",usAttachIndex2)); + CreateItem( usAttachIndex2, 100, &gTempObject ); + gTempObject.fFlags |= OBJECT_UNDROPPABLE; + pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject, FALSE ); + } else { + usAttachIndex2 = 0; + } + } else { + //The total pool of coolness we have for all the attachments. If fAttachment is true, the chance of getting an attachment is boosted. + INT8 iMiscAttachmentChance = 40 + (fAttachment * 20); + //Add a value equal to the avarage amount of attachments that will be on this gun. + //Because the guns scope does not subtract from this value, -1. + INT16 iAttachmentCoolnessPool = (bAttachClass * (gGameExternalOptions.iMaxEnemyAttachments-1) * iMiscAttachmentChance) / 100; + + BOOLEAN fFoundValidAttachment = FALSE; + BOOLEAN fRandomPassed = FALSE; + BOOLEAN fGetMatchingCoolness = FALSE; + UINT16 usTryCount = 0; + + //When using NAS, we want more attachments. + if ( Weapon[usGunIndex].ubWeaponType == GUN_SN_RIFLE ) + { + usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass,TRUE); + if ( usScopeIndex == 0 ) + { + // find any one that works + usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass,FALSE); + } + //Guns should have a fairly good chance of having a scope. Even when they're not sniper rifles. + //They're likely to be crappier, though. + } else if (Chance(75) && fAttachment){ + usScopeIndex = PickARandomAttachment(SCOPE,usGunIndex,bAttachClass-1,FALSE); + } + + if( ValidItemAttachmentSlot(&(pp->Inv[ HANDPOS ]),usScopeIndex, TRUE,FALSE) ) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Create Scope %d",usScopeIndex)); + CreateItem( usScopeIndex, 100, &gTempObject ); + gTempObject.fFlags |= OBJECT_UNDROPPABLE; + pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject, FALSE ); + } + + //Loop for the maximum amount of attachments (-1 because we can already have a scope by here) + //cnt = -1 because we start with ++ing it + for(INT16 cnt = -1; cnt < (gGameExternalOptions.iMaxEnemyAttachments-1); ){ + usTryCount++; + usAttachIndex = 0; + + //Our coolness pool was depleted, we won't find any more attachments anyway. + if(iAttachmentCoolnessPool <= 0) + break; + + //Only move on to the next attachment if 1: we found a good one. 2: randomness decided this attachment won't be. 3: We've exceeded the maximum number of tries. + if(fFoundValidAttachment || !fRandomPassed || usTryCount > 20){ + cnt++; + usTryCount = 0; + fFoundValidAttachment = FALSE; + + //Determine if this attachments deserves to be. + fRandomPassed = Chance(iMiscAttachmentChance); + //Sometimes allow lower grade attachments. + fGetMatchingCoolness = Chance(70); + } + + if (fRandomPassed) + usAttachIndex = PickARandomAttachment(ATTACHMENTS,usGunIndex,bAttachClass,fGetMatchingCoolness); + + if(!usAttachIndex){ + continue; + } + + if( ValidItemAttachmentSlot(&(pp->Inv[ HANDPOS ]),usAttachIndex, TRUE,FALSE)) + { + fFoundValidAttachment = TRUE; + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Created Attachment %d, num: %d",usAttachIndex, cnt)); + CreateItem( usAttachIndex, 100, &gTempObject ); + gTempObject.fFlags |= OBJECT_UNDROPPABLE; + pp->Inv[ HANDPOS ].AttachObject( NULL, &gTempObject, FALSE ); + iAttachmentCoolnessPool -= Item[usAttachIndex].ubCoolness; + } + } + } } + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("ChooseWeaponForSoldierCreateStruct: Set bullets")); //set bullets = to magsize including any attachments (c-mag adapters, etc) @@ -1309,30 +1572,72 @@ void ChooseArmourForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bHelmetC //UINT16 i; //INVTYPE *pItem; //UINT16 usRandom; - UINT16 usItem = 0; + UINT16 usItem = 0, usHelmetItem = 0, usVestItem = 0, usLeggingsItem = 0; //UINT16 usNumMatches; -// INT8 bOrigVestClass = bVestClass; + //INT8 bOrigVestClass = bVestClass; + INT8 i; + + //tais: always get any armor... smeagol doesnt like naked people.. + if(gGameExternalOptions.fSoldiersWearAnyArmour) + { + if(bHelmetClass < 1) bHelmetClass = 1; + //search for a non-empty class with items we need + for(i=bHelmetClass;i<=10;i++) + { + usHelmetItem = PickARandomItem(HELMET,i ); + //if we find a non-empty class change to that and break + if(usHelmetItem > 0) + { + bHelmetClass = i; + break; + } + } + if(bVestClass < 1) bVestClass = 1; + //search for a non-empty class with items we need + for(i=bVestClass;i<=10;i++) + { + usVestItem = PickARandomItem(VEST,i ); + //if we find a non-empty class change to that and break + if(usVestItem > 0) + { + bVestClass = i; + break; + } + } + if(bLeggingsClass < 1) bLeggingsClass = 1; + //search for a non-empty class with items we need + for(i=bLeggingsClass;i<=10;i++) + { + usLeggingsItem = PickARandomItem(LEGS,i ); + //if we find a non-empty class change to that and break + if(usLeggingsItem > 0) + { + bLeggingsClass = i; + break; + } + } + } //Madd: added minimum protection of 10 for armours to be used by enemies //Choose helmet if( bHelmetClass ) { - usItem = PickARandomItem(HELMET,bHelmetClass ); - if ( usItem > 0 && Item[usItem].usItemClass == IC_ARMOUR && !(pp->Inv[ HELMETPOS ].fFlags & OBJECT_NO_OVERWRITE) && Armour[ Item[usItem].ubClassIndex ].ubArmourClass == ARMOURCLASS_HELMET ) + if(!gGameExternalOptions.fSoldiersWearAnyArmour) usHelmetItem = PickARandomItem(HELMET,bHelmetClass ); + if ( usHelmetItem > 0 && Item[usHelmetItem].usItemClass == IC_ARMOUR && !(pp->Inv[ HELMETPOS ].fFlags & OBJECT_NO_OVERWRITE) && Armour[ Item[usHelmetItem].ubClassIndex ].ubArmourClass == ARMOURCLASS_HELMET ) { - CreateItem( usItem, (INT8)(70+Random(31)), &(pp->Inv[ HELMETPOS ]) ); + CreateItem( usHelmetItem, (INT8)(70+Random(31)), &(pp->Inv[ HELMETPOS ]) ); pp->Inv[ HELMETPOS ].fFlags |= OBJECT_UNDROPPABLE; // roll to see if he gets an attachment, too. Higher chance the higher his entitled helmet class is - if (( INT8 ) Random( 100 ) < ( 15 * ( bHelmetClass - Item[usItem].ubCoolness ) ) ) + if (( INT8 ) Random( 100 ) < ( 15 * ( bHelmetClass - Item[usHelmetItem].ubCoolness ) ) ) { - UINT16 usAttachment = PickARandomAttachment(ARMOURATTACHMENT,usItem, bHelmetClass, FALSE); + UINT16 usAttachment = PickARandomAttachment(ARMOURATTACHMENT,usHelmetItem, bHelmetClass, FALSE); if ( usAttachment > 0 ) { CreateItem( usAttachment, (INT8)(70+Random(31)), &gTempObject ); gTempObject.fFlags |= OBJECT_UNDROPPABLE; - pp->Inv[ HELMETPOS ].AttachObject( NULL, &gTempObject ); + pp->Inv[ HELMETPOS ].AttachObject( NULL, &gTempObject, FALSE ); } } @@ -1391,21 +1696,21 @@ void ChooseArmourForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bHelmetC //Choose vest if( bVestClass ) { - usItem = PickARandomItem(VEST,bVestClass ); - if ( usItem > 0 && Item[usItem].usItemClass == IC_ARMOUR && !(pp->Inv[ VESTPOS ].fFlags & OBJECT_NO_OVERWRITE) && Armour[ Item[usItem].ubClassIndex ].ubArmourClass == ARMOURCLASS_VEST ) + if(!gGameExternalOptions.fSoldiersWearAnyArmour) usVestItem = PickARandomItem(VEST,bVestClass ); + if ( usVestItem > 0 && Item[usVestItem].usItemClass == IC_ARMOUR && !(pp->Inv[ VESTPOS ].fFlags & OBJECT_NO_OVERWRITE) && Armour[ Item[usVestItem].ubClassIndex ].ubArmourClass == ARMOURCLASS_VEST ) { - CreateItem( usItem, (INT8)(70+Random(31)), &(pp->Inv[ VESTPOS ]) ); + CreateItem( usVestItem, (INT8)(70+Random(31)), &(pp->Inv[ VESTPOS ]) ); pp->Inv[ VESTPOS ].fFlags |= OBJECT_UNDROPPABLE; // roll to see if he gets a CERAMIC PLATES, too. Higher chance the higher his entitled vest class is - if (( INT8 ) Random( 100 ) < ( 15 * ( bVestClass - Item[usItem].ubCoolness ) ) ) + if (( INT8 ) Random( 100 ) < ( 15 * ( bVestClass - Item[usVestItem].ubCoolness ) ) ) { - UINT16 usAttachment = PickARandomAttachment(ARMOURATTACHMENT,usItem, bVestClass, FALSE); + UINT16 usAttachment = PickARandomAttachment(ARMOURATTACHMENT,usVestItem, bVestClass, FALSE); if ( usAttachment > 0 ) { CreateItem( usAttachment, (INT8)(70+Random(31)), &gTempObject ); gTempObject.fFlags |= OBJECT_UNDROPPABLE; - pp->Inv[ VESTPOS ].AttachObject( NULL, &gTempObject ); + pp->Inv[ VESTPOS ].AttachObject( NULL, &gTempObject, FALSE ); } } @@ -1485,21 +1790,21 @@ void ChooseArmourForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bHelmetC //Choose Leggings if( bLeggingsClass ) { - usItem = PickARandomItem(LEGS,bLeggingsClass); - if ( usItem > 0 && Item[usItem].usItemClass == IC_ARMOUR && !(pp->Inv[ LEGPOS ].fFlags & OBJECT_NO_OVERWRITE) && Armour[ Item[usItem].ubClassIndex ].ubArmourClass == ARMOURCLASS_LEGGINGS ) + if(!gGameExternalOptions.fSoldiersWearAnyArmour) usLeggingsItem = PickARandomItem(LEGS,bLeggingsClass ); + if ( usLeggingsItem > 0 && Item[usLeggingsItem].usItemClass == IC_ARMOUR && !(pp->Inv[ LEGPOS ].fFlags & OBJECT_NO_OVERWRITE) && Armour[ Item[usLeggingsItem].ubClassIndex ].ubArmourClass == ARMOURCLASS_LEGGINGS ) { - CreateItem( usItem, (INT8)(70+Random(31)), &(pp->Inv[ LEGPOS ]) ); + CreateItem( usLeggingsItem, (INT8)(70+Random(31)), &(pp->Inv[ LEGPOS ]) ); pp->Inv[ LEGPOS ].fFlags |= OBJECT_UNDROPPABLE; // roll to see if he gets an attachment, too. Higher chance the higher his entitled Leggings class is - if (( INT8 ) Random( 100 ) < ( 15 * ( bLeggingsClass - Item[usItem].ubCoolness ) ) ) + if (( INT8 ) Random( 100 ) < ( 15 * ( bLeggingsClass - Item[usLeggingsItem].ubCoolness ) ) ) { - UINT16 usAttachment = PickARandomAttachment(ARMOURATTACHMENT,usItem, bLeggingsClass, FALSE); + UINT16 usAttachment = PickARandomAttachment(ARMOURATTACHMENT,usLeggingsItem, bLeggingsClass, FALSE); if ( usAttachment > 0 ) { CreateItem( usAttachment, (INT8)(70+Random(31)), &gTempObject ); gTempObject.fFlags |= OBJECT_UNDROPPABLE; - pp->Inv[ LEGPOS ].AttachObject( NULL, &gTempObject ); + pp->Inv[ LEGPOS ].AttachObject( NULL, &gTempObject, FALSE); } } @@ -2137,7 +2442,8 @@ void RandomlyChooseWhichItemsAreDroppable( SOLDIERCREATE_STRUCT *pp, INT8 bSoldi UINT32 uiRandomValue = 0; //Madd -if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) +//if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) // EXTERNILIZED TO THE INI INSTEAD - SANDRO +if ( gGameOptions.fEnemiesDropAllItems ) { ENEMYAMMODROPRATE = 100; ENEMYGRENADEDROPRATE = 100; @@ -2253,7 +2559,8 @@ else usItem = pp->Inv[ i ].usItem; //TODO: someday maybe pp->Inv[i].fFlags &= ~ITEM_REPAIRABLE; - if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) + //if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) // EXTERNILIZED TO THE INI INSTEAD - SANDRO + if ( gGameOptions.fEnemiesDropAllItems ) { // WANNE: "Drop all" should mean "Drop all" /* @@ -2294,7 +2601,8 @@ else } } - if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) + //if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) // EXTERNILIZED TO THE INI INSTEAD - SANDRO + if ( gGameOptions.fEnemiesDropAllItems ) return; @@ -2925,12 +3233,14 @@ void ReplaceExtendedGuns( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass ) CreateItem( usNewGun, (*pObj)[0]->data.gun.bGunStatus, &gTempObject ); gTempObject.fFlags = (*pObj).fFlags; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - gTempObject.AttachObject(0, &(*iter)); - } + //init attachments + InitItemAttachments(pObj); - //for any old attachments that don't fit on the new gun, place or drop them - RemoveProhibitedAttachments(0, &gTempObject, usNewGun); + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()){ + gTempObject.AttachObject(0, &(*iter), FALSE); + } + } //copy it over *pObj = gTempObject; @@ -3173,7 +3483,7 @@ UINT16 PickARandomAttachment(UINT8 typeIndex, UINT16 usBaseItem, UINT8 maxCoolne return 0; // check up to 10 times for an item with a matching coolness - for (int i=0; i < 10;i++) + for (int i=0; i < 50; i++) { //if we've already tried more times then there are items + 1, limit the looping to speed up the game, and just plain give up if ( i > gArmyItemChoices[ typeIndex ].ubChoices ) @@ -3182,14 +3492,23 @@ UINT16 PickARandomAttachment(UINT8 typeIndex, UINT16 usBaseItem, UINT8 maxCoolne uiChoice = Random(gArmyItemChoices[ typeIndex ].ubChoices); usItem = gArmyItemChoices[ typeIndex ].bItemNo[ uiChoice ]; - if ( usItem >= 0 && Item[usItem].ubCoolness <= maxCoolness && ValidAttachment(usItem,usBaseItem)) + BOOLEAN fDefaultAttachment = FALSE; + for(UINT8 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS; cnt++){ + if(Item[usBaseItem].defaultattachments[cnt] == 0) + break; + + if(Item[usBaseItem].defaultattachments[cnt] == usItem){ + fDefaultAttachment = TRUE; + } + } + if ( usItem >= 0 && Item[usItem].ubCoolness <= maxCoolness && ValidAttachment(usItem,usBaseItem) && !fDefaultAttachment) { // pick a default item in case we don't find anything with a matching coolness, but pick the coolest item we can find if ( defaultItem == 0 || Item[usItem].ubCoolness > Item[defaultItem].ubCoolness ) defaultItem = usItem; // found something with the right coolness - if ( Item[usItem].ubCoolness == maxCoolness || !getMatchingCoolness ) + if ( (Item[usItem].ubCoolness >= maxCoolness-2) || !getMatchingCoolness ) { // DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("PickARandomAttachment: baseItem = %d, usItem = %d",usBaseItem, usItem)); if (ItemIsLegal(usItem)) diff --git a/Tactical/Item Types.cpp b/Tactical/Item Types.cpp index 2091a29b..b692a824 100644 --- a/Tactical/Item Types.cpp +++ b/Tactical/Item Types.cpp @@ -201,10 +201,11 @@ BOOLEAN MoveItemsToActivePockets( SOLDIERTYPE *pSoldier, std::vector& LBES if(pSoldier->inv[i].exists() == false) // No item in this pocket. Place the item. { if((i == CPACKPOCKPOS && uiHandPos == BPACKPOCKPOS) || (i == BPACKPOCKPOS && uiHandPos == CPACKPOCKPOS)) - { - UINT8 newPack = LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo; - UINT8 chkPack = LoadBearingEquipment[Item[pSoldier->inv[i].usItem].ubClassIndex].lbeCombo; - if(newPack == 0 || newPack != chkPack) + { + //DBrot: changed to bitwise comparison + UINT32 newPack = LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo; + UINT32 chkPack = LoadBearingEquipment[Item[pSoldier->inv[i].usItem].ubClassIndex].lbeCombo; + if(newPack == 0 || (newPack & chkPack == 0)) continue; } if(CanItemFitInPosition(pSoldier, &(pSoldier->inv[LBESlots[x]]), i, FALSE)) @@ -470,7 +471,10 @@ LBENODE* OBJECTTYPE::GetLBEPointer(unsigned int index) } } } - return NULL; + //CHRISL: if the LBEArray is empty, we probably need to force the creation of an entry so that future functions don't crash. + //return NULL; + LBEArray.resize(1); + return &(*LBEArray.begin()); } bool OBJECTTYPE::exists() @@ -595,6 +599,7 @@ int OBJECTTYPE::ForceAddObjectsToStack(OBJECTTYPE& sourceObject, int howMany) Assert(sourceObject.exists() == true); usItem = sourceObject.usItem; this->fFlags = sourceObject.fFlags; + //this->usAttachmentSlotIndexVector = sourceObject.usAttachmentSlotIndexVector; } Assert(sourceObject.usItem == usItem); @@ -648,6 +653,7 @@ int OBJECTTYPE::AddObjectsToStack(OBJECTTYPE& sourceObject, int howMany, SOLDIER Assert(sourceObject.exists() == true); usItem = sourceObject.usItem; this->fFlags = sourceObject.fFlags; + //this->usAttachmentSlotIndexVector = sourceObject.usAttachmentSlotIndexVector; } Assert(sourceObject.usItem == usItem); @@ -785,6 +791,7 @@ bool OBJECTTYPE::RemoveObjectAtIndex(unsigned int index, OBJECTTYPE* destObject) destObject->fFlags = fFlags; //handles weight calc and ubNumber too destObject->SpliceData((*this), 1, spliceIter); + //destObject->usAttachmentSlotIndexVector = usAttachmentSlotIndexVector; } else { objectStack.erase(spliceIter); @@ -814,6 +821,18 @@ StackedObjectData* OBJECTTYPE::operator [](const unsigned int index) return &(*iter); } +const StackedObjectData* OBJECTTYPE::operator [](const unsigned int index) const { + StackedObjects::const_iterator iter = objectStack.begin(); + if(index >= objectStack.size()){ + return &(*iter); + } + Assert(index < objectStack.size()); + for (unsigned int x = 0; x < index; ++x) { + ++iter; + } + return &(*iter); +} + //you may have noticed code like this: //pSoldier->pTempObject = (OBJECTTYPE *)MemAlloc( sizeof( OBJECTTYPE ) ); @@ -872,6 +891,71 @@ OBJECTTYPE* StackedObjectData::GetAttachmentAtIndex(UINT8 index) return 0; } +BOOLEAN StackedObjectData::RemoveAttachmentAtIndex(UINT8 index, attachmentList::iterator * returnIter) +{ + attachmentList::iterator iter = attachments.begin(); + for (int x = 0; iter != attachments.end(); ++x, ++iter) { + if(x == index){ + if(UsingNewAttachmentSystem()==true){ + OBJECTTYPE null; + iter = attachments.erase(iter); + if(returnIter){ + *returnIter = attachments.insert(iter, null); + } else { + attachments.insert(iter, null); + } + return TRUE; + } else { + if(returnIter){ + *returnIter = attachments.erase(iter); + } else { + attachments.erase(iter); + } + return TRUE; + } + } + } + return FALSE; +} + +attachmentList::iterator StackedObjectData::RemoveAttachmentAtIter(attachmentList::iterator iter) +{ + if(UsingNewAttachmentSystem()==true){ + OBJECTTYPE null; + iter = attachments.erase(iter); + iter = attachments.insert(iter, null); + return iter; + } else { + iter = attachments.erase(iter); + return iter; + } +} + +BOOLEAN StackedObjectData::AddAttachmentAtIndex(UINT8 index, OBJECTTYPE Attachment) +{ + AssertMsg(UsingNewAttachmentSystem()==true, "Cannot use the AddAttachmentAtIndex function without NAS"); + + attachmentList::iterator iter = attachments.begin(); + for (int x = 0; iter != attachments.end(); ++x, ++iter) { + if(x == index){ + iter = attachments.erase(iter); + attachments.insert(iter, Attachment); + return TRUE; + } + } + return FALSE; +} + +UINT16 StackedObjectData::AttachmentListSize() +{ + UINT16 attachmentSize = 0; + for (attachmentList::iterator iter = attachments.begin(); iter != attachments.end(); ++iter) { + if(iter->exists()){ + attachmentSize++; + } + } + return attachmentSize; +} bool StackedObjectData::operator==(StackedObjectData& compare) { BOOLEAN pass = FALSE; @@ -1138,6 +1222,7 @@ OBJECTTYPE::OBJECTTYPE(const OBJECTTYPE& src) this->fFlags = src.fFlags; this->ubMission = src.ubMission; this->objectStack = src.objectStack; + //this->usAttachmentSlotIndexVector = src.usAttachmentSlotIndexVector; } } @@ -1152,6 +1237,7 @@ OBJECTTYPE& OBJECTTYPE::operator=(const OBJECTTYPE& src) this->fFlags = src.fFlags; this->ubMission = src.ubMission; this->objectStack = src.objectStack; + //this->usAttachmentSlotIndexVector = src.usAttachmentSlotIndexVector; } return *this; } @@ -1258,6 +1344,15 @@ OBJECTTYPE& OBJECTTYPE::operator=(const OLD_OBJECTTYPE_101& src) } } + //CHRISL: Deal with NAS +/* if(UsingNewAttachmentSystem()==true){ + for(int x = 0; x < max(ubNumberOfObjects, 1); ++x) { + std::vector usAttachmentSlotIndexVector = GetItemSlots(this, x); + if((*this)[x]->attachments.size() != usAttachmentSlotIndexVector.size()) + (*this)[x]->attachments.resize(usAttachmentSlotIndexVector.size()); + } + }*/ + RemoveProhibitedAttachments(NULL, this, this->usItem); //just a precaution //ADB ubWeight has been removed, see comments in OBJECTTYPE //this->ubWeight = CalculateObjectWeight(this); diff --git a/Tactical/Item Types.h b/Tactical/Item Types.h index 6a2fa69e..e950dc5b 100644 --- a/Tactical/Item Types.h +++ b/Tactical/Item Types.h @@ -113,6 +113,40 @@ extern int MEDPOCKFINAL ;//= SMALLPOCK1POS;//RESET in initInventory extern int SMALLPOCKFINAL ;//= NUM_INV_SLOTS;//RESET in initInventory #define STACK_SIZE_LIMIT NUM_INV_SLOTS +typedef enum ATTACHMENT_SLOT{ + ATTACHMENTPOINT1 = 0, + ATTACHMENTPOINT2, + ATTACHMENTPOINT3, + ATTACHMENTPOINT4, + ATTACHMENTPOINT5, + ATTACHMENTPOINT6, + ATTACHMENTPOINT7, + ATTACHMENTPOINT8, + ATTACHMENTPOINT9, + ATTACHMENTPOINT10, + ATTACHMENTPOINT11, + ATTACHMENTPOINT12, + ATTACHMENTPOINT13, + ATTACHMENTPOINT14, + ATTACHMENTPOINT15, + ATTACHMENTPOINT16, + ATTACHMENTPOINT17, + ATTACHMENTPOINT18, + ATTACHMENTPOINT19, + ATTACHMENTPOINT20, + ATTACHMENTPOINT21, + ATTACHMENTPOINT22, + ATTACHMENTPOINT23, + ATTACHMENTPOINT24, + ATTACHMENTPOINT25, + ATTACHMENTPOINT26, + ATTACHMENTPOINT27, + ATTACHMENTPOINT28, + ATTACHMENTPOINT29, + ATTACHMENTPOINT30, + ATTACHMENTPOINT31, + NUM_ATTACH_SLOTS +}; #define INVALIDCURS 0 #define QUESTCURS 1 #define PUNCHCURS 2 @@ -152,7 +186,9 @@ extern int SMALLPOCKFINAL ;//= NUM_INV_SLOTS;//RESET in initInventory #define USABLE 10 // minimum work% of items to still be usable #define MAX_OBJECTS_PER_SLOT 255 -#define MAX_ATTACHMENTS 4 +#define MAX_ATTACHMENTS 32 +#define MAX_DEFAULT_ATTACHMENTS 20 +extern UINT16 LAST_SLOT_INDEX; #define MAX_MONEY_PER_SLOT 20000 typedef enum @@ -418,6 +454,10 @@ public: ~StackedObjectData(); void initialize() {attachments.clear(); data.initialize();}; OBJECTTYPE* GetAttachmentAtIndex(UINT8 index); + BOOLEAN RemoveAttachmentAtIndex(UINT8 index, attachmentList::iterator * returnIter = NULL); + attachmentList::iterator RemoveAttachmentAtIter(attachmentList::iterator iter); + BOOLEAN AddAttachmentAtIndex(UINT8 index, OBJECTTYPE pObj); + UINT16 AttachmentListSize(); bool operator==(StackedObjectData& compare); bool operator==(const StackedObjectData& compare)const; @@ -446,6 +486,7 @@ public: // Destructor ~OBJECTTYPE(); + const StackedObjectData* operator[](const unsigned int index) const; StackedObjectData* operator[](const unsigned int index); // Initialize the soldier. @@ -474,9 +515,10 @@ private://these are only helpers for the above functions bool CanStack(OBJECTTYPE& sourceObject, int& numToStack); public: - BOOLEAN AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound = TRUE, UINT8 subObject = 0); - BOOLEAN RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNewObj = NULL, UINT8 subObject = 0); - + BOOLEAN AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound = TRUE, UINT8 subObject = 0, INT32 iItemPos = -1, BOOLEAN fRemoveProhibited = TRUE, std::vector usAttachmentSlotIndexVector = std::vector()); + BOOLEAN AttachObjectOAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound = TRUE, UINT8 subObject = 0); + BOOLEAN AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound = TRUE, UINT8 subObject = 0, INT32 iItemPos = -1, BOOLEAN fRemoveProhibited = TRUE, std::vector usAttachmentSlotIndexVector = std::vector()); + BOOLEAN RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNewObj = NULL, UINT8 subObject = 0, SOLDIERTYPE * pSoldier = NULL, BOOLEAN fForceInseperable = FALSE, BOOLEAN fRemoveProhibited = TRUE); //see comments in .cpp static void DeleteMe(OBJECTTYPE** ppObject); @@ -500,6 +542,7 @@ public: #define SIZEOF_OBJECTTYPE_POD (offsetof(OBJECTTYPE, endOfPOD)) StackedObjects objectStack; +// std::vector usAttachmentSlotIndexVector; //WarmSteel - This holds the slots indexes this weapon has. -- CHRISL: Can't have this here because of item stacks }; extern OBJECTTYPE gTempObject; @@ -540,6 +583,39 @@ extern OBJECTTYPE gTempObject; #define IC_BOBBY_GUN ( IC_GUN | IC_LAUNCHER ) #define IC_BOBBY_MISC ( IC_GRENADE | IC_BOMB | IC_MISC | IC_MEDKIT | IC_KIT | IC_BLADE | IC_THROWING_KNIFE | IC_PUNCH | IC_FACE | IC_LBEGEAR ) +// Chrisl: Define attachment classes +#define AC_DEFAULT1 0x00000001 //1 +#define AC_BARREL 0x00000002 //2 +#define AC_LASER 0x00000004 //4 +#define AC_SIGHT 0x00000008 //8 +#define AC_SCOPE 0x00000010 //16 +#define AC_STOCK 0x00000020 //32 +#define AC_AMMO 0x00000040 //64 +#define AC_INTERNAL 0x00000080 //128 +#define AC_EXTERNAL 0x00000100 //256 +#define AC_UNDERBARREL 0x00000200 //512 +#define AC_GRENADE 0x00000400 //1024 +#define AC_ROCKET 0x00000800 //2048 +#define AC_MISC1 0x00001000 //4096 +#define AC_MISC2 0x00002000 //8192 +#define AC_MISC3 0x00004000 //16384 +#define AC_MISC4 0x00008000 //32768 +#define AC_MISC5 0x00010000 //65536 +#define AC_MISC6 0x00020000 //131072 +#define AC_MISC7 0x00040000 //262144 +#define AC_MISC8 0x00080000 //524288 +#define AC_MISC9 0x00100000 //1048576 +#define AC_MISC10 0x00200000 //2097152 +#define AC_MISC11 0x00400000 //4194304 +#define AC_MISC12 0x00800000 //8388608 +#define AC_MISC13 0x01000000 //16777216 +#define AC_MISC14 0x02000000 //33554432 +#define AC_MISC15 0x04000000 //67108864 +#define AC_MISC16 0x08000000 //134217728 +#define AC_MISC17 0x10000000 //268435456 +#define AC_MISC18 0x20000000 //536870912 +#define AC_MISC19 0x40000000 //1073741824 +#define AC_MISC20 0x80000000 //2147483648 // replaces candamage //#define ITEM_DAMAGEABLE 0x0001 @@ -585,9 +661,26 @@ extern OBJECTTYPE gTempObject; //#define EXPLOSIVE_GUN( x ) ( x == ROCKET_LAUNCHER || x == TANK_CANNON || x == RPG7 ) +// HEADROCK HAM 4: As part of NCTH, over a dozen new variables have been added to the item struct. About the same number +// have also been removed. The new variables relate to the way the new shooting mechanism works, and obviously the ones +// taken out are no longer used anywhere as a result. Note that most of these new variables, the ones having to do with +// the CTH part of the shooting mechanism, come in size-3 arrays. The first item ([0]) represents modifiers given when the +// character is standing. [1] represents crouched, and [2] represents prone. Read more about how this is read from XML +// in the XML-reader formula. +// Removed vars: +// bipod, +// tohitbonus, +// bestlaserrange, +// aimbonus, +// minrangeforaimbonus, +// autofiretohitbonus, +// bursttohitbonus + typedef struct { UINT32 usItemClass; + UINT32 nasAttachmentClass; //CHRISL: Identify the class of attachment + UINT32 nasLayoutClass; UINT16 ubClassIndex; UINT8 ubCursor; INT8 bSoundType; @@ -658,7 +751,8 @@ typedef struct BOOLEAN singleshotrocketlauncher; UINT16 discardedlauncheritem; BOOLEAN brassknuckles; - UINT16 bloodieditem; + //*** ddd UINT16 bloodieditem; + INT16 bloodieditem; BOOLEAN crowbar; BOOLEAN glgrenade; BOOLEAN flakjacket; @@ -719,16 +813,41 @@ typedef struct BOOLEAN scifi; // item only available in scifi mode BOOLEAN newinv; // item only available in new inventory mode + UINT8 ubAttachmentSystem; //Item availability per attachment system: 0 = both, 1 = OAS, 2 = NAS - UINT16 defaultattachment; + UINT16 defaultattachments[MAX_DEFAULT_ATTACHMENTS]; //Need more default attachments, chose an array to do so. (no vector / list just to keep this all plain data) //zilpin: pellet spread patterns externalized in XML INT32 spreadPattern; + // HEADROCK HAM 4: New variable arrays for the New CTH system. + INT16 flatbasemodifier[3]; + INT16 percentbasemodifier[3]; + INT16 flataimmodifier[3]; + INT16 percentaimmodifier[3]; + INT16 percentcapmodifier[3]; + INT16 percenthandlingmodifier[3]; + INT16 percentdropcompensationmodifier[3]; + INT16 maxcounterforcemodifier[3]; + INT16 counterforceaccuracymodifier[3]; + INT16 counterforcefrequencymodifier[3]; + INT16 targettrackingmodifier[3]; + INT16 aimlevelsmodifier[3]; + // HEADROCK HAM 4: New modifiers that do not require a stance array, since they affect the gun objectively, not + // subjectively. + INT16 RecoilModifierX; + INT16 RecoilModifierY; + INT16 PercentRecoilModifier; + INT16 percentaccuracymodifier; + FLOAT scopemagfactor; + FLOAT projectionfactor; + BOOLEAN speeddot; + } INVTYPE; // CHRISL: Added new structures to handle LBE gear and the two new XML files that will be needed to deal // with the IC pockets and the new inventory system. +//DBrot: Increased the LBE combo to 32bit to allow for multiple combos (using a bitwise system) class LBETYPE{ public: LBETYPE(); @@ -737,7 +856,7 @@ public: ~LBETYPE(); UINT16 lbeIndex; UINT32 lbeClass; - UINT8 lbeCombo; + UINT32 lbeCombo; UINT8 lbeFilledSize; char POD; std::vector lbePocketIndex; @@ -1236,7 +1355,43 @@ const INT16 icDefault[NUM_INV_SLOTS] = { #define MAXATTACHMENTS 30000 extern INVTYPE Item[MAXITEMS]; -extern UINT16 Attachment[MAXATTACHMENTS][3]; +extern UINT16 Attachment[MAXATTACHMENTS][4]; + +//WarmSteel - Here we have some definitions for NAS +typedef struct +{ + UINT16 uiSlotIndex; + CHAR16 szSlotName[200]; + UINT32 nasAttachmentClass; + UINT128 nasLayoutClass; + UINT16 usDescPanelPosX; + UINT16 usDescPanelPosY; + BOOLEAN fMultiShot; + BOOLEAN fBigSlot; +} AttachmentSlotStruct; + +extern AttachmentSlotStruct AttachmentSlots[MAXITEMS+1]; + +typedef struct +{ + UINT32 uiIndex; + UINT32 OIV; + UINT32 NIV; + UINT32 OAS; + UINT32 NAS; +} ItemReplacementStruct; + +extern ItemReplacementStruct ItemReplacement[MAXATTACHMENTS]; + +typedef struct +{ + std::vector usItemExclude; + std::vector usItemInclude; + std::vector ubWeaponClass; + std::vector usAddsSlots; + std::vector usRemovesSlots; + +} AlterationStruct; typedef struct { @@ -1302,22 +1457,45 @@ enum IMP_EXPLOSIVE, IMP_MECHANICAL, IMP_MEDICAL, -//SKILLS - IMP_HTH, - IMP_MARTIALARTS, - IMP_NIGHTOPS, +//SKILLS - SANDRO was here + IMP_AUTO_WEAPONS, + IMP_HEAVY_WEAPONS, + IMP_SNIPER, + IMP_RANGER, + IMP_GUNSLINGER, + IMP_MARTIAL_ARTS, + IMP_SQUADLEADER, + IMP_TECHNICIAN, + IMP_DOCTOR, + IMP_AMBIDEXTROUS, + IMP_MELEE, + IMP_THROWING, + IMP_NIGHT_OPS, IMP_STEALTHY, - IMP_PROF_SNIPER, + IMP_ATHLETICS, + IMP_BODYBUILDING, + IMP_DEMOLITIONS, + IMP_TEACHING, + IMP_SCOUTING, IMP_LOCKPICKING, IMP_ELECTRONICS, - IMP_THROWING, - IMP_KNIFING, - IMP_HEAVYWEAPONS, - IMP_AUTOWEAPONS, - IMP_AMBIDEXTROUS, IMP_CAMOUFLAGED, - IMP_TEACHING, - IMP_THIEF, +// DBrot: added seperate choices for experts + IMP_AUTO_WEAPONS_EXP, + IMP_HEAVY_WEAPONS_EXP, + IMP_SNIPER_EXP, + IMP_RANGER_EXP, + IMP_GUNSLINGER_EXP, + IMP_MARTIAL_ARTS_EXP, + IMP_SQUADLEADER_EXP, + IMP_TECHNICIAN_EXP, + IMP_DOCTOR_EXP, + IMP_MELEE_EXP, + IMP_THROWING_EXP, + IMP_NIGHT_OPS_EXP, + IMP_STEALTHY_EXP, + IMP_TEACHING_EXP, + IMP_LOCKPICKING_EXP, MAX_IMP_ITEM_TYPES }; diff --git a/Tactical/Items.cpp b/Tactical/Items.cpp index 354958d9..618ad9c4 100644 --- a/Tactical/Items.cpp +++ b/Tactical/Items.cpp @@ -52,6 +52,8 @@ #include "utilities.h" #include "english.h" #include "debug control.h" + + #include "math.h" #endif //forward declarations of common classes to eliminate includes @@ -65,6 +67,7 @@ void SetNewItem( SOLDIERTYPE *pSoldier, UINT8 ubInvPos, BOOLEAN fNewItem ); extern SOLDIERTYPE *gpItemDescSoldier; extern BOOLEAN fShowMapInventoryPool; +extern UINT32 guiCurrentItemDescriptionScreen; extern BOOLEAN AutoPlaceObjectInInventoryStash( OBJECTTYPE *pItemPtr, INT32 sGridNo ); // weight units are 100g each @@ -538,7 +541,11 @@ AttachmentInfoStruct AttachmentInfo[MAXITEMS+1];// = // { 0, 0 } //}; -UINT16 Attachment[MAXATTACHMENTS][3];// = +//WarmSteel - For the New Attachment System +AttachmentSlotStruct AttachmentSlots[MAXITEMS+1]; +ItemReplacementStruct ItemReplacement[MAXATTACHMENTS]; + +UINT16 Attachment[MAXATTACHMENTS][4];// = //{ // {SILENCER, GLOCK_17}, // {SILENCER, GLOCK_18}, @@ -1219,12 +1226,12 @@ std::vector LBEPocketType; // { /* Knife Pocket */ 5, 0, 1, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } //}; -BOOLEAN ItemIsLegal( UINT16 usItemIndex ) +BOOLEAN ItemIsLegal( UINT16 usItemIndex, BOOLEAN fIgnoreCoolness ) { - //if the user has selected the reduced gun list - if ( Item[usItemIndex].ubCoolness == 0 ) + if ( Item[usItemIndex].ubCoolness == 0 && !fIgnoreCoolness ) return FALSE; + //if the user has selected the reduced gun list if( !gGameOptions.fGunNut ) { //if the item is a gun, or ammo @@ -1255,6 +1262,11 @@ BOOLEAN ItemIsLegal( UINT16 usItemIndex ) return FALSE; } + if(UsingNewAttachmentSystem()==true && Item[usItemIndex].ubAttachmentSystem == 1){ + return FALSE; + } else if(UsingNewAttachmentSystem()==false && Item[usItemIndex].ubAttachmentSystem == 2){ + return FALSE; + } return(TRUE); } @@ -1366,7 +1378,18 @@ UINT8 ItemSlotLimit( OBJECTTYPE * pObject, INT16 bSlot, SOLDIERTYPE *pSoldier, B //doesn't matter what inventory method we are using usItem = pObject->usItem; - if (usItem == MONEY) { + + // WANNE: This is the problem, why silver nuggets don't stuck, because it is not a MONEY item!! + // We have to check the item class (IC_MONEY) and not the item index!!! + //if (usItem == MONEY) + //{ + // //need to have money "stackable" in all slots to trick it into merging + // return 2; + //} + + // WANNE: This fixes the stacking problem of silver nuggets!! + if (Item[usItem].usItemClass == IC_MONEY) + { //need to have money "stackable" in all slots to trick it into merging return 2; } @@ -1463,7 +1486,7 @@ UINT32 MoneySlotLimit( INT8 bSlot ) INT8 FindBestWeaponIfCurrentIsOutOfRange(SOLDIERTYPE * pSoldier, INT8 bCurrentWeaponIndex, UINT16 bWantedRange) { //assuming current weapon is in the handpos - if (GunRange(&pSoldier->inv[bCurrentWeaponIndex]) >= bWantedRange) + if (GunRange(&pSoldier->inv[bCurrentWeaponIndex], pSoldier) >= bWantedRange) // SANDRO - added argument { //our current weapon is good enough return( bCurrentWeaponIndex ); @@ -1480,7 +1503,7 @@ INT8 FindBestWeaponIfCurrentIsOutOfRange(SOLDIERTYPE * pSoldier, INT8 bCurrentWe //if this is a weapon if (Item[pSoldier->inv[bLoop].usItem].usItemClass & (IC_WEAPON | IC_THROWN) && pSoldier->inv[bLoop].exists() == true) { - range = GunRange(&pSoldier->inv[bLoop]); + range = GunRange(&pSoldier->inv[bLoop], pSoldier); // SANDRO - added argument if (range >= bWantedRange) { if (bestWeaponThatMeetsRange == 0) @@ -1796,11 +1819,25 @@ INT8 FindThrowableGrenade( SOLDIERTYPE * pSoldier ) return( NO_SLOT ); } +INT16 FindAttachmentSlot( OBJECTTYPE* pObj, UINT16 usItem, UINT8 subObject) +{ + if(UsingNewAttachmentSystem()==false || pObj->exists() == false) + return -1; + + UINT8 loop = 0; + for(attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); iter++, loop++){ + if(iter->exists() && iter->usItem == usItem) + return loop; + } + + return -1; +} + OBJECTTYPE* FindAttachment( OBJECTTYPE * pObj, UINT16 usItem, UINT8 subObject ) { if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) { - if (iter->usItem == usItem) + if (iter->usItem == usItem && iter->exists()) { return &(*iter); } @@ -1813,7 +1850,7 @@ OBJECTTYPE* FindAttachmentByClass( OBJECTTYPE * pObj, UINT32 uiItemClass, UINT8 { if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) { - if (Item[iter->usItem].usItemClass == uiItemClass) + if (Item[iter->usItem].usItemClass == uiItemClass && iter->exists()) { return &(*iter); } @@ -1864,7 +1901,7 @@ OBJECTTYPE* FindLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon ) { if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (ValidLaunchable( iter->usItem, usWeapon)) + if (ValidLaunchable( iter->usItem, usWeapon) && iter->exists()) { return &(*iter); } @@ -1874,12 +1911,45 @@ OBJECTTYPE* FindLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon ) return( 0 ); } +//CHRISL: This function attempts to find a legal, single-shot grenade item based on the illegal, multi-shot one we send it +UINT16 FindLegalGrenade(UINT16 usItem) +{ + UINT16 newItem = 0; + UINT16 usClass = Item[usItem].ubClassIndex; + if(UsingNewAttachmentSystem()==false) + return usItem; + for(UINT16 loop = 0; loop < MAXITEMS+1; loop++){ + if(loop == usClass) + continue; + if(Explosive[usClass].ubType == Explosive[loop].ubType && Explosive[usClass].ubDamage == Explosive[loop].ubDamage + && Explosive[usClass].ubStunDamage == Explosive[loop].ubStunDamage && Explosive[usClass].ubRadius == Explosive[loop].ubRadius + && Explosive[usClass].ubVolume == Explosive[loop].ubVolume && Explosive[usClass].ubVolatility == Explosive[loop].ubVolatility + && Explosive[usClass].ubAnimationID == Explosive[loop].ubAnimationID && Explosive[usClass].ubDuration == Explosive[loop].ubDuration + && Explosive[usClass].ubStartRadius == Explosive[loop].ubStartRadius && Explosive[loop].ubMagSize == 1){ + newItem = loop; + break; + } + if(Explosive[loop].uiIndex == 0 && loop > 0) + break; + } + if(newItem > 0){ + for(UINT16 loop = 1; loop < MAXITEMS+1; loop++){ + if(Item[loop].uiIndex == 0) + break; + if(Item[loop].usItemClass & IC_GRENADE && Item[loop].ubClassIndex == newItem){ + return Item[loop].uiIndex; + } + } + } + return usItem; +} + OBJECTTYPE* FindNonSmokeLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon ) { if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (ValidLaunchable( iter->usItem, usWeapon) && Explosive[Item[iter->usItem].ubClassIndex].ubType != EXPLOSV_SMOKE) + if (ValidLaunchable( iter->usItem, usWeapon) && Explosive[Item[iter->usItem].ubClassIndex].ubType != EXPLOSV_SMOKE && iter->exists()) { return &(*iter); } @@ -1896,13 +1966,13 @@ BOOLEAN ItemHasAttachments( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier, UINT8 ite if (pObj->exists() == true) { if(pSoldier != NULL){ for (iter = 0; iter != pObj->objectStack.size(); ++iter) { - if((*pObj)[iter]->attachments.empty() == false){ + if((*pObj)[iter]->AttachmentListSize() > 0){ return TRUE; } } } else{ - if((*pObj)[iter]->attachments.empty() == false){ + if((*pObj)[iter]->AttachmentListSize() > 0){ return TRUE; } } @@ -1985,10 +2055,12 @@ BOOLEAN ValidAttachment( UINT16 usAttachment, UINT16 usItem, UINT8 * pubAPCost ) { if (Attachment[iLoop][1] == usItem) { - if (pubAPCost) { - *pubAPCost = (UINT8)Attachment[iLoop][2]; //Madd: get ap cost of attaching items :) + if((UsingNewAttachmentSystem()==false && Attachment[iLoop][3] != 1) || UsingNewAttachmentSystem()==true) { + if (pubAPCost) { + *pubAPCost = (UINT8)Attachment[iLoop][2]; //Madd: get ap cost of attaching items :) + } + break; } - break; } iLoop++; if (Attachment[iLoop][0] != usAttachment) @@ -2000,19 +2072,212 @@ BOOLEAN ValidAttachment( UINT16 usAttachment, UINT16 usItem, UINT8 * pubAPCost ) return( TRUE ); } -UINT8 AttachmentAPCost( UINT16 usAttachment, UINT16 usItem ) +BOOLEAN ValidAttachment( UINT16 usAttachment, OBJECTTYPE * pObj, UINT8 * pubAPCost, UINT8 subObject, std::vector usAttachmentSlotIndexVector ) +{ + if (pObj->exists() == false) { + return FALSE; + } + + if(UsingNewAttachmentSystem()==true) + { + UINT16 usSlotIndex = 0; + BOOLEAN foundValidAttachment = FALSE; + UINT16 usLoop = 0; + + //It's possible we've entered this function without being passed the usAttachmentSlotIndexVector parameter + if(usAttachmentSlotIndexVector.empty()) + usAttachmentSlotIndexVector = GetItemSlots(pObj); + + //Still no slots means nothing will ever be valid + if(usAttachmentSlotIndexVector.empty()) + return FALSE; + + //Check if the attachment is valid with the main item + foundValidAttachment = (ValidAttachment(usAttachment, pObj->usItem, pubAPCost) || ValidLaunchable(usAttachment, pObj->usItem)); + + //Loop through all attachment points on the main item + for(attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end() && !foundValidAttachment; ++iter) + { + if(iter->exists()) + foundValidAttachment = (ValidAttachment(usAttachment, iter->usItem, pubAPCost) || ValidLaunchable(usAttachment, iter->usItem)); + } + + return ( foundValidAttachment ); + } + else + { + return( ValidAttachment(usAttachment, pObj->usItem, pubAPCost) ); + } +} + +UINT8 AttachmentAPCost( UINT16 usAttachment, UINT16 usItem, SOLDIERTYPE * pSoldier ) // SANDRO - added argument { UINT8 ubAPCost; ValidAttachment( usAttachment, usItem, &ubAPCost); + // SANDRO - STOMP traits - Ambidextrous attaching objects speed bonus + if ( pSoldier != NULL ) + { + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + { + ubAPCost = (UINT8)((ubAPCost * (100 - gSkillTraitValues.ubAMAttachingItemsAPsReduction) / 100) + 0.5); + } + } + return ubAPCost; } +//Also need one with pObj, for the one with usItem is not always correct. +UINT8 AttachmentAPCost( UINT16 usAttachment, OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier, UINT8 subObject, std::vector usAttachmentSlotIndexVector ) +{ + UINT8 ubAPCost; + + ValidAttachment(usAttachment, pObj, &ubAPCost, subObject, usAttachmentSlotIndexVector); + + // SANDRO - STOMP traits - Ambidextrous attaching objects speed bonus + if ( pSoldier != NULL ) + { + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + { + ubAPCost = (UINT8)((ubAPCost * (100 - gSkillTraitValues.ubAMAttachingItemsAPsReduction) / 100) + 0.5); + } + } + + return ubAPCost; +} + +//Determine if this slot can receive this attachment. This is different, in that it may +//be possible to have this attachment on this item, but may already have an attachment +//in the slot we're trying to attach to. +BOOLEAN ValidItemAttachmentSlot( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage, UINT8 subObject, INT16 slotCount, BOOLEAN fIgnoreAttachmentInSlot, OBJECTTYPE ** ppAttachInSlot, std::vector usAttachmentSlotIndexVector) +{ + BOOLEAN fSimilarItems = FALSE, fSameItem = FALSE; + UINT16 usSimilarItem = NOTHING; + INT16 ubSlotIndex = 0; + INT32 iLoop2 = 0; + INT16 sTimesToRun = 0; + UINT8 curSlot = 0; + BOOLEAN foundValidAttachment = FALSE; + + if (pObj->exists() == false) { + return FALSE; + } + + //It's possible we could get here without being sent the usAttachmentSlotIndexVector parameter + if(usAttachmentSlotIndexVector.empty()) + usAttachmentSlotIndexVector = GetItemSlots(pObj, subObject); + + //No slots means nothing will ever be valid, also a slotCount outside this vector will never be valid either. + if(usAttachmentSlotIndexVector.empty() || (INT16)usAttachmentSlotIndexVector.size() <= slotCount) + return FALSE; + + //Search for incompatible attachments + for(int i = 0;iattachments.size() && !foundValidAttachment; curSlot++){ + //Any attachment that is already in this slot will go here. + OBJECTTYPE * pAttachment; + + //Get the current attachment in the slot we're looking at. + pAttachment = (*pObj)[subObject]->GetAttachmentAtIndex(curSlot); + ubSlotIndex = usAttachmentSlotIndexVector[curSlot]; + + //WarmSteel - does this particular slot already hold an item? + if(ppAttachInSlot && pAttachment->exists() ) + *ppAttachInSlot = pAttachment; + + //Search for any valid attachments in this slot + //CHRISL: Valid attachments are determined by the old "ValidItemAttachment" function and comparing the attachment class of the item and slot + if(AttachmentSlots[ubSlotIndex].nasAttachmentClass & Item[usAttachment].nasAttachmentClass && + (ValidItemAttachment(pObj,usAttachment,fAttemptingAttachment,fDisplayMessage,subObject,usAttachmentSlotIndexVector) || + ValidLaunchable(usAttachment, GetAttachedGrenadeLauncher(pObj)) || + ValidLaunchable(usAttachment, pObj->usItem))) + { + foundValidAttachment = TRUE; + } + } + } else { + + OBJECTTYPE * pAttachment; + + pAttachment = (*pObj)[subObject]->GetAttachmentAtIndex((UINT8)slotCount); + + ubSlotIndex = usAttachmentSlotIndexVector[slotCount]; + + //WarmSteel - does this particular slot already hold an item? :( If we have a pAttachInSlot we're trying to switch, so then it doesn't matter. + if(!fIgnoreAttachmentInSlot && pAttachment->exists() && fAttemptingAttachment && (!ppAttachInSlot || Item[pAttachment->usItem].inseparable)){ + //If we have a parameter to return pAttachment to, store it, else the item does not attach to this slot. + fSimilarItems = TRUE; + usSimilarItem = pAttachment->usItem; + } else { + //CHRISL: This should allow attachment swapping even if our attachments can't normally be on the weapon at the same time. + if(slotCount != -1 && pAttachment->exists() && FindAttachmentSlot(pObj, pAttachment->usItem, subObject) == slotCount) + fSimilarItems = FALSE; + + //If we have an item to return the existing attachment to. + if(ppAttachInSlot && pAttachment->exists()) + *ppAttachInSlot = pAttachment; + + //Search for any valid attachments in this slot + //CHRISL: Valid attachments are determined by the old "ValidItemAttachment" function and comparing the attachment class of the item and slot + if(AttachmentSlots[ubSlotIndex].nasAttachmentClass & Item[usAttachment].nasAttachmentClass && + (ValidItemAttachment(pObj,usAttachment,FALSE,FALSE,subObject,usAttachmentSlotIndexVector) || + ValidLaunchable(usAttachment, GetAttachedGrenadeLauncher(pObj)) || + ValidLaunchable(usAttachment, pObj->usItem))) + { + foundValidAttachment = TRUE; + } + } + } + + if(fAttemptingAttachment){ + if (fSimilarItems) + { + if(fDisplayMessage) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, Message[ STR_CANT_USE_TWO_ITEMS ], ItemNames[ usSimilarItem ], ItemNames[ usAttachment ] ); + return( FALSE ); + } + else if (fSameItem) + { + if (fDisplayMessage) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, Message[ STR_ATTACHMENT_ALREADY ] ); + return( FALSE ); + } + else if ( !foundValidAttachment && fDisplayMessage && !ValidMerge( usAttachment, pObj->usItem ) ) + { + //We don't want a message if we might be merging this little thingey later. + //well, maybe the player thought he could + CHAR16 zTemp[ 100 ]; + + swprintf( zTemp, Message[ STR_CANNOT_ATTACH_SLOT ], ItemNames[ usAttachment ] ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, zTemp ); + } + } + + return( foundValidAttachment ); +} + //Determine if this item can receive this attachment. This is different, in that it may //be possible to have this attachment on this item, but may already have an attachment on //it which doesn't work simultaneously with the new attachment (like a silencer and duckbill). -BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage, UINT8 subObject ) +BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage, UINT8 subObject, std::vector usAttachmentSlotIndexVector ) { BOOLEAN fSameItem = FALSE, fSimilarItems = FALSE; UINT16 usSimilarItem = NOTHING; @@ -2020,10 +2285,10 @@ BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAt if (pObj->exists() == false) { return FALSE; } - if ( !ValidAttachment( usAttachment, pObj->usItem ) ) + if ( !ValidAttachment( usAttachment, pObj, NULL, subObject, usAttachmentSlotIndexVector ) ) { // check for an underslung grenade launcher attached to the gun - if ( (IsGrenadeLauncherAttached ( pObj ) ) && ValidLaunchable( usAttachment, GetAttachedGrenadeLauncher( pObj ) ) ) + if ( (IsGrenadeLauncherAttached ( pObj, subObject ) ) && ValidLaunchable( usAttachment, GetAttachedGrenadeLauncher( pObj ) ) ) { return ( TRUE ); /* @@ -2068,6 +2333,12 @@ BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAt for(int i = 0;iattachments.begin(); iter != (*this)[index]->attachments.end(); ++iter) { - weight += CalculateObjectWeight(&(*iter)); + if(iter->exists()){ + weight += CalculateObjectWeight(&(*iter)); + } } // add in weight of ammo @@ -2690,6 +2969,12 @@ UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier ) ubStrengthForCarrying += (ubStrengthForCarrying - 80); } + // SANDRO - STOMP traits - Bodybuilding carry weight bonus + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, BODYBUILDING_NT ) ) + { + ubStrengthForCarrying = (ubStrengthForCarrying * (100 + gSkillTraitValues.ubBBCarryWeightBonus) / 100); // plus one third + } + // for now, assume soldiers can carry 1/2 their strength in KGs without penalty. // instead of multiplying by 100 for percent, and then dividing by 10 to account // for weight units being in 10ths of kilos, not kilos... we just start with 10 instead of 100! @@ -2856,7 +3141,7 @@ BOOLEAN ReloadGun( SOLDIERTYPE * pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo INT8 bReloadType; UINT16 usNewAmmoItem; UINT16 usLargestMag; - UINT32 ammoObject = subObject; + UINT32 ammoObject = 0; bAPs = 0; @@ -2886,7 +3171,7 @@ BOOLEAN ReloadGun( SOLDIERTYPE * pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo fEmptyGun = ((*pGun)[subObject]->data.gun.ubGunShotsLeft == 0); fReloadingWithStack = (pAmmo->ubNumberOfObjects > 1); fSameAmmoType = ( (*pGun)[subObject]->data.gun.ubGunAmmoType == Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType ); - fSameMagazineSize = ( Magazine[ Item[ pAmmo->usItem ].ubClassIndex ].ubMagSize == GetMagSize( pGun)); + fSameMagazineSize = ( Magazine[ Item[ pAmmo->usItem ].ubClassIndex ].ubMagSize == GetMagSize( pGun, subObject)); fEnoughAPs = EnoughPoints( pSoldier, GetAPsToReloadGunWithAmmo( pSoldier, pGun, pAmmo, FALSE ), 0,FALSE ); if (fEmptyGun) @@ -2975,32 +3260,32 @@ BOOLEAN ReloadGun( SOLDIERTYPE * pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo } } - else if (Magazine[Item[pAmmo->usItem].ubClassIndex].ubMagSize > GetMagSize(pGun)) + else if (Magazine[Item[pAmmo->usItem].ubClassIndex].ubMagSize > GetMagSize(pGun, subObject)) { //MADD MARKER //usNewAmmoItem = pAmmo->usItem - 1; - usNewAmmoItem = FindReplacementMagazine(Weapon[pGun->usItem].ubCalibre ,GetMagSize(pGun),Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType); + usNewAmmoItem = FindReplacementMagazine(Weapon[pGun->usItem].ubCalibre ,GetMagSize(pGun, subObject),Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType); if (bReloadType == RELOAD_TOPOFF) { - ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) - (*pGun)[subObject]->data.gun.ubGunShotsLeft ); + ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun, subObject) - (*pGun)[subObject]->data.gun.ubGunShotsLeft ); } else { - ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) ); + ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun, subObject) ); } } else // mag is smaller than weapon mag { //MADD MARKER //usNewAmmoItem = pAmmo->usItem + 1; - usNewAmmoItem = FindReplacementMagazine(Weapon[pGun->usItem].ubCalibre ,GetMagSize(pGun),Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType); + usNewAmmoItem = FindReplacementMagazine(Weapon[pGun->usItem].ubCalibre ,GetMagSize(pGun, subObject),Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType); if (bReloadType == RELOAD_TOPOFF) { - ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun) - (*pGun)[subObject]->data.gun.ubGunShotsLeft ); + ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun, subObject) - (*pGun)[subObject]->data.gun.ubGunShotsLeft ); } else { - ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun)); + ubBulletsToMove = __min( (*pAmmo)[ammoObject]->data.ubShotsLeft, GetMagSize(pGun, subObject)); } } @@ -3051,7 +3336,7 @@ BOOLEAN ReloadGun( SOLDIERTYPE * pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo // (suppose his inventory is full!) //ADB copying the old ammo to the cursor at any time will screw it up if the cursor ammo is a stack! - if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && !EnoughPoints( pSoldier, (INT8) (bAPs + APBPConstants[AP_PICKUP_ITEM]), 0, FALSE ) + if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && !EnoughPoints( pSoldier, (INT8) (bAPs + GetBasicAPsToPickupItem( pSoldier )), 0, FALSE ) // SANDRO || pAmmo->ubNumberOfObjects > 1) { // try autoplace @@ -3091,7 +3376,7 @@ BOOLEAN ReloadGun( SOLDIERTYPE * pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo } // CHRISL: If we don't completely reload a SwapClips==0 weapon, set the "reload" flag - if(Weapon[pGun->usItem].swapClips == 0 && GetMagSize(pGun) != (*pGun)[0]->data.gun.ubGunShotsLeft) + if(Weapon[pGun->usItem].swapClips == 0 && GetMagSize(pGun, subObject) != (*pGun)[0]->data.gun.ubGunShotsLeft) { (*pGun)[subObject]->data.gun.ubGunState |= GS_WEAPON_BEING_RELOADED; (*pGun)[subObject]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER; @@ -3347,7 +3632,24 @@ BOOLEAN AutoReload( SOLDIERTYPE * pSoldier ) (*pObj)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; (*pObj)[0]->data.gun.ubGunState &= ~GS_WEAPON_BEING_RELOADED; - DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0); + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - SANDRO + if ( gGameOptions.fNewTraitSystem ) + { + // Sniper trait makes chambering a round faster + if (( Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_SN_RIFLE || Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_RIFLE ) && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT )) + DeductPoints(pSoldier, ((Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubSNChamberRoundAPsReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )))/100), 0); + // Ranger trait makes pumping shotguns faster + else if (( Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_SHOTGUN ) && HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + DeductPoints(pSoldier, ((Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubRAPumpShotgunsAPsReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT )))/100), 0); + else + DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0); + } + else + { + DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// PlayJA2Sample( Weapon[ Item[pObj->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); @@ -3374,7 +3676,24 @@ BOOLEAN AutoReload( SOLDIERTYPE * pSoldier ) { (*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; - DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0); + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - SANDRO + if ( gGameOptions.fNewTraitSystem ) + { + // Sniper trait makes chambering a round faster + if (( Weapon[Item[(pObj2)->usItem].ubClassIndex].ubWeaponType == GUN_SN_RIFLE || Weapon[Item[(pObj2)->usItem].ubClassIndex].ubWeaponType == GUN_RIFLE ) && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT )) + DeductPoints(pSoldier, ((Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubSNChamberRoundAPsReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )))/100), 0); + // Ranger trait makes pumping shotguns faster + else if (( Weapon[Item[(pObj2)->usItem].ubClassIndex].ubWeaponType == GUN_SHOTGUN ) && HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + DeductPoints(pSoldier, ((Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubRAPumpShotgunsAPsReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT )))/100), 0); + else + DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0); + } + else + { + DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// PlayJA2Sample( Weapon[ Item[pObj2->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); @@ -3454,7 +3773,7 @@ INT8 GetAttachmentComboMerge( OBJECTTYPE * pObj, UINT8 subObject ) * the Gun Barel Extender, since it would never been tested. */ pAttachment = FindAttachment( pObj, AttachmentComboMerge[ bIndex ].usAttachment[ bAttachLoop ], subObject ); - if ( pAttachment == 0 ) + if ( pAttachment->exists() == false ) { // didn't find something required break; @@ -3462,7 +3781,8 @@ INT8 GetAttachmentComboMerge( OBJECTTYPE * pObj, UINT8 subObject ) } // found everything required? /* 2007-05-27, Sgt_Kolja: Not-found-condition moved from above, otherwise we can only have ONE attachmentCombo per basic item */ - if ( pAttachment ) + //WarmSteel - Added check to see if the resulting item is valid. + if ( pAttachment->exists() && ItemIsLegal(AttachmentComboMerge[bIndex].usResult) ) { return( bIndex ); } @@ -3508,10 +3828,11 @@ void PerformAttachmentComboMerge( OBJECTTYPE * pObj, INT8 bAttachmentComboMerge bNumStatusContributors++; pObj->usItem = AttachmentComboMerge[ bAttachmentComboMerge ].usResult; + RemoveProhibitedAttachments(NULL, pObj, pObj->usItem); (*pObj)[0]->data.objectStatus = (INT8) (uiStatusTotal / bNumStatusContributors ); } -BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound, UINT8 subObject ) +BOOLEAN OBJECTTYPE::AttachObjectOAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound, UINT8 subObject ) { //CHRISL: This makes it impossible to add attachments to objects in a stack. Let's remove this and make this possible. //if ( this->ubNumberOfObjects > 1 ) @@ -3521,12 +3842,12 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme if (pAttachment->exists() == false) { return FALSE; } - if ((*this)[subObject]->attachments.size() >= MAX_ATTACHMENTS) { + if ((*this)[subObject]->attachments.size() >= OLD_MAX_ATTACHMENTS_101) { return FALSE; } //CHRISL: If we're adding a loaded UGL, then we have to make sure there are actually 2 open attachment slots instead of 1 if(Item[pAttachment->usItem].grenadelauncher && (*pAttachment)[0]->attachments.size() > 0) { - if ((*this)[subObject]->attachments.size() >= (MAX_ATTACHMENTS-1)) + if ((*this)[subObject]->attachments.size() >= (OLD_MAX_ATTACHMENTS_101-1)) return FALSE; } @@ -3538,6 +3859,11 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme INT32 iCheckResult; INT8 bAttachInfoIndex = -1, bAttachComboMerge; BOOLEAN fValidLaunchable = FALSE; + UINT16 oldMagSize = 0; + + //CHRISL: This is so we can try to determine if the removed attachment altered our mag size. + if(Item[this->usItem].usItemClass == IC_GUN) + oldMagSize = GetMagSize(this); bool canOnlyAttach1 = false; @@ -3622,7 +3948,7 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme //lalien: added to make a GL/RL work when reloaded manually // the AP costs for reloading GL/RL will be taken from weapons.xml ( wrong place!!! the AP's are deducted in DeleteItemDescriptionBox() ) //if (pAttachmentPosition) { - if(pAttachmentPosition || (pAttachmentPosition == NULL && (*this)[subObject]->attachments.size() < MAX_ATTACHMENTS)){ + if(pAttachmentPosition || (pAttachmentPosition == NULL && (*this)[subObject]->attachments.size() < OLD_MAX_ATTACHMENTS_101)){ //we know we are replacing this attachment if ( Item[ this->usItem ].usItemClass == IC_LAUNCHER || Item[this->usItem].cannon ) { @@ -3680,6 +4006,21 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme } } + //Ammo might have changed after adding an attachment. + if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[subObject]->data.gun.usGunAmmoItem != NONE && (*this)[subObject]->data.gun.ubGunShotsLeft > 0 && oldMagSize != GetMagSize(this, subObject) ) + { + if ( (*this)[subObject]->data.gun.ubGunShotsLeft > GetMagSize(this, subObject) ) + { //Too many rounds, eject ammo + EjectAmmoAndPlace(pSoldier, this, subObject); + } + //CHRISL: We should update the usGunAmmoItem if we've changed the ammo capacity + if((*this)[subObject]->data.gun.usGunAmmoItem != NONE){ + UINT16 usNewAmmoItem; + usNewAmmoItem = FindReplacementMagazine(Weapon[this->usItem].ubCalibre ,GetMagSize(this, subObject),Magazine[Item[(*this)[subObject]->data.gun.usGunAmmoItem].ubClassIndex].ubAmmoType); + (*this)[subObject]->data.gun.usGunAmmoItem = usNewAmmoItem; + } + } + // Check for attachment merge combos here //CHRISL: Only do this if we're looking at a single item. Don't try a combo merge when dealing with a stack @@ -3765,8 +4106,11 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme } StatChange( pSoldier, MECHANAMT, 25, FALSE ); StatChange( pSoldier, WISDOMAMT, 5, FALSE ); - } + // SANDRO - merc records - merging items + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usItemsCombined++; + } //Madd: note that use_item cannot produce two different items!!! so it doesn't use usResult2 @@ -3867,6 +4211,594 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); } break; + case ELECTRONIC_MERGE: + if ( pSoldier ) + { + iCheckResult = SkillCheck( pSoldier, ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK, -30 ); + if ( iCheckResult < 0 ) + { + DamageObj( this, (INT8) -iCheckResult ); + DamageObj( pAttachment, (INT8) -iCheckResult ); + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + return( FALSE ); + } + // grant experience! ... SANDRO - so what?! Grant them already! + StatChange( pSoldier, MECHANAMT, 30, FALSE ); + StatChange( pSoldier, WISDOMAMT, 10, FALSE ); + + // SANDRO - merc records - merging items + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usItemsCombined++; + } + // fall through + case EXPLOSIVE: + if ( ubType == EXPLOSIVE ) /// coulda fallen through + { + if (pSoldier) + { + // requires a skill check, and gives experience + iCheckResult = SkillCheck( pSoldier, ATTACHING_DETONATOR_CHECK, -30 ); + if (iCheckResult < 0) + { + // could have a chance of detonation + // for now, damage both objects + DamageObj( this, (INT8) -iCheckResult ); + DamageObj( pAttachment, (INT8) -iCheckResult ); + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + return( FALSE ); + } + StatChange( pSoldier, EXPLODEAMT, 25, FALSE ); + StatChange( pSoldier, WISDOMAMT, 5, FALSE ); + + // SANDRO - merc records - merging items + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usItemsCombined++; + } + } + // fall through + default: + // the merge will combine the two items + //Madd: usResult2 only works for standard merges->item1 + item2 = item3 + item4 + + //Madd: unload guns after merge if ammo caliber or mag size don't match + if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[subObject]->data.gun.usGunAmmoItem != NONE && (*this)[subObject]->data.gun.ubGunShotsLeft > 0 ) + { + if ( Item[usResult].usItemClass != IC_GUN || Weapon[Item[usResult].ubClassIndex].ubCalibre != Weapon[Item[this->usItem].ubClassIndex].ubCalibre || (*this)[subObject]->data.gun.ubGunShotsLeft > Weapon[Item[usResult].ubClassIndex].ubMagSize ) + { // item types/calibers/magazines don't match, spit out old ammo + EjectAmmoAndPlace(pSoldier, this); + } + } + + RemoveProhibitedAttachments(pSoldier, this, usResult); + + this->usItem = usResult; + if ( ubType != TREAT_ARMOUR ) + { + (*this)[subObject]->data.objectStatus = ((*this)[subObject]->data.objectStatus + (*pAttachment)[0]->data.objectStatus) / 2; + } + + //ADB ubWeight has been removed, see comments in OBJECTTYPE + //this->ubWeight = CalculateObjectWeight( this ); + + if ( usResult2 != NOTHING ) + { + //Madd: usResult2 is what the original attachment/source item turns into + + //Madd: unload guns after merge if ammo caliber or mag size don't match + if ( Item[pAttachment->usItem].usItemClass == IC_GUN && (*pAttachment)[0]->data.gun.usGunAmmoItem != NONE && (*pAttachment)[0]->data.gun.ubGunShotsLeft > 0 ) + { + if ( Item[usResult2].usItemClass != IC_GUN || Weapon[Item[usResult2].ubClassIndex].ubCalibre != Weapon[Item[pAttachment->usItem].ubClassIndex].ubCalibre || (*pAttachment)[0]->data.gun.ubGunShotsLeft > Weapon[Item[usResult2].ubClassIndex].ubMagSize ) + { // item types/calibers/magazines don't match, spit out old ammo + EjectAmmoAndPlace(pSoldier, pAttachment); + } + } + + RemoveProhibitedAttachments(pSoldier, pAttachment, usResult2); + + pAttachment->usItem = usResult2; + if ( ubType != TREAT_ARMOUR ) + { + (*pAttachment)[0]->data.objectStatus = ((*pAttachment)[0]->data.objectStatus + (*this)[subObject]->data.objectStatus) / 2; + } + //ADB ubWeight has been removed, see comments in OBJECTTYPE + //pAttachment->ubWeight = CalculateObjectWeight( pAttachment ); + } + else + pAttachment->RemoveObjectsFromStack(1); + + if (pSoldier && pSoldier->bTeam == gbPlayerNum) + { + pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); + } + break; + } + if ( pSoldier != NULL ) + ApplyEquipmentBonuses(pSoldier); + return( TRUE ); + } + return( FALSE ); +} + +BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound, UINT8 subObject, INT32 iItemPos, BOOLEAN fRemoveProhibited, std::vector usAttachmentSlotIndexVector ) +{ + if(UsingNewAttachmentSystem()==true){ + return( this->AttachObjectNAS(pSoldier, pAttachment, playSound, subObject, iItemPos, fRemoveProhibited, usAttachmentSlotIndexVector ) ); + } else { + return( this->AttachObjectOAS( pSoldier, pAttachment, playSound, subObject) ); + } +} + + +BOOLEAN OBJECTTYPE::AttachObjectNAS( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachment, BOOLEAN playSound, UINT8 subObject, INT32 iItemPos, BOOLEAN fRemoveProhibited, std::vector usAttachmentSlotIndexVector ) +{ + + if (pAttachment->exists() == false) { + return FALSE; + } + + UINT16 usResult, usResult2, ubLimit; + INT8 bLoop; + UINT8 ubType, ubAPCost; + INT32 iCheckResult; + INT8 bAttachInfoIndex = -1, bAttachComboMerge; + BOOLEAN fValidLaunchable = FALSE; + BOOLEAN fValidItemAttachment = FALSE; + INT32 curSlot = 0; + UINT16 oldMagSize = 0; + + //if there is already an attachment of the same type, we want to try swapping / replacing it + OBJECTTYPE* pAttachmentPosition = 0; + //OBJECTTYPE* pAttachInSlot = 0; + + static OBJECTTYPE attachmentObject; + + //CHRISL: This is so we can try to determine if the removed attachment altered our mag size. + if(Item[this->usItem].usItemClass == IC_GUN) + oldMagSize = GetMagSize(this); + + //if this is an attachment or ammo for a launchable item + fValidLaunchable = ValidLaunchable( pAttachment->usItem, this->usItem ); + + //WarmSteel - if uiItemPos is -1, we're not checking for a specific slot, but scrolling through them all. + if(iItemPos == -1){ + + //WarmSteel - repeat this for every slot + for(curSlot = 0; curSlot < (INT32)(*this)[0]->attachments.size(); curSlot++) + { + fValidItemAttachment = ValidItemAttachmentSlot( this, pAttachment->usItem, TRUE, FALSE, subObject, curSlot, 0, 0, usAttachmentSlotIndexVector); + + if(fValidItemAttachment){ + //WarmSteel - apparently we found a attachable slot, exiting here will remember the curSlot + break; + } + } + + //WarmSteel - if we didn't find any good slot, always just attach to the first slot. (because some functions will overrule this one). + //It's basically just a general check so that we NEVER try to attach outside the attachment list range. + if(curSlot == (*this)[subObject]->attachments.size()) + curSlot = 0; + + } else { + //WarmSteel - We know in what slot we're trying to put this, so lets see if we can. + curSlot = iItemPos; + fValidItemAttachment = ValidItemAttachmentSlot( this, pAttachment->usItem, TRUE, playSound, subObject, curSlot, FALSE, &pAttachmentPosition, usAttachmentSlotIndexVector); + //pAttachmentPosition = pAttachInSlot; + // try replacing if possible + } + + //CHRISL: If we don't want to play the sound, it's a good bet we don't want to display any messages either + if (/*fValidLaunchable ||*/ fValidItemAttachment ) + { + if ( pSoldier ) + { + //did the soldier damage it? + bAttachInfoIndex = GetAttachmentInfoIndex( pAttachment->usItem ); + // in-game (not behind the scenes) attachment + if ( bAttachInfoIndex != -1 && AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheck != NO_CHECK ) + { + iCheckResult = SkillCheck( pSoldier, AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheck, AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod ); + if (iCheckResult < 0) + { + // the attach failure damages both items + DamageObj( this, (INT8) -iCheckResult, subObject ); + DamageObj( pAttachment, (INT8) -iCheckResult, subObject ); + + // there should be a quote here! + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + if ( gfInItemDescBox ) + { + //DeleteItemDescriptionBox(); + } + return( FALSE ); + } + } + + if (fValidItemAttachment && playSound ) // not launchable + { + // attachment sounds + if ( Item[ this->usItem ].usItemClass & IC_WEAPON ) + { + PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + else if ( Item[ this->usItem ].usItemClass & IC_ARMOUR ) + { + PlayJA2Sample( ATTACH_CERAMIC_PLATES, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + else if ( Item[ this->usItem ].usItemClass & IC_BOMB ) + { + PlayJA2Sample( ATTACH_DETONATOR, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + } + } + + /* //NAS doesn't care about single attachments. + if (pAttachmentPosition) { + if (canOnlyAttach1 == true) { + if(pAttachment->ubNumberOfObjects > 1) + { + //We don't want to inadvertantly load two rounds during a swap so don't allow a swap if we're holding a stack + return(FALSE); + } + //we have requested to swap the attachment on the cursor with the current attachment + SwapObjs(pAttachmentPosition,pAttachment); + return(TRUE); + } + }*/ + + //ADB moved after skill check! + //lalien: added to make a GL/RL work when reloaded manually + // the AP costs for reloading GL/RL will be taken from weapons.xml ( wrong place!!! the AP's are deducted in DeleteItemDescriptionBox() ) + + //we know we are replacing this attachment + if ( Item[ this->usItem ].usItemClass == IC_LAUNCHER || Item[this->usItem].cannon ) + { + if ( fValidLaunchable ) + { + (*this)[subObject]->data.gun.usGunAmmoItem = pAttachment->usItem; + //we have reloaded a launchable, so the ammo is gone from the original object + } + } + + /* //WarmSteel - splice won't work with attachments anymore, because of the null attachments. Replaced this function somewhere lower, because it needs to be done after the attaching of the GL. + //Unfortunately this must come before any attachment swap + if (Item[pAttachment->usItem].grenadelauncher && gGameOptions.ubAttachmentSystem == ATTACHMENT_OLD) + { + // transfer any attachments from the grenade launcher to the gun + (*this)[subObject]->attachments.splice((*this)[subObject]->attachments.begin(), (*pAttachment)[0]->attachments, + (*pAttachment)[0]->attachments.begin(), (*pAttachment)[0]->attachments.end()); + }*/ + + //WarmSteel - Attachment swapping prevents multiple objects that are the same to be attached. + //This takes away freedom, which is bad. This is why I turned it off in NAS (If you want to turn it back on, it also doesn't work properly because it needs to swap xml slot indexes aswell). + if (pAttachmentPosition->exists()) { + //we are swapping the attachments, and we know we do NOT need to worry about attachment stack size + //CHRISL: Actually, we do need to worry about attachment stack size since we might have a stack in our cursor. + // Rather then doing a simple swap, try moving the existing attachment to our cursor stack, then attach one item + // from the cursor stack. + + //CHRISL: Try to replace illegal IC_GRENADE items with legal ones + if(!ItemIsLegal(pAttachment->usItem) && Item[pAttachment->usItem].usItemClass & IC_GRENADE){ + OBJECTTYPE* newAttachment = new OBJECTTYPE; + UINT16 newItem; + newItem = FindLegalGrenade(pAttachment->usItem); + if(newItem != pAttachment->usItem){ + CreateItem(newItem, 100, newAttachment); + (*pAttachment)[0]->data.objectStatus -= (INT16)(100/Weapon[this->usItem].ubMagSize); + if((*pAttachment)[0]->data.objectStatus <= 0 ) + pAttachment->RemoveObjectsFromStack(1); + newAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1); + } else { + pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1); + } + } else { + pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1); + } + if(pAttachment->ubNumberOfObjects > 0){ + if (pSoldier) { + if ( !AutoPlaceObject( pSoldier, pAttachmentPosition, FALSE ) ) + { // put it on the ground + AddItemToPool( pSoldier->sGridNo, pAttachmentPosition, 1, pSoldier->pathing.bLevel, 0 , -1 ); + } + } + } else { + pAttachment->AddObjectsToStack(*pAttachmentPosition,-1,pSoldier,NUM_INV_SLOTS,MAX_OBJECTS_PER_SLOT); + } + *pAttachmentPosition = attachmentObject; + + (*this)[subObject]->AddAttachmentAtIndex(curSlot, attachmentObject); + + //backup the original attachment + //attachmentObject = *pAttachmentPosition; + + //place the new one + //*pAttachmentPosition = *pAttachment; + + //whatever pAttachment pointed to is now the original attachment + //*pAttachment = attachmentObject; + } + else { + //it's a new attachment + + //pAttachment could have any number of objects, they have all been moved over + //CHRISL: This doesn't work. What if we have a stack of objects in the cursor? We don't want the whole + // stack to be attached + //(*this)[subObject]->attachments.push_back(*pAttachment); + //DeleteObj(pAttachment); + //CHRISL: Try to replace illegal IC_GRENADE items with legal ones + if(!ItemIsLegal(pAttachment->usItem) && Item[pAttachment->usItem].usItemClass & IC_GRENADE){ + OBJECTTYPE* newAttachment = new OBJECTTYPE; + UINT16 newItem; + newItem = FindLegalGrenade(pAttachment->usItem); + if(newItem != pAttachment->usItem){ + CreateItem(newItem, 100, newAttachment); + (*pAttachment)[0]->data.objectStatus -= (INT16)(100/Weapon[this->usItem].ubMagSize); + if((*pAttachment)[0]->data.objectStatus <= 0 ) + pAttachment->RemoveObjectsFromStack(1); + newAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1); + } else { + pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1); + } + } else { + pAttachment->MoveThisObjectTo(attachmentObject,1,pSoldier,NUM_INV_SLOTS,1); + } + + //WarmSteel - Because we want every attachment to stay in place in NAS, we must first delete the "null" attachment, then insert the new one. + //We know this attachment slot has a non-null object, otherwise ValidItemAttachmentSlot would not have returned true and we would not be here. + (*this)[subObject]->AddAttachmentAtIndex(curSlot, attachmentObject); + } + + + //Ammo might have changed after adding an attachment. + if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[subObject]->data.gun.usGunAmmoItem != NONE && (*this)[subObject]->data.gun.ubGunShotsLeft > 0 && oldMagSize != GetMagSize(this, subObject) ) + { + if ( (*this)[subObject]->data.gun.ubGunShotsLeft > GetMagSize(this, subObject) ) + { //Too many rounds, eject ammo + EjectAmmoAndPlace(pSoldier, this, subObject); + } + //CHRISL: We should update the usGunAmmoItem if we've changed the ammo capacity + if((*this)[subObject]->data.gun.usGunAmmoItem != NONE){ + UINT16 usNewAmmoItem; + usNewAmmoItem = FindReplacementMagazine(Weapon[this->usItem].ubCalibre ,GetMagSize(this, subObject),Magazine[Item[(*this)[subObject]->data.gun.usGunAmmoItem].ubClassIndex].ubAmmoType); + (*this)[subObject]->data.gun.usGunAmmoItem = usNewAmmoItem; + } + } + + //WarmSteel - If we have just attached a UGL, remove it's grenade and put it on the gun itself + //CHRISL: This section of code is also needed it we add any attachment that changes the valid attachments our item can use, so we should run it whenever we + // add an attachment in NAS + //if (FindAttachment_GrenadeLauncher(this)->exists() && attachmentObject.exists()) + if (attachmentObject.exists() && attachmentObject[0]->attachments.size() > 0 && FindAttachment(this, attachmentObject.usItem, subObject)->exists()) + { + //Make sure it's actually on that gun.. + //if(FindAttachment_GrenadeLauncher(this)->usItem == attachmentObject.usItem){ + if(FindAttachment(this, attachmentObject.usItem, subObject)->usItem == attachmentObject.usItem){ + // transfer the grenade from the grenade launcher to the gun + + //To know wether this grenade is valid, we need to correct the slots, because they may have changed when attaching the UGL + //Have to do it here, because from now on we don't need attachmentObject anymore. + //CHRISL: Because we want this function to be useful for more then just UGLs, and because there is the probability that the attaching item will + // give us more attachment points, we need to just remove all attachments, tack them to the end of the attachmentList, and then go through the + // RemoveProhibitedAttachments function to force everything to store in the correct slot + OBJECTTYPE * pGrenade = FindAttachment(this, attachmentObject.usItem, subObject); + for(attachmentList::iterator iter = (*pGrenade)[0]->attachments.begin(); iter != (*pGrenade)[0]->attachments.end(); ++iter){ + if(iter->exists()){ + (*this)[subObject]->attachments.push_back((*iter)); + iter = (*pGrenade)[0]->RemoveAttachmentAtIter(iter); + fRemoveProhibited = TRUE; + } + } +// if(fRemoveProhibited){ +// RemoveProhibitedAttachments(pSoldier, this, this->usItem); +// } + +/* CHRISL: None of this is needed. Instead we strip any attachments from attachmentObject in the above loop. + for(INT16 sSlot = 0; sSlot < (INT16) (*this)[subObject]->attachments.size(); sSlot++){ + OBJECTTYPE * pGrenade = FindAttachmentByClass(FindAttachment_GrenadeLauncher(this), IC_GRENADE, subObject); + if(pGrenade->exists()){ + if(ValidItemAttachmentSlot(this, pGrenade->usItem, 1, 0, 0, sSlot)){ + OBJECTTYPE tempObject; + FindAttachment_GrenadeLauncher(this)->RemoveAttachment(pGrenade,&tempObject,0,0,1,0); + (*this)[subObject]->AddAttachmentAtIndex((UINT8) sSlot, tempObject); + } + } + }*/ + } + } + + //Check if any of the attached items has changed the slots (including the UGL grenade we just added). + if(fRemoveProhibited){ + RemoveProhibitedAttachments(pSoldier, this, this->usItem); + } + // Check for attachment merge combos here + //CHRISL: Only do this if we're looking at a single item. Don't try a combo merge when dealing with a stack + bAttachComboMerge = GetAttachmentComboMerge( this, subObject ); + if ( bAttachComboMerge != -1 ) + { + if(this->ubNumberOfObjects == 1) + { + PerformAttachmentComboMerge( this, bAttachComboMerge ); + if ( bAttachInfoIndex != -1 && AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod < 20 ) + { + StatChange( pSoldier, MECHANAMT, (INT8) ( 20 - AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod ), FALSE ); + StatChange( pSoldier, WISDOMAMT, (INT8) ( 20 - AttachmentInfo[ bAttachInfoIndex ].bAttachmentSkillCheckMod ), FALSE ); + } + } + //CHRISL: If we're looking at a stack, we need to unattach the object we just attached + else if(this->RemoveAttachment(&attachmentObject, pAttachmentPosition, subObject, pSoldier)) + { + pAttachment->AddObjectsToStack(attachmentObject, -1, pSoldier, NUM_INV_SLOTS, MAX_OBJECTS_PER_SLOT); + } + } + + //ADB ubWeight has been removed, see comments in OBJECTTYPE + //this->ubWeight = CalculateObjectWeight( this ); + //ADB ubWeight has been removed, see comments in OBJECTTYPE + //pAttachment->ubWeight = CalculateObjectWeight(pAttachment); + + if ( pSoldier != NULL ) + ApplyEquipmentBonuses(pSoldier); + + return( TRUE ); + } + // check for merges + else if (EvaluateValidMerge( pAttachment->usItem, this->usItem, &usResult, &usResult2, &ubType, &ubAPCost )) + { + //CHRISL: we don't want to try to merge IC_LBEGEAR items that are currently storing items. + if(Item[this->usItem].usItemClass == IC_LBEGEAR) + { + if(this->IsActiveLBE(subObject) == true) + return( FALSE ); + } + //CHRISL: We don't want to do any merges if we're looking at a stack of items, with the exception of combines. + if ( this->ubNumberOfObjects > 1 && ubType != COMBINE_POINTS ) + { + return( FALSE ); + } + if ( ubType != COMBINE_POINTS ) + { + if ( pSoldier ) + { + if ( !EnoughPoints( pSoldier, ubAPCost, 0, TRUE ) ) + { + return( FALSE ); + } + + //lalien: don't charge AP's for reloading a GL/RL ( wrong place!!! the AP's are deducted in DeleteItemDescriptionBox() ) + //if ( IsAGLorRL == FALSE ) + //{ + DeductPoints( pSoldier, ubAPCost, 0 ); + //} + } + } + + switch( ubType ) + { + case USE_ITEM: + case USE_ITEM_HARD: + // the merge will combine the two items + if ( pSoldier ) + { + if ( ubType == USE_ITEM_HARD ) + { + // requires a skill check, and gives experience + iCheckResult = SkillCheck( pSoldier, ATTACHING_SPECIAL_ITEM_CHECK, -30 ); + if (iCheckResult < 0) + { + // could have a chance of detonation + // for now, damage both objects + DamageObj( this, (INT8) -iCheckResult ); + DamageObj( pAttachment, (INT8) -iCheckResult ); + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + return( FALSE ); + } + StatChange( pSoldier, MECHANAMT, 25, FALSE ); + StatChange( pSoldier, WISDOMAMT, 5, FALSE ); + } + + + //Madd: note that use_item cannot produce two different items!!! so it doesn't use usResult2 + + //Madd: unload guns after merge if ammo caliber or mag size don't match + if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[0]->data.gun.usGunAmmoItem != NONE && (*this)[0]->data.gun.ubGunShotsLeft > 0 ) + { + if ( Item[usResult].usItemClass != IC_GUN || Weapon[Item[usResult].ubClassIndex].ubCalibre != Weapon[Item[this->usItem].ubClassIndex].ubCalibre || (*this)[0]->data.gun.ubGunShotsLeft > Weapon[Item[usResult].ubClassIndex].ubMagSize ) + { // item types/calibers/magazines don't match, spit out old ammo + EjectAmmoAndPlace(pSoldier, this); + } + } + + UINT16 usOldItem = this->usItem; + this->usItem = usResult; + + //WarmSteel - Replaced this with one that also checks default attachments, otherwise you could not replace built-in bonuses with default inseperable attachments. + //RemoveProhibitedAttachments(pSoldier, this, usResult); + ReInitMergedItem(pSoldier, this, usOldItem); + + //AutoPlaceObject( pAttachment ); + //ADB ubWeight has been removed, see comments in OBJECTTYPE + //this->ubWeight = CalculateObjectWeight( this ); + if (pSoldier->bTeam == gbPlayerNum) + { + pSoldier->DoMercBattleSound( BATTLE_SOUND_COOL1 ); + } + ApplyEquipmentBonuses(pSoldier); + return TRUE; + } + else + return FALSE; + case COMBINE_POINTS: + // transfer points... + UINT32 combinedAmount; + UINT32 attachmentAmount; + //CHRISL: Treat differently if we're combining money items (other then MONEY) + if(Item[this->usItem].usItemClass != IC_MONEY) + { + if ( Item[ this->usItem ].usItemClass == IC_AMMO ) + { + ubLimit = Magazine[ Item[ this->usItem ].ubClassIndex ].ubMagSize; + } + else + { + ubLimit = 100; + } + + // count down through # of attaching items and add to status of item in position 0 + for (bLoop = 0; bLoop < pAttachment->ubNumberOfObjects; ) + { + //ADB need to watch for overflow here (thus UINT32), and need to cast to UINT8 before adding + combinedAmount = (UINT16)(*this)[subObject]->data.objectStatus + (UINT16)(*pAttachment)[0]->data.objectStatus; + if (combinedAmount <= ubLimit) + { + // consume this one totally and continue + (*this)[subObject]->data.objectStatus = combinedAmount; + pAttachment->RemoveObjectsFromStack(1); + } + else + { + // add part of this one and then we're done + attachmentAmount = (UINT16)(*pAttachment)[0]->data.objectStatus; + attachmentAmount -= (ubLimit - (UINT16)(*this)[subObject]->data.objectStatus); + (*pAttachment)[0]->data.objectStatus = attachmentAmount; + if ((*pAttachment)[0]->data.ubShotsLeft == 0) { + pAttachment->RemoveObjectsFromStack(1); + } + (*this)[subObject]->data.ubShotsLeft = ubLimit; + break; + } + } + } + else + { + ubLimit = MAX_MONEY_PER_SLOT; + combinedAmount = (*this)[subObject]->data.money.uiMoneyAmount + (*pAttachment)[0]->data.money.uiMoneyAmount; + if (combinedAmount <= ubLimit) + { + (*this)[subObject]->data.money.uiMoneyAmount = combinedAmount; + pAttachment->RemoveObjectsFromStack(1); + } + else + { + attachmentAmount = (*pAttachment)[0]->data.money.uiMoneyAmount; + attachmentAmount -= (ubLimit - (*this)[subObject]->data.money.uiMoneyAmount); + (*pAttachment)[0]->data.money.uiMoneyAmount = attachmentAmount; + if((*pAttachment)[0]->data.money.uiMoneyAmount == 0) + { + pAttachment->RemoveObjectsFromStack(1); + } + (*this)[subObject]->data.money.uiMoneyAmount = ubLimit; + break; + } + } + break; + case DESTRUCTION: + // the merge destroyed both items! + this->RemoveObjectsFromStack(1); + pAttachment->RemoveObjectsFromStack(1); + if ( pSoldier ) + { + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + } + break; case ELECTRONIC_MERGE: if ( pSoldier ) { @@ -3915,9 +4847,13 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme } } - RemoveProhibitedAttachments(pSoldier, this, usResult); - + UINT16 usOldItem = this->usItem; this->usItem = usResult; + + //WarmSteel - Replaced this with one that also checks default attachments, otherwise you could not replace built-in bonuses with default inseperable attachments. + //RemoveProhibitedAttachments(pSoldier, this, usResult); + ReInitMergedItem(pSoldier, this, usOldItem); + if ( ubType != TREAT_ARMOUR ) { (*this)[subObject]->data.objectStatus = ((*this)[subObject]->data.objectStatus + (*pAttachment)[0]->data.objectStatus) / 2; @@ -3939,9 +4875,10 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme } } + pAttachment->usItem = usResult2; + RemoveProhibitedAttachments(pSoldier, pAttachment, usResult2); - pAttachment->usItem = usResult2; if ( ubType != TREAT_ARMOUR ) { (*pAttachment)[0]->data.objectStatus = ((*pAttachment)[0]->data.objectStatus + (*this)[subObject]->data.objectStatus) / 2; @@ -3965,35 +4902,442 @@ BOOLEAN OBJECTTYPE::AttachObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pAttachme return( FALSE ); } -void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usItem) -{ - //Madd: remove any prohibited attachments - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (!ValidAttachment(iter->usItem, usItem) && !ValidLaunchable(iter->usItem, usItem) ) - { - if ( !Item[iter->usItem].inseparable ) - { - if (pSoldier) { - if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) ) - { // put it on the ground - AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 ); +//CHRISL: Use this function to sort through Attachments.xml and Launchables.xml +UINT32 SetAttachmentSlotsFlag(OBJECTTYPE* pObj){ + UINT32 uiSlotFlag = 0; + UINT32 uiLoop = 0; + UINT32 fItem; + + if(pObj->exists()==false) + return 0; + while(1) + { + fItem = 0; + if (Attachment[uiLoop][1] == pObj->usItem){ + fItem = Attachment[uiLoop][0]; + } + if (Launchable[uiLoop][1] == pObj->usItem ){ + fItem = Launchable[uiLoop][0]; + } + if(fItem){ // We've found a valid attachment. Set the nasAttachmentSlots flag appropriately + uiSlotFlag |= Item[fItem].nasAttachmentClass; + } + uiLoop++; + if (Attachment[uiLoop][0] == 0 && Launchable[uiLoop][0] == 0){ + // No more attachments to search + break; + } + } + return uiSlotFlag; + +} + +//WarmSteel - This function returns the available item slot indexes in a vector. +std::vector GetItemSlots(OBJECTTYPE* pObj, UINT8 subObject, BOOLEAN fAttachment){ + std::vector tempItemSlots; + std::vector tempAttachmentSlots; + std::vector tempSlots; + UINT8 numSlots = 0; + UINT16 magSize = 0; + UINT32 fItemSlots = 0; + UINT128 fItemLayout = 0; + + if(UsingNewAttachmentSystem()==false || !pObj->exists()) + return tempItemSlots; + + //CHRISL: We no longer need the ItemSlotAssign.xml file but we do still need to figure out which slots an item can have + //Start by searching Attachments.xml and Launchables.xml for valid attachments for the primary object + fItemSlots = SetAttachmentSlotsFlag(pObj); + fItemLayout = Item[pObj->usItem].nasLayoutClass; + if(Item[pObj->usItem].grenadelauncher || Item[pObj->usItem].rocketlauncher) + magSize = GetMagSize(pObj); + + //Next, let's figure out which slots the item gives us access to + if(fItemSlots){ //We don't need to do anything if the item gets no slots + for(UINT8 sClass = 0; sClass < 32; sClass++){ //go through each attachment class and find the slots the item should have + UINT32 uiClass = (UINT32)pow((double)2, (int)sClass); + UINT32 slotSize = tempItemSlots.size(); + if(fItemSlots & uiClass){ //don't bother with this slot if it's not a valid class + for(UINT32 sCount = 1; sCount < MAXITEMS+1; sCount++){ + if(AttachmentSlots[sCount].uiSlotIndex == 0) + break; + if(AttachmentSlots[sCount].nasAttachmentClass & uiClass && AttachmentSlots[sCount].nasLayoutClass & fItemLayout){ //found a slot + if(magSize > 0 && AttachmentSlots[sCount].fMultiShot) + magSize--; + else if(AttachmentSlots[sCount].fMultiShot) + continue; + tempItemSlots.push_back(AttachmentSlots[sCount].uiSlotIndex); + } + } + if(slotSize == tempItemSlots.size()){ //we didn't find a layout specific slot so try to find a default layout slot + for(UINT32 sCount = 1; sCount < MAXITEMS+1; sCount++){ + if(AttachmentSlots[sCount].uiSlotIndex == 0) + break; + if(AttachmentSlots[sCount].nasAttachmentClass & uiClass && AttachmentSlots[sCount].nasLayoutClass == 1){ //found a default slot + tempItemSlots.push_back(AttachmentSlots[sCount].uiSlotIndex); + } } } } - pObj->RemoveAttachment(&(*iter)); - iter = (*pObj)[0]->attachments.begin(); + } + } + + //Now that we've setup tempItemSlots for the main item, let's look at the individual attachments + for(attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter){ + if(iter->exists() && (*iter)[0]->attachments.size() > 0){ + OBJECTTYPE* pAttachment = &(*iter); + tempSlots = GetItemSlots(pAttachment,0,TRUE); + for(UINT8 x = 0; x < tempSlots.size(); x++) + tempAttachmentSlots.push_back(tempSlots[x]); + } + } + + //Now that we have tempAttachmentSlots, put it all together, assuming we're woking on the main item + if(!fAttachment){ + if(tempAttachmentSlots.size() > 0){ //Add attachmentSlots to itemSlots + for(UINT8 attachSlot = 0; attachSlot < tempAttachmentSlots.size(); attachSlot++){ + tempItemSlots.push_back(tempAttachmentSlots[attachSlot]); + } + } + tempSlots = tempItemSlots; + for(std::vector::iterator iter1 = tempSlots.begin(); iter1 != tempSlots.end(); ++iter1){ + BOOLEAN fSlotDuplicated = FALSE; + for(std::vector::iterator iter = tempItemSlots.begin(); iter != tempItemSlots.end();){ + UINT16 i1 = *iter1; + UINT16 i = *iter; + if(i1 == i && !fSlotDuplicated){ + fSlotDuplicated = TRUE; + ++iter; + continue; + } + else if(i1 == i && fSlotDuplicated){ + iter = tempItemSlots.erase(iter); + continue; + } + else + ++iter; + } + } + //If we still have no attachment slots, look through Merges.xml to see if we have merges and use the 4 default slots if we do + //Should we throw on default slots regardless of whether there is an entry in Merges? Ammo doesn't have Merges entries but we still need slots for them. + if(tempItemSlots.size() == 0){ +// INT32 iLoop = 0; +// while( 1 ){ +// if (Merge[iLoop][1] == pObj->usItem) + { + tempItemSlots.push_back(1); + tempItemSlots.push_back(2); + tempItemSlots.push_back(3); + tempItemSlots.push_back(4); +// break; + } +// iLoop++; +// if (Merge[iLoop][1] == 0) +// { +// break; +// } +// } + } + } + + return tempItemSlots; +} + +void InitItemAttachments(OBJECTTYPE* pObj){ + + if(UsingNewAttachmentSystem()==false) + return; + + //pObj->usAttachmentSlotIndexVector = GetItemSlots(pObj); + (*pObj)[0]->attachments.resize((GetItemSlots(pObj).size())); +} +/* +//WarmSteel - Changed this function for NAS, because when the slots change many items will become invalid IN THAT SLOT, but not on the weapon. +To fix this we re-attach all invalid attachments. It also checks the slots that are on the gun. +IMPORTANT: If you use AttachObject/RemoveAttachment with fRemoveProhibited TRUE in this function, I will hunt you down and smite you. +*/ +void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usItem, BOOLEAN fOnlyRemoveWhenSlotsChange) +{ + if(!pObj->exists()) + return; + + if(UsingNewAttachmentSystem()==true){ + UINT32 curSlot = 0; + BOOLEAN fCanAttach = FALSE; + BOOLEAN fRemoveProhibitedAttachments = FALSE; + BOOLEAN fDoneRemovingProhibited = FALSE; + attachmentList tempAttachList; + std::vector tempItemSlots; + std::vector usAttachmentSlotIndexVector = GetItemSlots(pObj); + + //Get the item slots this item SHOULD have (but may not have right now), also counting any slots that were added or removed. + //tempItemSlots = GetItemSlots(pObj); + + //Check if the slots have changed. + if(fOnlyRemoveWhenSlotsChange){ + if(usAttachmentSlotIndexVector.size() != (*pObj)[0]->attachments.size()){ + fRemoveProhibitedAttachments = TRUE; + } else { + for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end() && !fRemoveProhibitedAttachments; ++iter, ++curSlot){ + if(iter->exists()){ + UINT16 slotIndex = usAttachmentSlotIndexVector[curSlot]; + UINT16 sItem = iter->usItem; + if(!(AttachmentSlots[slotIndex].nasAttachmentClass & Item[sItem].nasAttachmentClass)){ + fRemoveProhibitedAttachments = TRUE; + } + } + } + } + } + + if(fRemoveProhibitedAttachments){ + UINT16 usInfiniteLoopCount = 0; + //CHRISL: There is the chance that we could have attachments in slots that are no longer valid, but if we arbitrarily resize the attachmentList + // we could actually lose attachments. So let's just remove all attachments and replace them in correct locations + for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()){ + tempAttachList.push_back((*iter)); + iter = (*pObj)[0]->RemoveAttachmentAtIter(iter); + } + } + //pObj->usAttachmentSlotIndexVector = tempItemSlots; + //Keep checking till slots stop changing. + while(!fDoneRemovingProhibited){ + //Surely 500 tries is enough to fix ANY item... + AssertMsg(usInfiniteLoopCount < 500, "There was an inifinite loop while removing prohibited attachments"); + + //Resize the object to the correct size + (*pObj)[0]->attachments.resize(usAttachmentSlotIndexVector.size()); + + //Start by trying to re-attach inseperable items. They take precedence over items that can normally be removed + for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) { + if(Item[iter->usItem].inseparable && ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, 0, -1, 0, NULL, usAttachmentSlotIndexVector)){ + //This seems to be rather valid. Can't be 100% sure though. + if(pObj->AttachObject(NULL, &(*iter), FALSE, 0, -1, FALSE, usAttachmentSlotIndexVector)){ + //Ok now we can be sure, lets remove this object so we don't try to drop it later. + iter = tempAttachList.erase(iter); + } else { + ++iter; + } + } else { + ++iter; + } + } + //Try to attach all the other attachments that didn't fit their current slot. + for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) { + if(ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE, 0, -1, 0, NULL, usAttachmentSlotIndexVector)){ + //This seems to be rather valid. Can't be 100% sure though. + if(pObj->AttachObject(NULL, &(*iter), FALSE, 0, -1, FALSE, usAttachmentSlotIndexVector)){ + //Ok now we can be sure, lets remove this object so we don't try to drop it later. + iter = tempAttachList.erase(iter); + } else { + ++iter; + } + } else { + ++iter; + } + } + + tempItemSlots = GetItemSlots(pObj); + + //assume all attachments are replaced and we're good to break the look + fDoneRemovingProhibited = TRUE; + + //Check if the slots have changed after possibly removing attachments. + if(tempItemSlots.size() != usAttachmentSlotIndexVector.size()){ + //Changed, we need to correct again. + fDoneRemovingProhibited = FALSE; + } else if(!tempItemSlots.empty()){ + for (UINT16 cnt = 0; cnt < tempItemSlots.size(); ++cnt) { + //If these slots don't match, something has changed, keep checking. + if(tempItemSlots[cnt] != usAttachmentSlotIndexVector[cnt]){ + fDoneRemovingProhibited = FALSE; + break; + } + } + } + + if(usInfiniteLoopCount > 10){ //run through the loop 10 times before we drop items. + //Anything that's still in our tempAttachList couldn't be attached, and should be dropped. + for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) { + if (iter->exists()) { + if ( pSoldier && AutoPlaceObject( pSoldier, &(*iter), FALSE ) ) + { + iter = tempAttachList.erase(iter); + } else { // put it on the ground + INT8 pathing = (pSoldier?pSoldier->pathing.bLevel:0); + INT32 sGridNo = (pSoldier?pSoldier->sGridNo:0); + if(guiCurrentItemDescriptionScreen == MAP_SCREEN && fShowMapInventoryPool){ + AutoPlaceObjectInInventoryStash(&(*iter), sGridNo); + //AddItemToPool( sGridNo, &(*iter), 1, pathing, WORLD_ITEM_REACHABLE, 0 ); + iter = tempAttachList.erase(iter); + } else { + AddItemToPool( sGridNo, &(*iter), 1, pathing, WORLD_ITEM_REACHABLE, 0 ); + iter = tempAttachList.erase(iter); + } + } + } else { + ++iter; + } + } + } + if(!tempAttachList.empty()){ + fDoneRemovingProhibited = FALSE; + } + + usAttachmentSlotIndexVector = GetItemSlots(pObj); + usInfiniteLoopCount++; + } + } + } else { + UINT16 x = 0; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end();) { + if(!iter->exists()){ + //WarmSteel - erase null objects, we don't need them without the NAS. + iter = (*pObj)[0]->attachments.erase(iter); + } else { + if ( (!ValidAttachment(iter->usItem, pObj) && !ValidLaunchable(iter->usItem, usItem) && !ValidLaunchable(iter->usItem, GetAttachedGrenadeLauncher(pObj)) ) || x >= OLD_MAX_ATTACHMENTS_101) + { + if ( !Item[iter->usItem].inseparable ) + { + if (pSoldier) { + if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) ) + { // put it on the ground + AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 ); + } + } + } + pObj->RemoveAttachment(&(*iter),0 ,0 , pSoldier, TRUE, FALSE); + iter = (*pObj)[0]->attachments.begin(); + x = 0; + } else { + ++x; + ++iter; + } + } } } return; } -void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj) +//WarmSteel - Needed for merges, because the new items don't get their new default attachments. +//This does the same as RemoveProhibitedAttachments but is a bit more thorough at it. +//This is at the risk that items move around if more than one slot is valid, but since this is used for "new" guns after merges, that's acceptable. +void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem){ + + attachmentList tempAttachList; + attachmentList tempSlotChangingAttachList; + BOOLEAN fFoundDefaultAttachment = FALSE; + UINT8 slotCount; + std::vector usAttachmentSlotIndexVector = GetItemSlots(pObj); + + if( !(*pObj)[0]->attachments.empty() ){ + //Have to take all attachments off, because of possible incompatibilities with the default attachments (can't NOT attach a default attachment because some stupid item already attached is incompatible with it). + + //Delete all default inseperable attachments from the old gun. + //This is safe UNLESS the inseparable default attachments is not the only attachment of the same kind on the gun. + //I can't think of any reason why this would happen, and if it does the worst that can happen is your attachment disappearing. + for(slotCount = 0; slotCount < (*pObj)[0]->attachments.size(); slotCount++){ + UINT16 usAttach = (*pObj)[0]->GetAttachmentAtIndex(slotCount)->usItem; + if(Item[usAttach].inseparable){ + for(UINT16 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS && Item[usOldItem].defaultattachments[cnt] != 0; cnt++){ + if(Item[usOldItem].defaultattachments[cnt] == usAttach){ + (*pObj)[0]->RemoveAttachmentAtIndex(slotCount); + break; + } + } + } + } + slotCount = 0; + //Put all other attachments into a temporary storage, so we can try to re-attach later. + for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); iter++, slotCount++) { + if(iter->exists()){ + UINT16 cnt = 0; + tempAttachList.push_back((*iter)); + } + } + } + //clear the attachment list, we've saved the attachments somewhere safe now. + (*pObj)[0]->attachments.clear(); + + //Make sure the attachment slot data is correct. + //std::vector tempItemSlots = GetItemSlots(pObj); + (*pObj)[0]->attachments.resize(usAttachmentSlotIndexVector.size()); + //pObj->usAttachmentSlotIndexVector = tempItemSlots; + + //Now add all default attachments, but add them with the same status as the gun. We don't want to make repairing guns easy :) + for(UINT16 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS && Item[pObj->usItem].defaultattachments[cnt] != 0; cnt++){ + //Only add inseparable default attachments, because they are likely "part" of the gun. + if(Item[Item[pObj->usItem].defaultattachments[cnt]].inseparable){ + static OBJECTTYPE defaultAttachment; + CreateItem(Item [ pObj->usItem ].defaultattachments[cnt],(*pObj)[0]->data.objectStatus,&defaultAttachment); + AssertMsg(pObj->AttachObject(NULL,&defaultAttachment, FALSE, 0, -1, FALSE), "A default attachment could not be attached after merging, this should not be possible."); + } + } + + //First re-attach any slot-changing attachments. + for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end();) { + if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE )){ + //This seems to be rather valid. Can't be 100% sure though. + if(pObj->AttachObject(NULL, &(*iter), FALSE)){ + //Ok now we can be sure, lets remove this object so we don't try to drop it later. + iter = tempSlotChangingAttachList.erase(iter); + } else { + ++iter; + } + } else { + ++iter; + } + } + + //Time to re-attach the other attachments, if we can. I am the king of copy pasta. + for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end();) { + if( ValidItemAttachmentSlot(pObj, iter->usItem, TRUE, FALSE)){ + //This seems to be rather valid. Can't be 100% sure though. + if(pObj->AttachObject(NULL, &(*iter), FALSE)){ + //Ok now we can be sure, lets remove this object so we don't try to drop it later. + iter = tempAttachList.erase(iter); + } else { + ++iter; + } + } else { + ++iter; + } + } + + //drop all items we couldn't re-attach. + for (attachmentList::iterator iter = tempSlotChangingAttachList.begin(); iter != tempSlotChangingAttachList.end(); ++iter) { + if ( !Item[iter->usItem].inseparable ) + {//WarmSteel - Couldn't re-attach this item, try to drop it. + if (pSoldier) { + if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) ) + { // put it on the ground + AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 ); + } + } + } + } + //and the rest too + for (attachmentList::iterator iter = tempAttachList.begin(); iter != tempAttachList.end(); ++iter) { + if ( !Item[iter->usItem].inseparable ) + {//WarmSteel - Couldn't re-attach this item, try to drop it. + if (pSoldier) { + if ( !AutoPlaceObject( pSoldier, &(*iter), FALSE ) ) + { // put it on the ground + AddItemToPool( pSoldier->sGridNo, &(*iter), 1, pSoldier->pathing.bLevel, 0 , -1 ); + } + } + } + } +} + +void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT8 subObject) { - CreateAmmo((*pObj)[0]->data.gun.usGunAmmoItem, &gTempObject, (*pObj)[0]->data.gun.ubGunShotsLeft); - (*pObj)[0]->data.gun.ubGunShotsLeft = 0; - (*pObj)[0]->data.gun.usGunAmmoItem = NONE; + CreateAmmo((*pObj)[subObject]->data.gun.usGunAmmoItem, &gTempObject, (*pObj)[subObject]->data.gun.ubGunShotsLeft); + (*pObj)[subObject]->data.gun.ubGunShotsLeft = 0; + (*pObj)[subObject]->data.gun.usGunAmmoItem = NONE; // HEADROCK HAM 3.5: Clear ammo type - (*pObj)[0]->data.gun.ubGunAmmoType = NONE; + (*pObj)[subObject]->data.gun.ubGunAmmoType = NONE; if ( pSoldier ) { if ( !AutoPlaceObject( pSoldier, &gTempObject, FALSE ) ) @@ -4135,7 +5479,8 @@ BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos } if(pSoldier->inv[BPACKPOCKPOS].exists() == true) { - if(LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo != LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo || + //DBrot: changed to bitwise comparison + if(((LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo & LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo) == 0) || LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo == 0) { return( FALSE ); @@ -4152,7 +5497,8 @@ BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos // return( FALSE ); if(pSoldier->inv[CPACKPOCKPOS].exists() == true) { - if(LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo != LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo || + //DBrot: changed to bitwise comparison + if(((LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo & LoadBearingEquipment[Item[pObj->usItem].ubClassIndex].lbeCombo) ==0)|| LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo == 0) { return( FALSE ); @@ -4164,7 +5510,7 @@ BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos if(pObj->usItem == MONEY) return( FALSE ); if(Item[pObj->usItem].usItemClass == IC_AMMO || Item[pObj->usItem].usItemClass == IC_GRENADE) - return(CompatibleAmmoForGun(pObj, &pSoldier->inv[GUNSLINGPOCKPOS]) || ValidAttachment(pObj->usItem, pSoldier->inv[GUNSLINGPOCKPOS].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[GUNSLINGPOCKPOS].usItem)); + return(CompatibleAmmoForGun(pObj, &pSoldier->inv[GUNSLINGPOCKPOS]) || ValidAttachment(pObj->usItem, &(pSoldier->inv[GUNSLINGPOCKPOS]) ) || ValidLaunchable(pObj->usItem, pSoldier->inv[GUNSLINGPOCKPOS].usItem)); //recalc slot limit to exclude ItemSize attachment modifiers ubSlotLimit = ItemSlotLimit( pObj, bPos, pSoldier, FALSE ); // Removed backpack/gunsling restrictions @@ -4175,7 +5521,7 @@ BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos if(pObj->usItem == MONEY) return( FALSE ); if (Item[pObj->usItem].usItemClass != IC_BLADE && Item[pObj->usItem].usItemClass != IC_THROWING_KNIFE ) - return(CompatibleAmmoForGun(pObj, &pSoldier->inv[KNIFEPOCKPOS]) || ValidAttachment(pObj->usItem, pSoldier->inv[KNIFEPOCKPOS].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[KNIFEPOCKPOS].usItem)); + return(CompatibleAmmoForGun(pObj, &pSoldier->inv[KNIFEPOCKPOS]) || ValidAttachment(pObj->usItem, &(pSoldier->inv[KNIFEPOCKPOS]) ) || ValidLaunchable(pObj->usItem, pSoldier->inv[KNIFEPOCKPOS].usItem)); break; // IC Pockets case BIGPOCK1POS: @@ -4245,11 +5591,11 @@ BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos { // CHRISL: lbePocket==0 means pocket disabled. ubSlotLimit==0 means pocket can't hold item if ( lbePocket == 0 || ubSlotLimit == 0 ) - return ( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) || ValidAttachment(pObj->usItem, pSoldier->inv[bPos].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[bPos].usItem) ); + return ( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) || ValidAttachment(pObj->usItem, &(pSoldier->inv[bPos]) ) || ValidLaunchable(pObj->usItem, pSoldier->inv[bPos].usItem) ); // CHRISL: Adjust parameters to include the new inventory system if (ubSlotLimit == 0 && bPos >= BIGPOCKFINAL ) - return( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) || ValidAttachment(pObj->usItem, pSoldier->inv[bPos].usItem) || ValidLaunchable(pObj->usItem, pSoldier->inv[bPos].usItem) ); + return( CompatibleAmmoForGun(pObj, &pSoldier->inv[bPos]) || ValidAttachment(pObj->usItem, &(pSoldier->inv[bPos]) ) || ValidLaunchable(pObj->usItem, pSoldier->inv[bPos].usItem) ); } return( TRUE ); @@ -4880,7 +6226,7 @@ bool PlaceInAnySmallPocket(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewIte BOOLEAN AutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNewItem, INT8 bExcludeSlot ) { INVTYPE * pItem; - UINT8 packCombo, backCombo; + UINT32 packCombo, backCombo; // statuses of extra objects would be 0 if the # exceeds the maximum //Assert( pObj->ubNumberOfObjects <= MAX_OBJECTS_PER_SLOT); @@ -5043,7 +6389,8 @@ BOOLEAN AutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNew { packCombo = LoadBearingEquipment[pItem->ubClassIndex].lbeCombo; backCombo = LoadBearingEquipment[Item[pSoldier->inv[BPACKPOCKPOS].usItem].ubClassIndex].lbeCombo; - if((pSoldier->inv[BPACKPOCKPOS].exists() == true && packCombo != 0 && backCombo == packCombo) || pSoldier->inv[BPACKPOCKPOS].exists() == false) + //DBrot: changed to bitwise comparison + if((pSoldier->inv[BPACKPOCKPOS].exists() == true && packCombo != 0 && (backCombo & packCombo)) || pSoldier->inv[BPACKPOCKPOS].exists() == false) { PlaceObject( pSoldier, CPACKPOCKPOS, pObj, fNewItem ); if(pObj->exists() == false) @@ -5057,7 +6404,8 @@ BOOLEAN AutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNew //{ packCombo = LoadBearingEquipment[Item[pSoldier->inv[CPACKPOCKPOS].usItem].ubClassIndex].lbeCombo; backCombo = LoadBearingEquipment[pItem->ubClassIndex].lbeCombo; - if((pSoldier->inv[CPACKPOCKPOS].exists() == true && backCombo != 0 && backCombo == packCombo) || pSoldier->inv[CPACKPOCKPOS].exists() == false) + //DBrot: changed to bitwise comparison + if((pSoldier->inv[CPACKPOCKPOS].exists() == true && backCombo != 0 && (backCombo & packCombo)) || pSoldier->inv[CPACKPOCKPOS].exists() == false) { PlaceObject( pSoldier, BPACKPOCKPOS, pObj, fNewItem ); pSoldier->flags.DropPackFlag = FALSE; @@ -5269,6 +6617,22 @@ UINT16 UseKitPoints( OBJECTTYPE * pObj, UINT16 usPoints, SOLDIERTYPE *pSoldier ) for (bLoop = pObj->ubNumberOfObjects - 1; bLoop >= 0; bLoop--) { + // SANDRO - revisited this code, make the percentstatusdrainreduction count always + if( (usPoints * (max( 0, (100 - Item[pObj->usItem].percentstatusdrainreduction)))/100) < (*pObj)[bLoop]->data.objectStatus ) + { + (*pObj)[bLoop]->data.objectStatus -= (INT8)(usPoints * (max( 0, (100 - Item[pObj->usItem].percentstatusdrainreduction) ) )/100); + return( usOriginalPoints ); + } + else + { + // consume this kit totally + usPoints -= (((*pObj)[bLoop]->data.objectStatus) / (max( 0, (100 - Item[pObj->usItem].percentstatusdrainreduction))) /100); + (*pObj)[bLoop]->data.objectStatus = 0; + + pObj->ubNumberOfObjects--; + } + /* + // SANDRO - heh, this is not very right solution.. in second case, the percentstatusdrainreduction should be taken into account too if (Item[pObj->usItem].percentstatusdrainreduction > 0 && ((usPoints * (100 - Item[pObj->usItem].percentstatusdrainreduction))/100) < (*pObj)[bLoop]->data.objectStatus ) { (*pObj)[bLoop]->data.objectStatus -= (INT8) ((usPoints * (100 - Item[pObj->usItem].percentstatusdrainreduction ) )/100); @@ -5286,7 +6650,7 @@ UINT16 UseKitPoints( OBJECTTYPE * pObj, UINT16 usPoints, SOLDIERTYPE *pSoldier ) (*pObj)[bLoop]->data.objectStatus = 0; pObj->ubNumberOfObjects--; - } + }*/ } // check if pocket/hand emptied..update inventory, then update panel @@ -5326,7 +6690,10 @@ UINT16 MagazineClassIndexToItemType(UINT16 usMagIndex) // this function will have to be rewritten to scan the item table for an item // with item class ammo, which has class index usMagIndex DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "MagazineClassIndexToItemType" ) ); - for (usLoop = FIRST_AMMO; usLoop < MAXITEMS; usLoop++) + + // WANNE: Now ammo can be inserted anywhere in Items.xml (before only on index > 70 [FIRST_AMMO] (fix by Realist) + //for (usLoop = FIRST_AMMO; usLoop < MAXITEMS; usLoop++) + for (usLoop = 0; usLoop < MAXITEMS; usLoop++) { if ( Item[usLoop].usItemClass == 0 ) { @@ -5659,6 +7026,10 @@ BOOLEAN CreateGun( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj ) } } + //WarmSteel - Init item slots. + if(UsingNewAttachmentSystem()==true) + InitItemAttachments(pObj); + //ADB ubWeight has been removed, see comments in OBJECTTYPE //pObj->ubWeight = CalculateObjectWeight( pObj ); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateGun: Done")); @@ -5682,6 +7053,10 @@ BOOLEAN CreateAmmo( UINT16 usItem, OBJECTTYPE * pObj, INT16 ubShotsLeft ) else { (*pObj)[0]->data.ubShotsLeft = (UINT8)ubShotsLeft; } + //WarmSteel - Init attachment slots. + if(UsingNewAttachmentSystem()==true) + InitItemAttachments(pObj); + //ADB ubWeight has been removed, see comments in OBJECTTYPE //pObj->ubWeight = CalculateObjectWeight( pObj ); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateAmmo: done")); @@ -5727,6 +7102,10 @@ BOOLEAN CreateItem( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj ) //ADB ubWeight has been removed, see comments in OBJECTTYPE //pObj->ubWeight = CalculateObjectWeight( pObj ); fRet = TRUE; + //WarmSteel - Init attachment slots. + if(UsingNewAttachmentSystem()==true) + InitItemAttachments(pObj); + } if (fRet) { @@ -5735,12 +7114,14 @@ BOOLEAN CreateItem( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj ) { (*pObj).fFlags |= OBJECT_UNDROPPABLE; } - if (Item [ usItem ].defaultattachment > 0 ) - { + for(UINT8 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS; cnt++){ + if(Item [ usItem ].defaultattachments[cnt] == 0) + break; + //cannot use gTempObject static OBJECTTYPE defaultAttachment; - CreateItem(Item [ usItem ].defaultattachment,100,&defaultAttachment); - pObj->AttachObject(NULL,&defaultAttachment); + CreateItem(Item [ usItem ].defaultattachments[cnt],100,&defaultAttachment); + pObj->AttachObject(NULL,&defaultAttachment, FALSE); } } @@ -5871,53 +7252,154 @@ BOOLEAN ArmBomb( OBJECTTYPE * pObj, INT8 bSetting ) return( TRUE ); } -BOOLEAN OBJECTTYPE::RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNewObj, UINT8 subObject ) +BOOLEAN OBJECTTYPE::RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNewObj, UINT8 subObject, SOLDIERTYPE * pSoldier, BOOLEAN fForceInseperable, BOOLEAN fRemoveProhibited ) { BOOLEAN objDeleted = FALSE; + std::vector usAttachmentSlotIndexVector; + std::vector usRemAttachmentSlotIndexVector; + UINT16 oldMagSize = 0; - if ( pAttachment == 0 ) + if ( pAttachment->exists() == false || this->exists() == false) { return( FALSE ); } - if ( Item[ pAttachment->usItem ].inseparable ) + //Sometimes we have to force inseparable items off, sadly. + if ( Item[ pAttachment->usItem ].inseparable && !fForceInseperable ) { return( FALSE ); } + //CHRISL: This is so we can try to determine if the removed attachment altered our mag size. + if(Item[this->usItem].usItemClass == IC_GUN) + oldMagSize = GetMagSize(this); + //CHRISL: I know this FOR loop is basically redundant to what the remove() function already does, but // this setup includes a failsafe. Now we'll only copy the attachment to our cursor (pNewObj) if // iter and pAttachment are the same. This should stop attachment duplication though it doesn't resolve // the initial cause of the attachment duplication issue. + + //First look for attachment with the exact same memory adress. + //This is so that you can click to remove an attachment and it will take off THAT attachment and not the first one that just "looks" like it. for (std::list::iterator iter = (*this)[subObject]->attachments.begin(); iter != (*this)[subObject]->attachments.end(); ++iter){ - if(*iter == *pAttachment) + //Compare the adress + if(&(*iter) == pAttachment) { if(pNewObj != NULL) { *pNewObj = *pAttachment; } - iter = (*this)[subObject]->attachments.erase(iter); + + iter = (*this)[subObject]->RemoveAttachmentAtIter(iter); + objDeleted = TRUE; break; } } + //It is possible that the previous loop did not find the EXACT attachment we wanted to delete, look if there is one that is at least equal in data. + if(!objDeleted){ + for (std::list::iterator iter = (*this)[subObject]->attachments.begin(); + iter != (*this)[subObject]->attachments.end(); ++iter){ + //This compares the internal data of the objects. + if(*iter == *pAttachment) + { + if(pNewObj != NULL) + { + *pNewObj = *pAttachment; + } + + iter = (*this)[subObject]->RemoveAttachmentAtIter(iter); + + objDeleted = TRUE; + break; + } + } + } if(!objDeleted) return( FALSE ); - if (pNewObj && Item[pNewObj->usItem].grenadelauncher )//UNDER_GLAUNCHER) + //After removing an attachment, the ammo capacity might have changed. + if ( Item[this->usItem].usItemClass == IC_GUN && (*this)[subObject]->data.gun.usGunAmmoItem != NONE && (*this)[subObject]->data.gun.ubGunShotsLeft > 0 && oldMagSize != GetMagSize(this, subObject) ) + { + if ( (*this)[subObject]->data.gun.ubGunShotsLeft > GetMagSize(this, subObject) ) + { //Too many rounds, eject ammo + EjectAmmoAndPlace(pSoldier, this, subObject); + } + //CHRISL: We should update the usGunAmmoItem if we've changed the ammo capacity + if((*this)[subObject]->data.gun.ubGunShotsLeft != GetMagSize(this, subObject) && (*this)[subObject]->data.gun.usGunAmmoItem != NONE){ + UINT16 usNewAmmoItem; + usNewAmmoItem = FindReplacementMagazine(Weapon[this->usItem].ubCalibre ,GetMagSize(this, subObject),Magazine[Item[(*this)[subObject]->data.gun.usGunAmmoItem].ubClassIndex].ubAmmoType); + (*this)[subObject]->data.gun.usGunAmmoItem = usNewAmmoItem; + } + } + + //CHRISL: We need to know if the removed attachment could have altered the base items potential attachments + BOOLEAN removeAttachments = TRUE, cleanAttachments = FALSE; + INT8 loopCount = 0; + while(removeAttachments){ + usRemAttachmentSlotIndexVector = GetItemSlots(pNewObj); + if(usRemAttachmentSlotIndexVector.empty()){ + removeAttachments = FALSE; + } else { + cleanAttachments = TRUE; + usAttachmentSlotIndexVector = GetItemSlots(this, subObject); + for(attachmentList::iterator iter = (*this)[subObject]->attachments.begin(); iter != (*this)[subObject]->attachments.end(); ++iter){ + removeAttachments = FALSE; + if(iter->exists()){ + if(!ValidItemAttachment(this, iter->usItem, FALSE, FALSE, subObject, usAttachmentSlotIndexVector)){ //attachment is no longer valid + removeAttachments = TRUE; + OBJECTTYPE remObj; + remObj = *iter; + if(ValidItemAttachment(pNewObj, iter->usItem, FALSE, FALSE, 0, usRemAttachmentSlotIndexVector)){ + (*pNewObj)[0]->attachments.push_back((*iter)); + iter = (*this)[subObject]->RemoveAttachmentAtIter(iter); + continue; + } + if(loopCount > 5){ //try moving attachments to the removed attachment 5 times before we drop anything + if ( pSoldier && AutoPlaceObject( pSoldier, &remObj, FALSE ) ) + { + iter = (*this)[subObject]->RemoveAttachmentAtIter(iter); + } else { // put it on the ground + INT8 pathing = (pSoldier?pSoldier->pathing.bLevel:0); + INT32 sGridNo = (pSoldier?pSoldier->sGridNo:0); + if(guiCurrentItemDescriptionScreen == MAP_SCREEN && fShowMapInventoryPool){ + if(AutoPlaceObjectInInventoryStash(&remObj, sGridNo)){ + iter = (*this)[subObject]->RemoveAttachmentAtIter(iter); + } + } else { + AddItemToPool( sGridNo, &remObj, 1, pathing, WORLD_ITEM_REACHABLE, 0 ); + iter = (*this)[subObject]->RemoveAttachmentAtIter(iter); + } + } + } + } + } + } + } + loopCount++; + } + if(cleanAttachments){ + RemoveProhibitedAttachments(pSoldier, pNewObj, pNewObj->usItem); + RemoveProhibitedAttachments(pSoldier, this, this->usItem); + } + if (pNewObj->exists() && Item[pNewObj->usItem].grenadelauncher )//UNDER_GLAUNCHER) { // look for any grenade; if it exists, we must make it an // attachment of the grenade launcher OBJECTTYPE* pGrenade = FindAttachmentByClass( this, IC_GRENADE ); - if (pGrenade) + if (pGrenade->exists()) { - (*pNewObj)[subObject]->attachments.push_back(*pGrenade); + pNewObj->AttachObject(NULL, pGrenade, FALSE, 0, -1, 0); //ADB ubWeight has been removed, see comments in OBJECTTYPE //pNewObj->ubWeight = CalculateObjectWeight( pNewObj ); - this->RemoveAttachment(pGrenade); + this->RemoveAttachment(pGrenade, NULL, 0, NULL, 1, 0); } } + //Removing an attachment can alter slots, check them. + if(UsingNewAttachmentSystem()==true && fRemoveProhibited){ + RemoveProhibitedAttachments(pSoldier, this, this->usItem); + } //ADB ubWeight has been removed, see comments in OBJECTTYPE //this->ubWeight = CalculateObjectWeight( this ); @@ -6015,7 +7497,7 @@ BOOLEAN PlaceObjectInSoldierProfile( UINT8 ubProfile, OBJECTTYPE *pObject ) Item[old_item].inseparable = FALSE; pObject->RemoveAttachment(&(*iter)); Item[old_item].inseparable = old_inseparable; - if ((*pObject)[0]->attachments.empty() == true) { + if ((*pObject)[0]->AttachmentListSize() == 0) { break; } else{ @@ -6175,6 +7657,11 @@ BOOLEAN CheckForChainReaction( UINT16 usItem, INT16 bStatus, INT16 bDamage, BOOL // improve chance to make it practical to blow up explosives on the ground iChance = 50 + (iChance - 1) * 10; } + // SANDRO - experimental - increased chance to chain reactions of carried explosives a bit + else + { + iChance = 3 + (iChance - 1) * 3; + } iChance = iChance * ( 100 + ( (100 - bStatus) + bDamage ) / 2 ) / 100; if ((INT32) PreRandom( 100 ) < iChance) @@ -6263,8 +7750,11 @@ BOOLEAN DamageItem( OBJECTTYPE * pObject, INT32 iDamage, BOOLEAN fOnGround ) if (iter->exists() == true) { ++iter; } - else { - iter = (*pObject)[bLoop]->attachments.erase(iter); + else { + iter = (*pObject)[bLoop]->RemoveAttachmentAtIter(iter); + + if(UsingNewAttachmentSystem()==true) + ++iter; } } } @@ -6368,6 +7858,13 @@ BOOLEAN DamageItemOnGround( OBJECTTYPE * pObject, INT32 sGridNo, INT8 bLevel, IN // OK, Ignite this explosion! IgniteExplosion( ubOwner, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pObject->usItem, bLevel ); + // SANDRO - merc records + if ( (pObject->fFlags & OBJECT_ARMED_BOMB) && ((*pObject)[0]->data.misc.ubBombOwner > 1) ) + { + if ( MercPtrs[ ((*pObject)[0]->data.misc.ubBombOwner - 2) ]->ubProfile != NO_PROFILE && MercPtrs[ ((*pObject)[0]->data.misc.ubBombOwner - 2) ]->bTeam == gbPlayerNum ) + gMercProfiles[ MercPtrs[ ((*pObject)[0]->data.misc.ubBombOwner - 2) ]->ubProfile ].records.usExpDetonated++; + } + // Remove item! return( TRUE ); } @@ -6493,57 +7990,173 @@ void WaterDamage( SOLDIERTYPE *pSoldier ) } } BOOLEAN camoWoreOff = FALSE; - if (pSoldier->bCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED ) ) + + ///////////////////////////////////////////////////////////////////////////////////// + // ADDED BY SANDRO - Ranger trait makes camouflage reduction lesser + // I've messed this part a little to be more clean, the different camouflaged traits have been merged into one + if ( gGameOptions.fNewTraitSystem) { // reduce camouflage by 2% per tile of deep water // and 1% for medium water - if ( pSoldier->MercInDeepWater( ) ) - pSoldier->bCamo = __max( 0, pSoldier->bCamo - 2 ); - else - pSoldier->bCamo = __max( 0, pSoldier->bCamo - 1 ); + if ( pSoldier->bCamo > 0 ) + { + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + { + if ( pSoldier->MercInDeepWater( ) ) + { + pSoldier->bCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->bCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + { + pSoldier->bCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + } + else + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->bCamo = __max( 0, pSoldier->bCamo - 2 ); + else + pSoldier->bCamo = __max( 0, pSoldier->bCamo - 1 ); + } - if ( (pSoldier->bCamo)== 0) - camoWoreOff = TRUE; + if ( pSoldier->bCamo <= 0 ) + { + pSoldier->bCamo = 0; + camoWoreOff = TRUE; + } + } + if ( pSoldier->urbanCamo > 0 ) + { + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + { + if ( pSoldier->MercInDeepWater( ) ) + { + pSoldier->urbanCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->urbanCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + { + pSoldier->urbanCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + } + else + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 2); + else + pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 1); + } + + if ( pSoldier->urbanCamo <= 0 ) + { + pSoldier->urbanCamo = 0; + camoWoreOff = TRUE; + } + } + if ( pSoldier->desertCamo > 0 ) + { + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + { + if ( pSoldier->MercInDeepWater( ) ) + { + pSoldier->desertCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->desertCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + { + pSoldier->desertCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + } + else + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 2); + else + pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 1); + } + + if ( pSoldier->desertCamo <= 0 ) + { + pSoldier->desertCamo = 0; + camoWoreOff = TRUE; + } + } + if ( pSoldier->snowCamo > 0 ) + { + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + { + if ( pSoldier->MercInDeepWater( ) ) + { + pSoldier->snowCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + pSoldier->snowCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + else + { + pSoldier->snowCamo -= (Chance(__max(0, 100 - gSkillTraitValues.ubRACamoWornountSpeedReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ? 1 : 0 ); + } + } + else + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 2); + else + pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 1); + } + + if ( pSoldier->snowCamo <= 0 ) + { + pSoldier->snowCamo = 0; + camoWoreOff = TRUE; + } + } } - - if (pSoldier->urbanCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN ) ) + else if ( !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_OT ) ) // Old Camouflaged trait { // reduce camouflage by 2% per tile of deep water // and 1% for medium water - if ( pSoldier->MercInDeepWater( ) ) - pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 2 ); - else - pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 1 ); + if ( pSoldier->bCamo > 0 ) + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->bCamo = __max( 0, pSoldier->bCamo - 2 ); + else + pSoldier->bCamo = __max( 0, pSoldier->bCamo - 1 ); - if ( (pSoldier->urbanCamo)== 0) - camoWoreOff = TRUE; - } - - if (pSoldier->desertCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT ) ) - { - // reduce camouflage by 2% per tile of deep water - // and 1% for medium water - if ( pSoldier->MercInDeepWater( ) ) - pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 2 ); - else - pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 1 ); - - if ( (pSoldier->desertCamo)== 0) - camoWoreOff = TRUE; - } - - if (pSoldier->snowCamo > 0 && !HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_SNOW ) ) - { - // reduce camouflage by 2% per tile of deep water - // and 1% for medium water - if ( pSoldier->MercInDeepWater( ) ) - pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 2 ); - else - pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 1 ); - - if ( (pSoldier->snowCamo)== 0) - camoWoreOff = TRUE; + if ( (pSoldier->bCamo)== 0) + camoWoreOff = TRUE; + } + if ( pSoldier->urbanCamo > 0 ) + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 2); + else + pSoldier->urbanCamo = __max( 0, pSoldier->urbanCamo - 1); + + if ( (pSoldier->urbanCamo)== 0) + camoWoreOff = TRUE; + } + if ( pSoldier->desertCamo > 0 ) + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 2); + else + pSoldier->desertCamo = __max( 0, pSoldier->desertCamo - 1); + + if ( (pSoldier->desertCamo)== 0) + camoWoreOff = TRUE; + } + if ( pSoldier->snowCamo > 0 ) + { + if ( pSoldier->MercInDeepWater( ) ) + pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 2); + else + pSoldier->snowCamo = __max( 0, pSoldier->snowCamo - 1); + + if ( (pSoldier->snowCamo)== 0) + camoWoreOff = TRUE; + } } + ///////////////////////////////////////////////////////////////////////////////////// if ( camoWoreOff ) { @@ -6552,7 +8165,24 @@ void WaterDamage( SOLDIERTYPE *pSoldier ) { pSoldier->CreateSoldierPalettes( ); } - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WASHED_OFF], pSoldier->name ); + // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_CAMMO_WASHED_OFF], pSoldier->name ); + + if ( pSoldier->bCamo <= 0 ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_JUNGLE_WASHED_OFF], pSoldier->name ); + } + else if ( pSoldier->urbanCamo <= 0 ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_URBAN_WASHED_OFF], pSoldier->name ); + } + else if ( pSoldier->snowCamo <= 0 ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_SNOW_WASHED_OFF], pSoldier->name ); + } + else if ( pSoldier->desertCamo <= 0 ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_DESERT_WASHED_OFF], pSoldier->name ); + } } @@ -6581,15 +8211,45 @@ void WaterDamage( SOLDIERTYPE *pSoldier ) BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs ) { + // Added - SANDRO INT8 bPointsToUse; UINT16 usTotalKitPoints; + UINT16 iRemainingCamoAfterRemoving; (*pfGoodAPs) = TRUE; - if (!Item[pObj->usItem].camouflagekit || pObj->exists() == false) + if (pObj->exists() == false) + return( FALSE ); + + ////////////////////////////////////////////////////////////////////////////// + // added possibility to remove all camo by using a rag on self - SANDRO + if (pObj->usItem == 1022 && gGameExternalOptions.fCamoRemoving) + { + if (!EnoughPoints( pSoldier, (APBPConstants[AP_CAMOFLAGE]/2), 0, TRUE ) ) + { + (*pfGoodAPs) = FALSE; + return( TRUE ); + } + // 100 should be enough. The third value "0" means we will remove all types of camo + ReduceCamoFromSoldier( pSoldier, 100, 0 ); + + // damage the rag :) - actually you would need to flag it damagable in the items.XML + DamageItem( pObj, 22, FALSE ); + + DeductPoints( pSoldier, (APBPConstants[AP_CAMOFLAGE] / 2), 0 ); + + // Reload palettes.... + if ( pSoldier->bInSector ) + { + pSoldier->CreateSoldierPalettes( ); + } + return( TRUE ); + } + else if ( !Item[pObj->usItem].camouflagekit ) { return( FALSE ); } + ////////////////////////////////////////////////////////////////////////////// if (!EnoughPoints( pSoldier, APBPConstants[AP_CAMOFLAGE], 0, TRUE ) ) { @@ -6604,31 +8264,213 @@ BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAP return( FALSE ); } - //get total camo bonus for kit -- note that camo kits now require the camobonus tag to be set - //int itemCamo = Item[pObj->usItem].camobonus + Item[pObj->usItem].urbanCamobonus + Item[pObj->usItem].desertCamobonus + Item[pObj->usItem].snowCamobonus; + ////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Added a feature to determine which type of camo we use // + // and procedure able to reduce different type of camo // + // ******************************************************************************************** // - int totalCamo = pSoldier->bCamo + pSoldier->wornCamo + pSoldier->urbanCamo+pSoldier->wornUrbanCamo+pSoldier->desertCamo+pSoldier->wornDesertCamo+pSoldier->snowCamo+pSoldier->wornSnowCamo; - if ((totalCamo) >= 100) + if (gGameExternalOptions.fCamoRemoving) { - // nothing more to add - return( FALSE ); + int iJungleCamoTotal = pSoldier->bCamo + pSoldier->wornCamo; + int iUrbanCamoTotal = pSoldier->urbanCamo + pSoldier->wornUrbanCamo; + int iDesertCamoTotal = pSoldier->desertCamo + pSoldier->wornDesertCamo; + int iSnowCamoTotal = pSoldier->snowCamo + pSoldier->wornSnowCamo; + + int totalCamo = iJungleCamoTotal + iUrbanCamoTotal + iDesertCamoTotal + iSnowCamoTotal; + + // First, check if we have an item with major JUNGLE camobonus + if ( (Item[pObj->usItem].camobonus > Item[pObj->usItem].urbanCamobonus) && + (Item[pObj->usItem].camobonus > Item[pObj->usItem].desertCamobonus) && + (Item[pObj->usItem].camobonus > Item[pObj->usItem].snowCamobonus) ) + { + if (iJungleCamoTotal >= 100) + return( FALSE ); + + // determine how much we can add + bPointsToUse = (100 - (iJungleCamoTotal) + 1 ) / 2; + bPointsToUse = __min( bPointsToUse, usTotalKitPoints ); + + // determine how much we will add + int iJungleCamoAdded = (int)(Item[pObj->usItem].camobonus * bPointsToUse * 2 / 100 ); + + // if we have already too much different camo on ourselves, reduce some or all + if ( (totalCamo + iJungleCamoAdded) > 100 ) + { + // first, determine how much we actually want to remove + int iCamoToRemove = (totalCamo + iJungleCamoAdded) - 100; + + // reduce camo.. IMPORTANT - third value is type of camo to skip (0=skip-none, 1=jungle, 2=urban, 3=desert,4=snow) + iRemainingCamoAfterRemoving = ReduceCamoFromSoldier( pSoldier, iCamoToRemove, 1 ); // "1" - we want to keep the JUNGLE camo + + // if some camo haven't been reduced from us, the camo to add will be lessened by that value + if (iRemainingCamoAfterRemoving > 0) + iJungleCamoAdded = max(0, (iJungleCamoAdded - iRemainingCamoAfterRemoving)); + + if (iJungleCamoAdded <= 0) // if we have nothing to add now, return + return( FALSE ); + else // otherwise apply the camo + { + pSoldier->bCamo = __min( 100, pSoldier->bCamo + iJungleCamoAdded ); + } + } + else // everything's fine, apply!! + { + pSoldier->bCamo = __min( 100, pSoldier->bCamo + iJungleCamoAdded ); + } + } + // Second, check if we have an item with major URBAN camobonus + else if ( (Item[pObj->usItem].urbanCamobonus > Item[pObj->usItem].camobonus) && + (Item[pObj->usItem].urbanCamobonus > Item[pObj->usItem].desertCamobonus) && + (Item[pObj->usItem].urbanCamobonus > Item[pObj->usItem].snowCamobonus) ) + { + if (iUrbanCamoTotal >= 100) + return( FALSE ); + + // determine how much we can add + bPointsToUse = (100 - (iUrbanCamoTotal) + 1 ) / 2; + bPointsToUse = __min( bPointsToUse, usTotalKitPoints ); + + // determine how much we will add + int iUrbanCamoAdded = (int)(Item[pObj->usItem].urbanCamobonus * bPointsToUse * 2 / 100 ); + + // if we have already too much different camo on ourselves, reduce some or all + if ( (totalCamo + iUrbanCamoAdded) > 100 ) + { + // first, determine how much we actually want to remove + int iCamoToRemove = (totalCamo + iUrbanCamoAdded) - 100; + + // reduce camo.. IMPORTANT - third value is type of camo to skip (0=skip-none, 1=jungle, 2=urban, 3=desert,4=snow) + iRemainingCamoAfterRemoving = ReduceCamoFromSoldier( pSoldier, iCamoToRemove, 2 ); // "2" - we want to keep the URBAN camo + + // if some camo haven't been reduced from us, the camo to add will be lessened by that value + if (iRemainingCamoAfterRemoving > 0) + iUrbanCamoAdded = max(0, (iUrbanCamoAdded - iRemainingCamoAfterRemoving)); + + if (iUrbanCamoAdded <= 0) // if we have nothing to add now, return + return( FALSE ); + else // otherwise apply the camo + { + pSoldier->urbanCamo = __min( 100, pSoldier->urbanCamo + iUrbanCamoAdded ); + } + } + else // everything's fine, apply!! + { + pSoldier->urbanCamo = __min( 100, pSoldier->urbanCamo + iUrbanCamoAdded ); + } + } + // Third, check if we have an item with major DESERT camobonus + else if ( (Item[pObj->usItem].desertCamobonus > Item[pObj->usItem].camobonus) && + (Item[pObj->usItem].desertCamobonus > Item[pObj->usItem].urbanCamobonus) && + (Item[pObj->usItem].desertCamobonus > Item[pObj->usItem].snowCamobonus) ) + { + if (iDesertCamoTotal >= 100) + return( FALSE ); + + // determine how much we can add + bPointsToUse = (100 - (iDesertCamoTotal) + 1 ) / 2; + bPointsToUse = __min( bPointsToUse, usTotalKitPoints ); + + // determine how much we will add + int iDesertCamoAdded = (int)(Item[pObj->usItem].desertCamobonus * bPointsToUse * 2 / 100 ); + + // if we have already too much different camo on ourselves, reduce some or all + if ( (totalCamo + iDesertCamoAdded) > 100 ) + { + // first, determine how much we actually want to remove + int iCamoToRemove = (totalCamo + iDesertCamoAdded) - 100; + + // reduce camo.. IMPORTANT - third value is type of camo to skip (0=skip-none, 1=jungle, 2=urban, 3=desert,4=snow) + iRemainingCamoAfterRemoving = ReduceCamoFromSoldier( pSoldier, iCamoToRemove, 3 ); // "3" - we want to keep the DESERT camo + + // if some camo haven't been reduced from us, the camo to add will be lessened by that value + if (iRemainingCamoAfterRemoving > 0) + iDesertCamoAdded = max(0, (iDesertCamoAdded - iRemainingCamoAfterRemoving)); + + if (iDesertCamoAdded <= 0) // if we have nothing to add now, return + return( FALSE ); + else // otherwise apply the camo + { + pSoldier->desertCamo = __min( 100, pSoldier->desertCamo + iDesertCamoAdded ); + } + } + else // everything's fine, apply!! + { + pSoldier->desertCamo = __min( 100, pSoldier->desertCamo + iDesertCamoAdded ); + } + } + // Fourth, check if we have an item with major SNOW camobonus + else if ( (Item[pObj->usItem].snowCamobonus > Item[pObj->usItem].camobonus) && + (Item[pObj->usItem].snowCamobonus > Item[pObj->usItem].urbanCamobonus) && + (Item[pObj->usItem].snowCamobonus > Item[pObj->usItem].desertCamobonus) ) + { + if (iSnowCamoTotal >= 100) + return( FALSE ); + + // determine how much we can add + bPointsToUse = (100 - (iSnowCamoTotal) + 1 ) / 2; + bPointsToUse = __min( bPointsToUse, usTotalKitPoints ); + + // determine how much we will add + int iSnowCamoAdded = (int)(Item[pObj->usItem].snowCamobonus * bPointsToUse * 2 / 100 ); + + // if we have already too much different camo on ourselves, reduce some or all + if ( (totalCamo + iSnowCamoAdded) > 100 ) + { + // first, determine how much we actually want to remove + int iCamoToRemove = (totalCamo + iSnowCamoAdded) - 100; + + // reduce camo.. IMPORTANT - third value is type of camo to skip (0=skip-none, 1=jungle, 2=urban, 3=desert,4=snow) + iRemainingCamoAfterRemoving = ReduceCamoFromSoldier( pSoldier, iCamoToRemove, 4 ); // "4" - we want to keep the SNOW camo + + // if some camo haven't been reduced from us, the camo to add will be lessened by that value + if (iRemainingCamoAfterRemoving > 0) + iSnowCamoAdded = max(0, (iSnowCamoAdded - iRemainingCamoAfterRemoving)); + + if (iSnowCamoAdded <= 0) // if we have nothing to add now, return + return( FALSE ); + else // otherwise apply the camo + { + pSoldier->snowCamo = __min( 100, pSoldier->snowCamo + iSnowCamoAdded ); + } + } + else // everything's fine, apply!! + { + pSoldier->snowCamo = __min( 100, pSoldier->snowCamo + iSnowCamoAdded ); + } + } + else // the item has no major camo, return + return( FALSE ); + // ****************************************************************************************** // + //////////////////////////////////////////////////////////////////////////////////////////////// } + else + { + //get total camo bonus for kit -- note that camo kits now require the camobonus tag to be set + //int itemCamo = Item[pObj->usItem].camobonus + Item[pObj->usItem].urbanCamobonus + Item[pObj->usItem].desertCamobonus + Item[pObj->usItem].snowCamobonus; - // points are used up at a rate of 50% kit = 100% cammo on guy - // add 1 to round off - bPointsToUse = (100 - (totalCamo) + 1 ) / 2; - bPointsToUse = __min( bPointsToUse, usTotalKitPoints ); + int totalCamo = pSoldier->bCamo + pSoldier->wornCamo + pSoldier->urbanCamo+pSoldier->wornUrbanCamo+pSoldier->desertCamo+pSoldier->wornDesertCamo+pSoldier->snowCamo+pSoldier->wornSnowCamo; + if ((totalCamo) >= 100) + { + // nothing more to add + return( FALSE ); + } - //figure out proportions of each to be applied, one item can theoretically have more than one camouflage type this way - int urban = (int)(Item[pObj->usItem].urbanCamobonus * bPointsToUse * 2 / 100 ); - int jungle = (int)(Item[pObj->usItem].camobonus * bPointsToUse * 2 / 100 ); - int desert = (int)(Item[pObj->usItem].desertCamobonus * bPointsToUse * 2 / 100 ); - int snow = (int)(Item[pObj->usItem].snowCamobonus * bPointsToUse * 2 / 100 ); + // points are used up at a rate of 50% kit = 100% cammo on guy + // add 1 to round off + bPointsToUse = (100 - (totalCamo) + 1 ) / 2; + bPointsToUse = __min( bPointsToUse, usTotalKitPoints ); - pSoldier->bCamo = __min( 100, pSoldier->bCamo + jungle ); - pSoldier->urbanCamo = __min( 100, pSoldier->urbanCamo + urban ); - pSoldier->desertCamo = __min( 100, pSoldier->desertCamo + desert ); - pSoldier->snowCamo = __min( 100, pSoldier->snowCamo + snow ); + //figure out proportions of each to be applied, one item can theoretically have more than one camouflage type this way + int urban = (int)(Item[pObj->usItem].urbanCamobonus * bPointsToUse * 2 / 100 ); + int jungle = (int)(Item[pObj->usItem].camobonus * bPointsToUse * 2 / 100 ); + int desert = (int)(Item[pObj->usItem].desertCamobonus * bPointsToUse * 2 / 100 ); + int snow = (int)(Item[pObj->usItem].snowCamobonus * bPointsToUse * 2 / 100 ); + + pSoldier->bCamo = __min( 100, pSoldier->bCamo + jungle ); + pSoldier->urbanCamo = __min( 100, pSoldier->urbanCamo + urban ); + pSoldier->desertCamo = __min( 100, pSoldier->desertCamo + desert ); + pSoldier->snowCamo = __min( 100, pSoldier->snowCamo + snow ); + } UseKitPoints( pObj, bPointsToUse, pSoldier ); @@ -6920,16 +8762,34 @@ INT16 BonusOnOff( INT16 bonus, INT16 status ) return bonus; } +// HEADROCK HAM 4: Scopes now determined not by an aim bonus but by a magnification factor. +BOOLEAN NCTHIsScoped( OBJECTTYPE * pObj ) +{ + if (pObj->exists() == true) { + if ( Item[pObj->usItem].scopemagfactor > 1.0 || Item[(*pObj)[0]->data.gun.usGunAmmoItem].scopemagfactor > 1.0 ) + return TRUE; + + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if ( Item[iter->usItem].scopemagfactor > 1.0 && iter->exists() ) + return TRUE; + } + } + + return FALSE; +} // Snap: a fast aimbonus check for AI BOOLEAN IsScoped( OBJECTTYPE * pObj ) { + if(UsingNewCTHSystem() == true) + return NCTHIsScoped(pObj); + if (pObj->exists() == true) { if ( Item[pObj->usItem].aimbonus > 0 || Item[(*pObj)[0]->data.gun.usGunAmmoItem].aimbonus > 0 ) return TRUE; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[iter->usItem].aimbonus > 0 ) + if ( Item[iter->usItem].aimbonus > 0 && iter->exists()) return TRUE; } } @@ -6977,13 +8837,37 @@ INT16 GetAimBonus( OBJECTTYPE * pObj, INT32 iRange, INT16 ubAimTime ) bonus += GetItemAimBonus( &Item[(*pObj)[0]->data.gun.usGunAmmoItem], iRange, ubAimTime ); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( GetItemAimBonus( &Item[iter->usItem], iRange, ubAimTime ), (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( GetItemAimBonus( &Item[iter->usItem], iRange, ubAimTime ), (*iter)[0]->data.objectStatus ); + } } } return( bonus ); } +//WarmSteel - This is used to determine the base aim bonus of the scope on this gun. +//It searched for the most powerful scope that is not targetting under it's minimum range. +INT16 GetBaseScopeAimBonus( OBJECTTYPE * pObj, INT32 iRange ) +{ + INT16 bonus = 0; + + //Valid integrated scope? + if(Item[pObj->usItem].aimbonus > bonus && iRange >= Item[pObj->usItem].minrangeforaimbonus ){ + bonus = Item[pObj->usItem].aimbonus; + } + + //Search for the most powerful scope we can use. + for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); iter++) + { + if(Item[iter->usItem].aimbonus > bonus && iRange >= Item[iter->usItem].minrangeforaimbonus && iter->exists()) + { + bonus = Item[iter->usItem].aimbonus; + } + } + return( bonus ); +} + // Madd: check equipment for aim bonus (penalties) INT16 GetGearAimBonus( SOLDIERTYPE * pSoldier, INT32 iRange, INT16 ubAimTime ) { @@ -6995,7 +8879,9 @@ INT16 GetGearAimBonus( SOLDIERTYPE * pSoldier, INT32 iRange, INT16 ubAimTime ) if (pObj->exists() == true) { bonus += GetItemAimBonus( &Item[pSoldier->inv[j].usItem], iRange, ubAimTime ); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += GetItemAimBonus(&Item[iter->usItem],iRange,ubAimTime); + if(iter->exists()){ + bonus += GetItemAimBonus(&Item[iter->usItem],iRange,ubAimTime); + } } } } @@ -7014,7 +8900,9 @@ INT16 GetGearToHitBonus( SOLDIERTYPE * pSoldier ) if (pObj->exists() == true) { bonus += Item[pSoldier->inv[j].usItem].tohitbonus; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += Item[iter->usItem].tohitbonus; + if(iter->exists()){ + bonus += Item[iter->usItem].tohitbonus; + } } } } @@ -7033,7 +8921,9 @@ INT16 GetGearAPBonus( SOLDIERTYPE * pSoldier ) bonus += Item[pSoldier->inv[j].usItem].APBonus; OBJECTTYPE* pObj = &pSoldier->inv[j]; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += Item[iter->usItem].APBonus; + if(iter->exists()){ + bonus += Item[iter->usItem].APBonus; + } } } } @@ -7045,7 +8935,7 @@ UINT32 FindRangeBonusAttachment( OBJECTTYPE * pObj ) { if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].rangebonus > 0 ) + if (Item[iter->usItem].rangebonus > 0 && iter->exists()) { return( Item[iter->usItem].uiIndex ); } @@ -7064,7 +8954,7 @@ INT16 GetRangeBonus( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].rangebonus; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( !Item[iter->usItem].duckbill || ( Item[iter->usItem].duckbill && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT )) + if ( !Item[iter->usItem].duckbill || ( Item[iter->usItem].duckbill && (*pObj)[0]->data.gun.ubGunAmmoType == AMMO_BUCKSHOT ) && iter->exists()) bonus += BonusReduce( Item[iter->usItem].rangebonus, (*iter)[0]->data.objectStatus ); } } @@ -7110,10 +9000,12 @@ INT16 GetToHitBonus( OBJECTTYPE * pObj, INT32 iRange, UINT8 bLightLevel, BOOLEAN bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].tohitbonus; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( fProneStance ) - bonus += Item[iter->usItem].bipod; + if(iter->exists()){ + if ( fProneStance ) + bonus += Item[iter->usItem].bipod; - bonus += BonusReduceMore( LaserBonus( &Item[iter->usItem], iRange, bLightLevel), (*iter)[0]->data.objectStatus ); + bonus += BonusReduceMore( LaserBonus( &Item[iter->usItem], iRange, bLightLevel), (*iter)[0]->data.objectStatus ); + } } } @@ -7121,33 +9013,433 @@ INT16 GetToHitBonus( OBJECTTYPE * pObj, INT32 iRange, UINT8 bLightLevel, BOOLEAN return( bonus ); } +// HEADROCK HAM 4: The following functions return the value of new NCTH-related modifiers from an item and all its +// attachments. They are stance-based, meaning that the soldier's stance determines which modifier is referenced. +// For a "default" value, feed the function a value of ubStance=ANIM_STAND. + +INT32 GetFlatBaseModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].flatbasemodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].flatbasemodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + return (iModifier); +} + +INT32 GetPercentBaseModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].percentbasemodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].percentbasemodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +INT32 GetFlatAimModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].flataimmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].flataimmodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + return (iModifier); +} + +INT32 GetPercentAimModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].percentaimmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].percentaimmodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +INT32 GetPercentCapModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].percentcapmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].percentcapmodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +INT32 GetPercentHandlingModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].percenthandlingmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].percenthandlingmodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return ((UINT32)iModifier); +} + +INT32 GetDropCompensationModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].percentdropcompensationmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].percentdropcompensationmodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +// HEADROCK HAM 4: This function returns the Max Counter Force modifier given by the weapon +INT32 GetCounterForceMaxModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].maxcounterforcemodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].maxcounterforcemodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +// HEADROCK HAM 4: This function returns the Counter Force Accuracy modifier given by the weapon +INT32 GetCounterForceAccuracyModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].counterforceaccuracymodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].counterforceaccuracymodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +INT32 GetCounterForceFrequencyModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].counterforcefrequencymodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].counterforcefrequencymodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + return (iModifier); +} + +INT32 GetTargetTrackingModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].targettrackingmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += BonusReduceMore( Item[iter->usItem].targettrackingmodifier[ubRef], (*iter)[0]->data.objectStatus ); + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + +INT32 GetAimLevelsModifier( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + INT32 iModifier=0; + + UINT8 ubRef = GetStanceModifierRef( ubStance ); + + if (pObj->exists() == true) + { + iModifier += Item[pObj->usItem].aimlevelsmodifier[ubRef]; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + iModifier += Item[iter->usItem].aimlevelsmodifier[ubRef]; + } + } + } + iModifier = __max(-100,iModifier); + return (iModifier); +} + INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance ) { INT16 bonus=0; // Snap: bipod is effective only in the prone stance + // CHRISL: We don't want to count both bipod AND bursttohitbonus as some items get both bonuses if (pObj->exists() == true) { if ( fProneStance ) - bonus += Item[pObj->usItem].bipod; - - bonus += BonusReduceMore( Item[pObj->usItem].bursttohitbonus, (*pObj)[0]->data.objectStatus ); + bonus += BonusReduceMore( Item[pObj->usItem].bipod, (*pObj)[0]->data.objectStatus ); + else + bonus += BonusReduceMore( Item[pObj->usItem].bursttohitbonus, (*pObj)[0]->data.objectStatus ); // HEADROCK HAM B2.5: A certain setting in the New Tracer System can turn auto/burst penalties off // entirely, to make up for "Tracer Bump". if ( gGameExternalOptions.ubRealisticTracers != 1 ) - bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bursttohitbonus ; + bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bursttohitbonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( fProneStance ) - bonus += Item[iter->usItem].bipod; - - bonus += BonusReduceMore( Item[iter->usItem].bursttohitbonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + if ( fProneStance ) + bonus += BonusReduceMore( Item[iter->usItem].bipod, (*iter)[0]->data.objectStatus ); + else + bonus += BonusReduceMore( Item[iter->usItem].bursttohitbonus, (*iter)[0]->data.objectStatus ); + } } } return( bonus ); } +void GetRecoil( OBJECTTYPE *pObj, INT8 *bRecoilX, INT8 *bRecoilY, UINT8 ubNumBullet ) +{ + *bRecoilX = 0; + *bRecoilY = 0; + +//CHRISL: TODO: STOMP: The AUTO_WEAPS_OT and AUTO_WEAPONS_NT traits should probably modify recoil in some fashion to show that an experience shooter is +// going to be better at compensating for recoil. Alternatively, perhaps the modifiers should go wherever recoil compensation is handled. Or even both +// places should receive a modifier. + if (ubNumBullet < 2) + { + // The first bullet in a volley never has recoil - it hasn't "set in" yet. Only the second+ bullets + // will have any recoil. + *bRecoilX = 0; + *bRecoilY = 0; + return; + } + + // Determine current gun recoil based on recoil array from the gun's properties. + // We use either the value relevant to this bullet, or the last valid value encountered. + // This allows a gun's recoil to vary during the firing. For instance, the second bullet might have + // 0 vertical recoil, the third might have 1, then the fourth might have 5. Subsequent bullets will + // all have 5 recoil since that's the end of the array. + + // Run X number of times, either to the end of the array or the number of bullets fired. + for (UINT8 X = 1; X <= __min(3,ubNumBullet); X++) + { + // If this value is valid (-127 is considered invalid), record it. + //if (Weapon[pObj->usItem].bRecoilX != -127) + if (Weapon[pObj->usItem].ubRecoilDelay >= X) + { + *bRecoilX = Weapon[pObj->usItem].bRecoilX; + //} + //if (Weapon[pObj->usItem].bRecoilY != -127) + //{ + *bRecoilY = Weapon[pObj->usItem].bRecoilY; + } + } + + // Apply a percentage-based modifier. This can increase or decrease BOTH axes. At most, it can eliminate + // recoil on the gun. + + INT16 sPercentRecoilModifier = GetPercentRecoilModifier( pObj ); + + *bRecoilX += (*bRecoilX * sPercentRecoilModifier ) / 100; + *bRecoilY += (*bRecoilY * sPercentRecoilModifier ) / 100; + + // Apply a flat modifier. This acts on either axis, and if powerful enough can "reverse polarity" of either + // axis recoil. For instance, it can make a gun that normally pulls LEFT start pulling RIGHT instead. + + INT8 bRecoilAdjustX = 0; + INT8 bRecoilAdjustY = 0; + + GetFlatRecoilModifier( pObj, &bRecoilAdjustX, &bRecoilAdjustY ); + + *bRecoilX = __max(0, *bRecoilX + bRecoilAdjustX); + *bRecoilY = __max(0, *bRecoilY + bRecoilAdjustY); + + + + return; +} + +/////////////////////////////////////////////////////// +// HEADROCK HAM 4: This function calculates the flat recoil adjustment for a gun. Flat adjustment increases +// or decreases recoil by a specific number of points in either the vertical or horizontal axes (or both). +// It can potentially cause a weapon it reverse its recoil direction. +void GetFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY ) +{ + + INT8 bRecoilAdjustX = 0; + INT8 bRecoilAdjustY = 0; + + if (pObj->exists() == true) + { + // Inherent item modifiers + bRecoilAdjustX += BonusReduceMore( Item[pObj->usItem].RecoilModifierX, (*pObj)[0]->data.objectStatus ); + bRecoilAdjustY += BonusReduceMore( Item[pObj->usItem].RecoilModifierY, (*pObj)[0]->data.objectStatus ); + + // Ammo item modifiers + bRecoilAdjustX += Item[(*pObj)[0]->data.gun.usGunAmmoItem].RecoilModifierX; + bRecoilAdjustY += Item[(*pObj)[0]->data.gun.usGunAmmoItem].RecoilModifierY; + + // Attachment item modifiers + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + bRecoilAdjustX += BonusReduceMore( Item[iter->usItem].RecoilModifierX, (*iter)[0]->data.objectStatus ); + bRecoilAdjustY += BonusReduceMore( Item[iter->usItem].RecoilModifierY, (*iter)[0]->data.objectStatus ); + } + } + } + + *bRecoilModifierX = bRecoilAdjustX; + *bRecoilModifierY = bRecoilAdjustY; +} + +/////////////////////////////////////////////////////////////////// +// HEADROCK HAM 4: This calculates the percentile recoil adjustment of a gun. +// This adjustment either increases or decreases the gun's vertical and horizontal recoil at the same time. Due to +// the percentage-based nature of this modifier, it cannot cause a gun to reverse its recoil - only diminish it to +// zero. +INT16 GetPercentRecoilModifier( OBJECTTYPE *pObj ) +{ + INT16 sRecoilAdjust = 0; + + if (pObj->exists() == true) + { + // Inherent item modifiers + sRecoilAdjust += BonusReduceMore( Item[pObj->usItem].PercentRecoilModifier, (*pObj)[0]->data.objectStatus ); + + // Ammo item modifiers + sRecoilAdjust += Item[(*pObj)[0]->data.gun.usGunAmmoItem].PercentRecoilModifier; + + // Attachment item modifiers + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + sRecoilAdjust += BonusReduceMore( Item[iter->usItem].PercentRecoilModifier, (*iter)[0]->data.objectStatus ); + } + } + } + + sRecoilAdjust = __max(-100, sRecoilAdjust); + return (sRecoilAdjust); +} + +// HEADROCK HAM 4: This is used by functions that get stance-based modifiers from weapons. It turns a ubEndHeight variable +// as either 0, 1 or 2. +INT8 GetStanceModifierRef( INT8 ubStance ) +{ + switch (ubStance) + { + case ANIM_PRONE: + return(2); + case ANIM_CROUCH: + return(1); + default: + return(0); + } +} INT16 GetDamageBonus( OBJECTTYPE * pObj ) { @@ -7159,7 +9451,9 @@ INT16 GetDamageBonus( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].damagebonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduce( Item[iter->usItem].damagebonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduce( Item[iter->usItem].damagebonus, (*iter)[0]->data.objectStatus ); + } } } @@ -7175,7 +9469,9 @@ INT16 GetMeleeDamageBonus( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].meleedamagebonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduce( Item[iter->usItem].meleedamagebonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduce( Item[iter->usItem].meleedamagebonus, (*iter)[0]->data.objectStatus ); + } } } return( bonus ); @@ -7190,22 +9486,26 @@ INT16 GetPercentAPReduction( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentapreduction; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].percentapreduction, - (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( Item[iter->usItem].percentapreduction, + (*iter)[0]->data.objectStatus ); + } } } return( bonus ); } -INT16 GetMagSizeBonus( OBJECTTYPE * pObj ) +INT16 GetMagSizeBonus( OBJECTTYPE * pObj, UINT8 subObject ) { INT16 bonus = 0; if (pObj->exists() == true) { - bonus = BonusOnOff( Item[pObj->usItem].magsizebonus, (*pObj)[0]->data.objectStatus ); + bonus = BonusOnOff( Item[pObj->usItem].magsizebonus, (*pObj)[subObject]->data.objectStatus ); - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusOnOff( Item[iter->usItem].magsizebonus, (*iter)[0]->data.objectStatus ); + for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) { + if(iter->exists()){ + bonus += BonusOnOff( Item[iter->usItem].magsizebonus, (*iter)[0]->data.objectStatus ); + } } } return( bonus ); @@ -7219,7 +9519,9 @@ INT16 GetBurstSizeBonus( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].burstsizebonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusOnOff( Item[iter->usItem].burstsizebonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusOnOff( Item[iter->usItem].burstsizebonus, (*iter)[0]->data.objectStatus ); + } } } @@ -7243,7 +9545,9 @@ INT16 GetRateOfFireBonus( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].rateoffirebonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].rateoffirebonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( Item[iter->usItem].rateoffirebonus, (*iter)[0]->data.objectStatus ); + } } } return( bonus ); @@ -7254,24 +9558,27 @@ INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance ) INT16 bonus=0; // Snap: bipod is effective only in the prone stance + // CHRISL: We don't want to count both bipod AND bursttohitbonus as some items get both bonuses if (pObj->exists() == true) { if ( fProneStance ) - bonus += Item[pObj->usItem].bipod; - - bonus += BonusReduceMore( Item[pObj->usItem].autofiretohitbonus, (*pObj)[0]->data.objectStatus ); + bonus += BonusReduceMore( Item[pObj->usItem].bipod, (*pObj)[0]->data.objectStatus ); + else + bonus += BonusReduceMore( Item[pObj->usItem].autofiretohitbonus, (*pObj)[0]->data.objectStatus ); // HEADROCK HAM B2.5: This external setting determines whether autofire penalty is affected by // tracer ammo. At setting "1", it is disabled. This goes hand in hand with a new tracer effect that // "bumps" CTH up after firing a tracer bullet. if ( gGameExternalOptions.ubRealisticTracers != 1 ) - bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].autofiretohitbonus ; + bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].autofiretohitbonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( fProneStance ) - bonus += Item[iter->usItem].bipod; - - bonus += BonusReduceMore( Item[iter->usItem].autofiretohitbonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + if ( fProneStance ) + bonus += BonusReduceMore( Item[iter->usItem].bipod, (*iter)[0]->data.objectStatus ); + else + bonus += BonusReduceMore( Item[iter->usItem].autofiretohitbonus, (*iter)[0]->data.objectStatus ); + } } } @@ -7286,7 +9593,9 @@ INT16 GetPercentReadyTimeAPReduction( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentreadytimeapreduction; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].percentreadytimeapreduction, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( Item[iter->usItem].percentreadytimeapreduction, (*iter)[0]->data.objectStatus ); + } } } @@ -7301,7 +9610,9 @@ INT16 GetPercentAutofireAPReduction( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentautofireapreduction; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].percentautofireapreduction, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( Item[iter->usItem].percentautofireapreduction, (*iter)[0]->data.objectStatus ); + } } } @@ -7316,7 +9627,9 @@ INT16 GetPercentReloadTimeAPReduction( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentreloadtimeapreduction; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].percentreloadtimeapreduction, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( Item[iter->usItem].percentreloadtimeapreduction, (*iter)[0]->data.objectStatus ); + } } } return( bonus ); @@ -7330,7 +9643,9 @@ INT16 GetPercentBurstFireAPReduction( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentburstfireapreduction; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].percentburstfireapreduction, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduceMore( Item[iter->usItem].percentburstfireapreduction, (*iter)[0]->data.objectStatus ); + } } } return( bonus ); @@ -7373,12 +9688,21 @@ INT16 GetVisionRangeBonus( SOLDIERTYPE * pSoldier ) //AXP 28.03.2007: CtH bug fix: We also want to check on a firing weapon, "raised" alone is not enough ;) if ( usingGunScope == true ) { + // SANDRO - added scouting check + INT16 sScopebonus = 0; pObj = &( pSoldier->inv[HANDPOS]); if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( Item[iter->usItem].visionrangebonus, (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + sScopebonus += BonusReduceMore( Item[iter->usItem].visionrangebonus, (*iter)[0]->data.objectStatus ); + } } } + if( sScopebonus > 0 && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && gGameOptions.fNewTraitSystem) + { + sScopebonus += gSkillTraitValues.ubSCSightRangebonusWithScopes; + } + bonus += sScopebonus; } return( bonus ); @@ -7434,14 +9758,23 @@ INT16 GetNightVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) // Snap: check only attachments on a raised weapon! if ( usingGunScope == true ) { + // SANDRO - added scouting check + INT16 sScopebonus = 0; pObj = &( pSoldier->inv[HANDPOS]); if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( - NightBonusScale( Item[iter->usItem].nightvisionrangebonus, bLightLevel ), - (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + sScopebonus += BonusReduceMore( + NightBonusScale( Item[iter->usItem].nightvisionrangebonus, bLightLevel ), + (*iter)[0]->data.objectStatus ); + } } } + if( sScopebonus > 0 && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && gGameOptions.fNewTraitSystem) + { + sScopebonus += gSkillTraitValues.ubSCSightRangebonusWithScopes; + } + bonus += sScopebonus; } return( bonus ); @@ -7484,14 +9817,23 @@ INT16 GetCaveVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) // Snap: check only attachments on a raised weapon! if ( usingGunScope == true ) { + // SANDRO - added scouting check + INT16 sScopebonus = 0; pObj = &( pSoldier->inv[HANDPOS]); if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( - NightBonusScale( Item[iter->usItem].cavevisionrangebonus, bLightLevel ), - (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + sScopebonus += BonusReduceMore( + NightBonusScale( Item[iter->usItem].cavevisionrangebonus, bLightLevel ), + (*iter)[0]->data.objectStatus ); + } } } + if( sScopebonus > 0 && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && gGameOptions.fNewTraitSystem) + { + sScopebonus += gSkillTraitValues.ubSCSightRangebonusWithScopes; + } + bonus += sScopebonus; } return( bonus ); @@ -7539,14 +9881,23 @@ INT16 GetDayVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) // difference between NORMAL_LIGHTLEVEL_NIGHT and 0, which represent bright light. if ( usingGunScope == true ) { + // SANDRO - added scouting check + INT16 sScopebonus = 0; pObj = &( pSoldier->inv[HANDPOS]); if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( idiv( Item[iter->usItem].dayvisionrangebonus - * (NORMAL_LIGHTLEVEL_NIGHT - __max(bLightLevel,NORMAL_LIGHTLEVEL_DAY)), (NORMAL_LIGHTLEVEL_NIGHT-NORMAL_LIGHTLEVEL_DAY) ), - (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + sScopebonus += BonusReduceMore( idiv( Item[iter->usItem].dayvisionrangebonus + * (NORMAL_LIGHTLEVEL_NIGHT - __max(bLightLevel,NORMAL_LIGHTLEVEL_DAY)), (NORMAL_LIGHTLEVEL_NIGHT-NORMAL_LIGHTLEVEL_DAY) ), + (*iter)[0]->data.objectStatus ); + } } } + if( sScopebonus > 0 && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && gGameOptions.fNewTraitSystem) + { + sScopebonus += gSkillTraitValues.ubSCSightRangebonusWithScopes; + } + bonus += sScopebonus; } return( bonus ); @@ -7591,14 +9942,23 @@ INT16 GetBrightLightVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel // Snap: check only attachments on a raised weapon! if ( usingGunScope == true ) { + // SANDRO - added scouting check + INT16 sScopebonus = 0; pObj = &( pSoldier->inv[HANDPOS]); if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduceMore( idiv( Item[iter->usItem].brightlightvisionrangebonus - * (NORMAL_LIGHTLEVEL_DAY - bLightLevel), NORMAL_LIGHTLEVEL_DAY ), - (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + sScopebonus += BonusReduceMore( idiv( Item[iter->usItem].brightlightvisionrangebonus + * (NORMAL_LIGHTLEVEL_DAY - bLightLevel), NORMAL_LIGHTLEVEL_DAY ), + (*iter)[0]->data.objectStatus ); + } } } + if( sScopebonus > 0 && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && gGameOptions.fNewTraitSystem) + { + sScopebonus += gSkillTraitValues.ubSCSightRangebonusWithScopes; + } + bonus += sScopebonus; } return( bonus ); @@ -7630,6 +9990,21 @@ INT16 GetTotalVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) bonus += GetBrightLightVisionRangeBonus(pSoldier, bLightLevel); } + // SANDRO - STOMP traits - Scouting bonus for sight range with binoculars and similar + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && pSoldier->pathing.bLevel == 0 ) + { + OBJECTTYPE *pObj = &( pSoldier->inv[HANDPOS]); + if (pObj->exists() == true) + { + // we have no pointer to binoculars, so just check any misc items in hands which have some vision bonus + if ( Item[pObj->usItem].usItemClass & IC_MISC && (Item[pObj->usItem].brightlightvisionrangebonus > 0 || + Item[pObj->usItem].dayvisionrangebonus > 0 || Item[pObj->usItem].nightvisionrangebonus > 0 || Item[pObj->usItem].visionrangebonus > 0 )) + { + bonus += gSkillTraitValues.usSCSightRangebonusWithBinoculars; + } + } + } + return bonus; } @@ -7673,13 +10048,30 @@ UINT8 GetPercentTunnelVision( SOLDIERTYPE * pSoldier ) bonus += Item[usItem].percenttunnelvision; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += Item[iter->usItem].percenttunnelvision; + if(iter->exists()) + bonus += Item[iter->usItem].percenttunnelvision; } } } + // SANDRO - STOMP traits - Scouting tunnel vision reduction with binoculars and similar + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SCOUTING_NT ) && pSoldier->pathing.bLevel == 0 ) + { + OBJECTTYPE *pObj = &( pSoldier->inv[HANDPOS]); + if (pObj->exists() == true) + { + // we have no pointer to binoculars, so just check any misc items in hands which have some vision bonus + if ( Item[pObj->usItem].usItemClass & IC_MISC && (Item[pObj->usItem].brightlightvisionrangebonus > 0 || + Item[pObj->usItem].dayvisionrangebonus > 0 || Item[pObj->usItem].nightvisionrangebonus > 0 || Item[pObj->usItem].visionrangebonus > 0 )) + { + bonus = max( 0, (bonus - gSkillTraitValues.ubSCTunnelVisionReducedWithBinoculars)); + } + } + } // HEADROCK HAM 3.2: Further increase tunnel-vision for cowering characters. - if (gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 3) + // SANDRO - this calls many sub-functions over and over, we should at least skip this for civilians and such + if ((gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 3) && + IS_MERC_BODY_TYPE(pSoldier) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) ) { INT8 bTolerance = CalcSuppressionTolerance( pSoldier ); @@ -7733,7 +10125,7 @@ BOOLEAN HasThermalOptics( SOLDIERTYPE * pSoldier ) OBJECTTYPE* pObj = &pSoldier->inv[HANDPOS]; if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[iter->usItem].thermaloptics ) + if ( Item[iter->usItem].thermaloptics && iter->exists() ) return TRUE; } } @@ -7790,7 +10182,7 @@ BOOLEAN IsDuckbill( OBJECTTYPE * pObj ) return TRUE; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].duckbill ) + if (Item[iter->usItem].duckbill && iter->exists() ) { return( TRUE ); } @@ -7808,6 +10200,7 @@ UINT16 GetPercentNoiseVolume( OBJECTTYPE * pObj ) mod = mod * ( 100 - Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentnoisereduction ) / 100; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) mod = mod * ( 100 - BonusReduce( Item[iter->usItem].percentnoisereduction, (*iter)[0]->data.objectStatus ) ) / 100; } } @@ -7840,7 +10233,7 @@ BOOLEAN IsDetonatorAttached( OBJECTTYPE * pObj ) // return TRUE; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].detonator ) + if (Item[iter->usItem].detonator && iter->exists() ) { return( TRUE ); } @@ -7856,7 +10249,7 @@ BOOLEAN IsRemoteDetonatorAttached( OBJECTTYPE * pObj ) // return TRUE; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].remotedetonator ) + if (Item[iter->usItem].remotedetonator && iter->exists() ) { return( TRUE ); } @@ -7879,7 +10272,7 @@ BOOLEAN IsFlashSuppressor( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier ) return TRUE; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].hidemuzzleflash ) + if (Item[iter->usItem].hidemuzzleflash && iter->exists() ) { return( TRUE ); } @@ -7896,7 +10289,7 @@ INT16 GetFlashSuppressorStatus( OBJECTTYPE * pObj ) p=(*pObj)[0]->data.objectStatus; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].hidemuzzleflash ) + if (Item[iter->usItem].hidemuzzleflash && iter->exists() ) { p =p+ (*iter)[0]->data.objectStatus; } @@ -7906,14 +10299,14 @@ INT16 GetFlashSuppressorStatus( OBJECTTYPE * pObj ) return p; } -BOOLEAN IsGrenadeLauncherAttached( OBJECTTYPE * pObj ) +BOOLEAN IsGrenadeLauncherAttached( OBJECTTYPE * pObj, UINT8 subObject ) { if (pObj->exists() == true) { if (Item[pObj->usItem].grenadelauncher ) return TRUE; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].grenadelauncher ) + for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) { + if (Item[iter->usItem].grenadelauncher && iter->exists() ) { return TRUE; } @@ -7929,7 +10322,7 @@ OBJECTTYPE* FindAttachment_GrenadeLauncher( OBJECTTYPE * pObj ) return pObj; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].grenadelauncher ) + if (Item[iter->usItem].grenadelauncher && iter->exists() ) { return( &(*iter) ); } @@ -7944,7 +10337,7 @@ INT16 GetGrenadeLauncherStatus( OBJECTTYPE * pObj ) return (*pObj)[0]->data.objectStatus; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].grenadelauncher ) + if (Item[iter->usItem].grenadelauncher && iter->exists()) { return( (*iter)[0]->data.objectStatus ); } @@ -7959,7 +10352,7 @@ UINT16 GetAttachedGrenadeLauncher( OBJECTTYPE * pObj ) return pObj->usItem; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].grenadelauncher ) + if (Item[iter->usItem].grenadelauncher && iter->exists()) { return( (UINT16) Item[iter->usItem].uiIndex ); } @@ -7975,8 +10368,10 @@ INT16 GetAttachedArmourBonus( OBJECTTYPE * pObj ) if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += BonusReduce( Armour[Item[iter->usItem].ubClassIndex].ubProtection, - (*iter)[0]->data.objectStatus ); + if(iter->exists()){ + bonus += BonusReduce( Armour[Item[iter->usItem].ubClassIndex].ubProtection, + (*iter)[0]->data.objectStatus ); + } } } return( bonus ); @@ -7991,6 +10386,7 @@ INT16 GetBulletSpeedBonus( OBJECTTYPE * pObj ) bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].bulletspeedbonus ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) bonus = bonus +Item[iter->usItem].bulletspeedbonus ; } } @@ -8075,7 +10471,7 @@ OBJECTTYPE* FindAttachedBatteries( OBJECTTYPE * pObj ) { if (pObj->exists() == true) { for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].batteries ) + if (Item[iter->usItem].batteries && iter->exists()) { return( &(*iter) ); } @@ -8230,7 +10626,8 @@ UINT16 PickARandomLaunchable(UINT16 itemIndex) UINT16 lowestCoolness = LowestLaunchableCoolness(itemIndex); //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("PickARandomLaunchable: itemIndex = %d", itemIndex)); - while( !usNumMatches ) + // WANNE: This should fix the hang on the merc positioning screen (fix by Razer) + //while( !usNumMatches ) { //Count the number of valid launchables for( i = 0; i < MAXITEMS; i++ ) { @@ -8241,6 +10638,7 @@ UINT16 PickARandomLaunchable(UINT16 itemIndex) usNumMatches++; } } + if( usNumMatches ) { usRandom = (UINT16)Random( usNumMatches ); @@ -8270,7 +10668,7 @@ INT16 GetCamoBonus( OBJECTTYPE * pObj ) bonus = (Item[pObj->usItem].camobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (!Item[iter->usItem].camouflagekit) + if (!Item[iter->usItem].camouflagekit && iter->exists()) bonus += (INT16) (Item[iter->usItem].camobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100)); } } @@ -8283,7 +10681,7 @@ INT16 GetUrbanCamoBonus( OBJECTTYPE * pObj ) bonus = (Item[pObj->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (!Item[iter->usItem].camouflagekit) + if (!Item[iter->usItem].camouflagekit && iter->exists()) bonus += (INT16) (Item[iter->usItem].urbanCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100)); } } @@ -8296,7 +10694,7 @@ INT16 GetDesertCamoBonus( OBJECTTYPE * pObj ) bonus = (Item[pObj->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (!Item[iter->usItem].camouflagekit) + if (!Item[iter->usItem].camouflagekit && iter->exists()) bonus += (INT16) (Item[iter->usItem].desertCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100)); } } @@ -8309,7 +10707,7 @@ INT16 GetSnowCamoBonus( OBJECTTYPE * pObj ) bonus = (Item[pObj->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*pObj)[0]->data.objectStatus) / 100)) ; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (!Item[iter->usItem].camouflagekit) + if (!Item[iter->usItem].camouflagekit && iter->exists()) bonus += (INT16) (Item[iter->usItem].snowCamobonus);// * (WEAPON_STATUS_MOD((*iter)[0]->data.objectStatus) / 100)); } } @@ -8480,18 +10878,24 @@ OBJECTTYPE* FindSunGogglesInInv( SOLDIERTYPE * pSoldier, BOOLEAN searchAllInvent INT16 bonusToBeat = 0; OBJECTTYPE* pGoggles = 0; // CHRISL: + // silversurfer: use the sum of day vision bonus and bright light bonus because both help at daytime + // but make sure that day vision bonus is > 0 because we are not always looking at bright lights for (bLoop = (searchAllInventory ? HELMETPOS : HANDPOS); bLoop < NUM_INV_SLOTS; bLoop++) { if ( pSoldier->inv[bLoop].exists() == true ) { - if (Item[pSoldier->inv[bLoop].usItem].brightlightvisionrangebonus > bonusToBeat && Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) { + if ( Item[pSoldier->inv[bLoop].usItem].dayvisionrangebonus > 0 && + ( Item[pSoldier->inv[bLoop].usItem].dayvisionrangebonus + Item[pSoldier->inv[bLoop].usItem].brightlightvisionrangebonus ) > bonusToBeat && + Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) { pGoggles = &(pSoldier->inv[bLoop]); - bonusToBeat = Item[pSoldier->inv[bLoop].usItem].brightlightvisionrangebonus; + bonusToBeat = Item[pSoldier->inv[bLoop].usItem].dayvisionrangebonus + Item[pSoldier->inv[bLoop].usItem].brightlightvisionrangebonus; } if (searchAllInventory) { OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].brightlightvisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE ) { + if ( Item[ iter->usItem ].dayvisionrangebonus > 0 && + ( Item[ iter->usItem ].dayvisionrangebonus + Item[ iter->usItem ].brightlightvisionrangebonus ) > bonusToBeat && + Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists() ) { pGoggles = &(*iter); - bonusToBeat = Item[ iter->usItem ].brightlightvisionrangebonus; + bonusToBeat = Item[ iter->usItem ].dayvisionrangebonus + Item[ iter->usItem ].brightlightvisionrangebonus; } } } @@ -8506,26 +10910,71 @@ OBJECTTYPE* FindNightGogglesInInv( SOLDIERTYPE * pSoldier, BOOLEAN searchAllInve INT16 bonusToBeat = 0; OBJECTTYPE* pGoggles = 0; // CHRISL: - for (bLoop = (searchAllInventory ? HELMETPOS : HANDPOS); bLoop < NUM_INV_SLOTS; bLoop++) { - if ( pSoldier->inv[bLoop].exists() == true ) { - if (Item[pSoldier->inv[bLoop].usItem].nightvisionrangebonus > bonusToBeat && Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) { - pGoggles = &(pSoldier->inv[bLoop]); - bonusToBeat = Item[pSoldier->inv[bLoop].usItem].nightvisionrangebonus; - } - if (searchAllInventory) { - OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]); - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].nightvisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE ) { - pGoggles = &(*iter); - bonusToBeat = Item[ iter->usItem ].nightvisionrangebonus; + // silversurfer: check if we are above ground, night vision is only useful there + if ( pSoldier->bSectorZ == 0 ) + { + for (bLoop = (searchAllInventory ? HELMETPOS : HANDPOS); bLoop < NUM_INV_SLOTS; bLoop++) { + if ( pSoldier->inv[bLoop].exists() == true ) { + if (Item[pSoldier->inv[bLoop].usItem].nightvisionrangebonus > bonusToBeat && Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) { + pGoggles = &(pSoldier->inv[bLoop]); + bonusToBeat = Item[pSoldier->inv[bLoop].usItem].nightvisionrangebonus; + } + if (searchAllInventory) { + OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]); + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if ( Item[ iter->usItem ].nightvisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists() ) { + pGoggles = &(*iter); + bonusToBeat = Item[ iter->usItem ].nightvisionrangebonus; + } } } } } } + // below ground we need cave vision + else + { + for (bLoop = (searchAllInventory ? HELMETPOS : HANDPOS); bLoop < NUM_INV_SLOTS; bLoop++) { + if ( pSoldier->inv[bLoop].exists() == true ) { + if (Item[pSoldier->inv[bLoop].usItem].cavevisionrangebonus > bonusToBeat && Item[pSoldier->inv[bLoop].usItem].usItemClass == IC_FACE ) { + pGoggles = &(pSoldier->inv[bLoop]); + bonusToBeat = Item[pSoldier->inv[bLoop].usItem].cavevisionrangebonus; + } + if (searchAllInventory) { + OBJECTTYPE* pObj = &(pSoldier->inv[bLoop]); + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if ( Item[ iter->usItem ].cavevisionrangebonus > bonusToBeat && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists() ) { + pGoggles = &(*iter); + bonusToBeat = Item[ iter->usItem ].cavevisionrangebonus; + } + } + } + } + } + } + return( pGoggles ); } +FLOAT GetHighestScopeMagnificationFactor( OBJECTTYPE * pObj ) +{ + FLOAT BestFactor = 1.0; + + if ( pObj->exists() == true ) { + BestFactor = Item[pObj->usItem].scopemagfactor; + + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + BestFactor = __max(BestFactor, Item[iter->usItem].scopemagfactor); + } + } + } + + return( BestFactor ); +} + INT16 GetMinRangeForAimBonus( OBJECTTYPE * pObj ) { INT16 bonus = 0; @@ -8542,131 +10991,531 @@ INT16 GetMinRangeForAimBonus( OBJECTTYPE * pObj ) return( bonus ); } -UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier) +FLOAT GetBestScopeMagnificationFactor( OBJECTTYPE * pObj, UINT32 uiRange ) +{ + FLOAT BestFactor = 1.0; + FLOAT TargetMagFactor = __max(1.0f,(FLOAT)uiRange / (FLOAT)gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + FLOAT CurrentFactor = 0.0; + FLOAT ActualCurrentFactor = 0.0; + INT32 iCurrentTotalPenalty = 0; + INT32 iBestTotalPenalty = 100; + + if (TargetMagFactor <= 1.0f) + { + // Target is at Iron Sights range. No scope is required. + return 1.0f; + } + + if ( pObj->exists() == true ) + { + // Real Scope Magnification Factor from the item + CurrentFactor = __max(1.0f, Item[pObj->usItem].scopemagfactor); + + if (CurrentFactor > 1.0f) + { + // Actual Scope Mag Factor is what we get at the distance the target's at. + ActualCurrentFactor = __min(CurrentFactor, TargetMagFactor); + + if (TargetMagFactor >= CurrentFactor) + { + // This scope gives no penalty. Record this as the best factor found so far. + BestFactor = CurrentFactor; + // Record the penalty (or rather, the bonus) this scope gives. + iBestTotalPenalty = (INT32)((-1) * ((CurrentFactor * 100) - 100)); + } + else + { + // This scopes gives a penalty for shooting under its range. Let's figure out whether + // the scope's mag factor is worth the penalty it gives. + FLOAT dScopePenaltyRatio = (CurrentFactor / TargetMagFactor)-1.0f; + INT32 iScopePenalty = abs((INT32)(dScopePenaltyRatio * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE) * (CurrentFactor / 2)); + + // How much bonus does this scope mag factor give us at this range? + INT32 iScopeBonus = (INT32)((ActualCurrentFactor * 100) - 100); + + // Do we get any benefit from using this scope? + if (iScopeBonus - iScopePenalty >= 0) + { + // This scope gives at least some benefit, so let's record how much. + BestFactor = CurrentFactor; + iBestTotalPenalty = iScopePenalty - iScopeBonus; + } + else + { + // This scope gives more penalty than it's worth. Ignore it! + } + } + + } + + // Now perform the same process for each scope installed on the item. The difference is, we also compare to + // BestTotalPenalty to find the scope that gives the least penalty compared to its bonus. + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists() && Item[iter->usItem].scopemagfactor > 1.0f) + { + // Real Scope Magnification Factor from the item + CurrentFactor = __max(1.0f, Item[iter->usItem].scopemagfactor); + + // Actual Scope Mag Factor is what we get at the distance the target's at. + ActualCurrentFactor = __min(CurrentFactor, TargetMagFactor); + + if (TargetMagFactor >= CurrentFactor) + { + // This scope gives no penalty. Is it any better than the ones we've already processed? + iCurrentTotalPenalty = (INT32)((-1) * ((CurrentFactor * 100) - 100)); + if (iCurrentTotalPenalty < iBestTotalPenalty) + { + // This is the best scope we've found so far. Record it. + BestFactor = CurrentFactor; + // Record the penalty (or rather, the bonus) this scope gives. + iBestTotalPenalty = iCurrentTotalPenalty; + } + else + { + // Ignore this scope, it can't match any others found on this gun, at this range. + continue; + } + } + else + { + // This scope will give a penalty if used. Is it worth using compared to other scopes found? + FLOAT dScopePenaltyRatio = (CurrentFactor / TargetMagFactor)-1.0f; + INT32 iScopePenalty = abs((INT32)(dScopePenaltyRatio * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE * (CurrentFactor/2))); + + // How much bonus does this scope mag factor give us at this range? + INT32 iScopeBonus = (INT32)((ActualCurrentFactor * 100) - 100); + + // Do we get any benefit from using this scope? + if (iScopeBonus - iScopePenalty >= 0) + { + // Is this scope any better than the ones we've already processed? + iCurrentTotalPenalty = iScopePenalty - iScopeBonus; + if (iCurrentTotalPenalty < iBestTotalPenalty) + { + // This is the best scope we've found so far. Record it. + BestFactor = CurrentFactor; + // Record the penalty (or rather, the bonus) this scope gives. + iBestTotalPenalty = iCurrentTotalPenalty; + } + else + { + // We've found better scopes before. Ignore it. + continue; + } + } + else + { + // This scope gives more penalty than it's worth. Ignore it! + } + } + } + } + + } + + return( __max(1.0f, BestFactor) ); +} + +// HEADROCK HAM 4: This function finds the best projection equipment (laser/reflex) on the weapon for a given range. +FLOAT GetProjectionFactor( OBJECTTYPE * pObj ) +{ + FLOAT BestFactor = 1.0; + + if ( pObj->exists() == true ) { + BestFactor = __max((FLOAT)Item[pObj->usItem].projectionfactor, 1.0f); + + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + BestFactor = __max(BestFactor, Item[iter->usItem].projectionfactor); + } + } + } + + return( BestFactor ); +} + +UINT8 AllowedAimingLevelsNCTH( SOLDIERTYPE *pSoldier, INT32 sGridNo ) { UINT8 aimLevels = 4; - UINT16 usScopeBonus = 0; + FLOAT iScopeMagFactor = 0.0, rangeMultiplier = gGameCTHConstants.SCOPE_RANGE_MULTIPLIER; BOOLEAN allowed = TRUE; + INT8 ubSkillModifier; + UINT16 weaponRange; + UINT8 weaponType; + BOOLEAN fTwoHanded, fUsingBipod; + UINT32 uiRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); - if ( gGameSettings.fOptions[TOPTION_AIM_LEVEL_RESTRICTION] ) // Options Menu setting. + // HEADROCK HAM 4: This function has been radically altered AGAIN for the NCTH project. + // Weapons can now have a tag that defines how many aim clicks they should have. Under the NCTH + // system, weapons with FEWER aiming clicks are faster to aim without being any less accurate. + // + // If the weapon lacks a ubAimLevels tag, the program uses the old HAM 3 algorithm to figure + // out how much it should have using its class and range. + + // Read from item + aimLevels = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubAimLevels; + fTwoHanded = Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded; + weaponRange = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usRange + GetRangeBonus(&pSoldier->inv[pSoldier->ubAttackingHand]); + weaponType = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType; + fUsingBipod = FALSE; + + // If outside limits... + if (aimLevels < 1 || + aimLevels > 8 ) + { + // Probably uninitialized. Run an algorithm instead. + + // Read weapon data + + // Define basic (no attachments), and absolute maximums + if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || fTwoHanded == 0) + { + aimLevels = 2; + } + else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || weaponType == GUN_SMG) + { + aimLevels = 3; + } + else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE ) && weaponRange <= 500) + { + aimLevels = 4; + } + else if (((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE) && weaponRange > 500) || + (weaponType == GUN_SN_RIFLE && weaponRange <= 500)) + { + aimLevels = 6; + } + else if (weaponType == GUN_SN_RIFLE && weaponRange > 500) + { + aimLevels = 8; + } + else + { + aimLevels = 4; + } + } + + // HEADROCK HAM 4: This modifier from the weapon and its attachments replaces the generic bipod bonus. + aimLevels += GetAimLevelsModifier( &pSoldier->inv[pSoldier->ubAttackingHand], gAnimControl[ pSoldier->usAnimState ].ubHeight ); + + // HEADROCK HAM 4: Sniper skill reduces aiming levels by one per skill level. This actually makes guns FASTER + // to aim, since aiming-bonus per click is based on the number of allowed levels. + iScopeMagFactor = GetBestScopeMagnificationFactor(&pSoldier->inv[pSoldier->ubAttackingHand], uiRange); + + if( gGameOptions.fNewTraitSystem ) + { + if(iScopeMagFactor > .5) + rangeMultiplier -= (NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ) * 0.05f); + else + rangeMultiplier -= (NUM_SKILL_TRAITS( pSoldier, RANGER_NT ) * 0.05f); + if ( weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL ) + ubSkillModifier = NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); + else + ubSkillModifier = NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); + aimLevels -= ubSkillModifier; + } + else + { + rangeMultiplier -= (NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT ) * 0.05f); + ubSkillModifier = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT ); + if (iScopeMagFactor > 1.0f && (iScopeMagFactor * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE * rangeMultiplier) <= uiRange) + { + // Make sure final level isn't going to be below 1... + aimLevels -= ubSkillModifier; + } + } + + aimLevels = __max(1, aimLevels); + aimLevels = __min(8, aimLevels); + + return aimLevels; + } + +UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier, INT32 sGridNo) +{ + if(UsingNewCTHSystem() == true) + return AllowedAimingLevelsNCTH(pSoldier, sGridNo); + + // SANDRO was here - changed a few things around + + UINT8 aimLevels = 4; + UINT16 sScopeBonus = 0; + BOOLEAN allowed = TRUE; + UINT8 weaponType; + + INT32 uiRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); + + weaponType = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType; + + if ( gGameExternalOptions.fAimLevelRestriction ) // Extra aiming on/off { // HEADROCK HAM B2.6: Dynamic aiming level restrictions based on gun type and attachments. // HEADROCK HAM 3.5: Revamped this - it was illogically constructed. - if ( gGameExternalOptions.fDynamicAimingTime ) - { - UINT16 weaponRange; - UINT8 weaponType, maxAimForType, maxAimWithoutBipod; - BOOLEAN fTwoHanded, fUsingBipod; - - // Read weapon data - fTwoHanded = Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded; - weaponRange = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usRange + GetRangeBonus(&pSoldier->inv[pSoldier->ubAttackingHand]); - weaponType = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubWeaponType; - fUsingBipod = FALSE; + if ( gGameExternalOptions.fDynamicAimingTime ) + { + // SANDRO - throwing knives are a special case, allow two aiming clicks for them + if( weaponType == NOT_GUN ) + { + if ( Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usItemClass == IC_THROWING_KNIFE ) + { + aimLevels = 2; + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, THROWING_NT ) ) + { + aimLevels += gSkillTraitValues.ubTHBladesAimClicksAdded; + } + return ( min(6, aimLevels) ); + } + else + { + return ( 2 ); + } + } + + UINT16 weaponRange; + UINT8 maxAimForType, maxAimWithoutBipod; + BOOLEAN fTwoHanded, fUsingBipod; + + // Read weapon data + fTwoHanded = Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded; + + UINT16 usRange = GetModifiedGunRange(pSoldier->inv[pSoldier->ubAttackingHand].usItem); + + weaponRange = usRange + GetRangeBonus(&pSoldier->inv[pSoldier->ubAttackingHand]); + fUsingBipod = FALSE; - maxAimWithoutBipod = 4; - - // Define basic (no attachments), and absolute maximums - if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || fTwoHanded == 0) - { - maxAimForType = 2; - aimLevels = 1; - maxAimWithoutBipod = 2; - } - else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || weaponType == GUN_SMG) - { - maxAimForType = 3; - aimLevels = 2; - maxAimWithoutBipod = 3; - } - else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE ) && weaponRange <= 500) - { - maxAimForType = 4; - aimLevels = 2; - maxAimWithoutBipod = 3; - } - else if (((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE) && weaponRange > 500) || - (weaponType == GUN_SN_RIFLE && weaponRange <= 500)) - { - maxAimForType = 6; - aimLevels = 3; maxAimWithoutBipod = 4; - } + + // Define basic (no attachments), and absolute maximums + if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL ) + { + maxAimForType = 2; + aimLevels = 1; + maxAimWithoutBipod = 2; + + // SANDRO - STOMP traits - Gunslinger bonus aim clicks + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) ) + { + maxAimForType += (gSkillTraitValues.ubGSAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )); + aimLevels += (gSkillTraitValues.ubGSAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )); + maxAimWithoutBipod += (gSkillTraitValues.ubGSAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )); + } + } + else if ((weaponType == GUN_SMG && fTwoHanded == 0) || fTwoHanded == 0) + { + maxAimForType = 2; + aimLevels = 1; + maxAimWithoutBipod = 2; + } + else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || (weaponType == GUN_SMG && fTwoHanded == 1)) + { + maxAimForType = 3; + aimLevels = 2; + maxAimWithoutBipod = 3; + } + else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE ) && weaponRange <= 500) + { + maxAimForType = 4; + aimLevels = 2; + maxAimWithoutBipod = 3; + + // SANDRO - STOMP traits - Sniper bonus aim clicks + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) + { + maxAimForType += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + aimLevels += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + maxAimWithoutBipod += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + } + } + else if (((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE) && weaponRange > 500) || + (weaponType == GUN_SN_RIFLE && weaponRange <= 500)) + { + maxAimForType = 6; + aimLevels = 3; + maxAimWithoutBipod = 4; + // SANDRO - STOMP traits - Sniper bonus aim clicks + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) + { + maxAimForType += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + aimLevels += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + maxAimWithoutBipod += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + } + } else if (weaponType == GUN_SN_RIFLE && weaponRange > 500) { maxAimForType = 8; aimLevels = 4; maxAimWithoutBipod = 3; + + // SANDRO - STOMP traits - Sniper bonus aim clicks + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) + { + maxAimForType += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + aimLevels += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + maxAimWithoutBipod += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + } } - else - { - return 4; - } - - // Determine whether a bipod is being used (prone) - if (GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])>0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) - { - fUsingBipod = TRUE; - } - - usScopeBonus = ( GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) * 10 ) / gGameExternalOptions.ubStraightSightRange; - - if ( usScopeBonus >= 50 ) // Scope Min Range >= 7 Tiles + else { - aimLevels *= 2; + return 4; } - else if ( usScopeBonus >= 30 ) // Scope Min Range >= 4 Tiles + // Determine whether a bipod is being used (prone) + if (GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])>0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) { - aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5); + fUsingBipod = TRUE; } - else if ( usScopeBonus >= 15 ) // Scope Min Range >= 2 Tiles + // don't break compatibility, let the users choose + sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? + //WarmSteel - Using scope aimbonus instead, as it is used elsewhere like this too. + //Also, you won't get extra aimclicks anymore if you're too close to use your scope. + //I've externalized the scope types. + GetBaseScopeAimBonus( &pSoldier->inv[pSoldier->ubAttackingHand], uiRange ) + : GetMinRangeForAimBonus( &pSoldier->inv[pSoldier->ubAttackingHand]); + + if ( sScopeBonus >= gGameExternalOptions.sVeryHighPowerScope ) + { + aimLevels *= 2; + } + + else if ( sScopeBonus >= gGameExternalOptions.sHighPowerScope ) + { + aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5); + } + + else if ( sScopeBonus >= gGameExternalOptions.sMediumPowerScope ) + { + aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.3); + } + + // Smaller scopes increase by one. + else if ( sScopeBonus > 0 ) + { + aimLevels++; + } + + // Make sure not over maximum allowed for weapon type. + if (aimLevels > maxAimForType) { - aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.3); + aimLevels = maxAimForType; } - - // Smaller scopes increase by one. - else if ( usScopeBonus > 0 ) + // Make sure not over maximum allowed without a bipod. + if (!fUsingBipod) { - aimLevels++; + aimLevels = __min(aimLevels, maxAimWithoutBipod); } - - // Make sure not over maximum allowed for weapon type. - if (aimLevels > maxAimForType) - { - aimLevels = maxAimForType; } - // Make sure not over maximum allowed without a bipod. - if (!fUsingBipod) + else // JA2 1.13 Basic aiming restrictions (8 levels for 10x scope, 6 levels for 7x scope) { - aimLevels = __min(aimLevels, maxAimWithoutBipod); - } - } - else // JA2 1.13 Basic aiming restrictions (8 levels for 10x scope, 6 levels for 7x scope) - { - if ( !IsScoped( &pSoldier->inv[pSoldier->ubAttackingHand] ) ) + OBJECTTYPE* pAttackingWeapon = &pSoldier->inv[pSoldier->ubAttackingHand]; + if ( !IsScoped( pAttackingWeapon ) ) { // No scope. 4 Allowed. return (4); } - usScopeBonus = ( GetMinRangeForAimBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) * 10 ) / gGameExternalOptions.ubStraightSightRange; - - if ( usScopeBonus >= 50 ) // Scope Min Range >= 7 Tiles (Sniper Scope) + //CHRRISL: yeah, this doesn't work. GetMinRangeForAimBonus returns a range value in units while GetBaseScopeAimBonus returns a small number. + // The result is that if fAimLevelsDependOnDistance is false, all scopes are going to grant +4 aim clicks which is definitely not what + // we want to happen. What we do want is simply to know whether we should send the range or use an extreme range value to guarantee that + // the scope is factored. + // don't break compatibility, let the users choose +// sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? +// GetBaseScopeAimBonus( pAttackingWeapon, iRange ) +// : GetMinRangeForAimBonus( pAttackingWeapon ); + sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? GetBaseScopeAimBonus( pAttackingWeapon, uiRange ) : GetBaseScopeAimBonus( pAttackingWeapon, 25000 ); + + if ( sScopeBonus >= gGameExternalOptions.sVeryHighPowerScope ) { aimLevels += 2; } - if ( usScopeBonus >= 30 ) // Scope Min Range >= 4 Tiles (Battle Scope) + if ( sScopeBonus >= gGameExternalOptions.sHighPowerScope ) { aimLevels += 2; } + // SANDRO - STOMP traits - Sniper bonus aim clicks + if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && + gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) + { + aimLevels += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + } + // SANDRO - STOMP traits - Gunslinger bonus aim clicks + if ((weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL) && + gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) ) + { + aimLevels += (gSkillTraitValues.ubGSAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )); + } + //CHRISL: The system can't currently support more then 8 aim levels so make sure we can never have more then 8 + aimLevels = min(8, aimLevels); } } return aimLevels; } + +UINT8 GetAllowedAimingLevelsForItem( OBJECTTYPE *pObj, UINT8 ubStance ) +{ + if ( !(Item[pObj->usItem].usItemClass & (IC_GUN|IC_LAUNCHER|IC_THROWING_KNIFE)) ) + { + return 1; + } + + UINT8 aimLevels = 4; + + // HEADROCK HAM B2.6: Dynamic aiming level restrictions based on gun type and attachments. + // HEADROCK HAM 3.5: Revamped this - it was illogically constructed. + if ( gGameExternalOptions.fDynamicAimingTime ) + { + UINT16 weaponRange; + UINT8 weaponType; + BOOLEAN fTwoHanded, fUsingBipod; + + // Read weapon data + fTwoHanded = Item[pObj->usItem].twohanded; + weaponRange = Weapon[Item[pObj->usItem].ubClassIndex].usRange + GetRangeBonus(pObj); + weaponType = Weapon[Item[pObj->usItem].ubClassIndex].ubWeaponType; + fUsingBipod = FALSE; + + // Define basic (no attachments), and absolute maximums + if (weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL || fTwoHanded == 0) + { + aimLevels = 2; + } + else if (weaponType == GUN_SHOTGUN || weaponType == GUN_LMG || weaponType == GUN_SMG) + { + aimLevels = 3; + } + else if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE ) && weaponRange <= 500) + { + aimLevels = 4; + } + else if (((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE) && weaponRange > 500) || + (weaponType == GUN_SN_RIFLE && weaponRange <= 500)) + { + aimLevels = 6; + } + else if (weaponType == GUN_SN_RIFLE && weaponRange > 500) + { + aimLevels = 8; + } + else + { + return 4; + } + + // HEADROCK HAM 4: This modifier from the weapon and its attachments replaces the generic bipod bonus. + aimLevels += GetAimLevelsModifier( pObj, ubStance ); + + aimLevels = __max(1, aimLevels); + aimLevels = __min(8, aimLevels); + + } + return aimLevels; +} + //Madd: added INT16 GetStealthBonus( OBJECTTYPE * pObj ) { @@ -8675,7 +11524,8 @@ INT16 GetStealthBonus( OBJECTTYPE * pObj ) bonus = BonusReduce(Item[pObj->usItem].stealthbonus,(*pObj)[0]->data.objectStatus); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += (INT16) BonusReduce(Item[iter->usItem].stealthbonus,(*iter)[0]->data.objectStatus); + if(iter->exists()) + bonus += (INT16) BonusReduce(Item[iter->usItem].stealthbonus,(*iter)[0]->data.objectStatus); } } return( bonus ); @@ -8695,6 +11545,10 @@ INT16 GetWornStealth( SOLDIERTYPE * pSoldier ) ttl += GetStealthBonus(&pSoldier->inv[bLoop]); } + // Add some default stealth ability to mercs with STEALTHY trait - SANDRO + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) + ttl += gSkillTraitValues.ubSTStealthBonus; + return __min( ttl, 100 ); } @@ -8705,6 +11559,28 @@ INT16 GetWornStealth( SOLDIERTYPE * pSoldier ) // other variable. //////////////////////////// +//WarmSteel - Function to get the total reliability from the gun and its attachments +INT16 GetReliability( OBJECTTYPE * pObj ) +{ + INT16 bonus = 0; + + bonus += Item[pObj->usItem].bReliability; + + //Ammo modifications need to be added aswell + if ( Item[ pObj->usItem ].usItemClass == IC_GUN && (*pObj)[0]->data.gun.ubGunShotsLeft > 0 ) + { + bonus += Item[( *pObj )[0]->data.gun.usGunAmmoItem].bReliability; + } + + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if(iter->exists()) + bonus += Item[iter->usItem].bReliability; + } + + return( bonus ); +} + // HEADROCK: Function to get the total aim-bonus from the gun and its attachments INT16 GetFlatAimBonus( OBJECTTYPE * pObj ) { @@ -8712,9 +11588,10 @@ INT16 GetFlatAimBonus( OBJECTTYPE * pObj ) bonus += Item[pObj->usItem].aimbonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += Item[iter->usItem].aimbonus; + if(iter->exists()) + bonus += Item[iter->usItem].aimbonus; } return( bonus ); @@ -8728,6 +11605,14 @@ INT16 GetFinalLoudness( OBJECTTYPE * pObj ) loudness = Weapon[Item[pObj->usItem].ubClassIndex].ubAttackVolume; + + // WANNE: Fix by Headrock + // It seems that the game calculates noise reduction not by adding together the reduction from ammo and all attachments, + // but by applying them to the gun's loudness as percentages one by one. + // So instead of (60+20)% it does 60% and then 20%, giving completely different results. + loudness = ( loudness * GetPercentNoiseVolume( pObj ) ) / 100; + + /* loudnessModifier += Item[pObj->usItem].percentnoisereduction; if ( (*pObj)[0]->data.gun.ubGunShotsLeft > 0 ) @@ -8739,6 +11624,8 @@ INT16 GetFinalLoudness( OBJECTTYPE * pObj ) } loudness = loudness * ( 100 - loudnessModifier ) / 100; + */ + loudness = __max(loudness, 1); return ( loudness ); @@ -8752,9 +11639,9 @@ INT16 GetAPBonus( OBJECTTYPE * pObj ) bonus += Item[ pObj->usItem ].APBonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].APBonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].APBonus; } return( bonus ); @@ -8768,9 +11655,9 @@ INT16 GetFlatToHitBonus( OBJECTTYPE * pObj ) bonus = Item[pObj->usItem].tohitbonus; bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].tohitbonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].tohitbonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter){ + if(iter->exists()) + bonus += Item[iter->usItem].tohitbonus; } return( bonus ); @@ -8789,7 +11676,7 @@ INT16 GetAverageBestLaserRange( OBJECTTYPE * pObj ) } for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].bestlaserrange > 0) + if (Item[iter->usItem].bestlaserrange > 0 && iter->exists()) { numModifiers++; bonus += Item[iter->usItem].bestlaserrange; @@ -8811,9 +11698,9 @@ INT16 GetBipodBonus( OBJECTTYPE * pObj ) bonus = Item[pObj->usItem].bipod; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].bipod; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter){ + if(iter->exists()) + bonus += Item[iter->usItem].bipod; } return( bonus ); @@ -8834,45 +11721,45 @@ INT16 GetItemVisionRangeBonus( OBJECTTYPE * pObj, INT16 VisionType ) { bonus += Item[ pObj->usItem ].visionrangebonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].visionrangebonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].visionrangebonus; } } else if (VisionType == 1) { bonus += Item[ pObj->usItem ].dayvisionrangebonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].dayvisionrangebonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].dayvisionrangebonus; } } else if (VisionType == 2) { bonus += Item[ pObj->usItem ].nightvisionrangebonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].nightvisionrangebonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].nightvisionrangebonus; } } else if (VisionType == 3) { bonus += Item[ pObj->usItem ].brightlightvisionrangebonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].brightlightvisionrangebonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].brightlightvisionrangebonus; } } else if (VisionType == 4) { bonus += Item[ pObj->usItem ].cavevisionrangebonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].cavevisionrangebonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].cavevisionrangebonus; } } @@ -8888,9 +11775,9 @@ UINT8 GetItemPercentTunnelVision( OBJECTTYPE * pObj ) bonus += Item[ pObj->usItem ].percenttunnelvision; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[iter->usItem].percenttunnelvision; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[iter->usItem].percenttunnelvision; } bonus = __min(bonus, 100); @@ -8905,9 +11792,9 @@ INT16 GetItemHearingRangeBonus( OBJECTTYPE * pObj ) bonus += Item[ pObj->usItem ].hearingrangebonus; - for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) - { - bonus += Item[ iter->usItem ].hearingrangebonus; + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()) + bonus += Item[ iter->usItem ].hearingrangebonus; } return( bonus ); @@ -8927,7 +11814,7 @@ BOOLEAN IsFlashSuppressorAlt( OBJECTTYPE * pObj ) return TRUE; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].hidemuzzleflash ) + if (Item[iter->usItem].hidemuzzleflash && iter->exists() ) { return( TRUE ); } @@ -8943,12 +11830,68 @@ INT16 GetBasicStealthBonus( OBJECTTYPE * pObj ) bonus = Item[pObj->usItem].stealthbonus; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - bonus += (INT16) Item[iter->usItem].stealthbonus; + if(iter->exists()) + bonus += (INT16) Item[iter->usItem].stealthbonus; } } return( bonus ); } +// HEADROCK HAM 4: Calculate a gun's accuracy, including bonuses from ammo and attachments. +INT32 GetGunAccuracy( OBJECTTYPE *pObj ) +{ + if(UsingNewCTHSystem() == false) + return(Weapon[pObj->usItem].bAccuracy); + + INT32 bonus = 0; + if ( pObj->exists() == true ) + { + bonus = Weapon[Item[pObj->usItem].uiIndex].nAccuracy; + bonus = (bonus * (*pObj)[0]->data.gun.bGunStatus) / 100; + + INT32 iModifier = GetAccuracyModifier( pObj ); + // Accuracy works in a very different way from most modifiers. At low levels, a small change is almost completely + // irrelevant. At high levels, every point of accuracy can potentially increase the gun's effective range by + // a large amount. Therefore, we apply this percentage in REVERSE - the higher our accuracy, the less change + // we receive. + // You can look at it a different way: We're actually adding/subtracting a percentage of the distance between + // the gun's accuracy and Max Accuracy (100). + // Examples: + // Modifier = +20% + // Initial Gun Accuracy = 90, Final Gun Accuracy = 90 + (20% of the gap = 20% of 100-90 = 20% of 10 = 2) = 92. + // Initial Gun Accuracy = 10, Final Gun Accuracy = 10 + (20% of the gap = 20% of 100-10 = 20% of 90 = 18) = 28. + bonus += ((100-bonus) * iModifier) / 100; + } + + bonus = __max(0,bonus); + bonus = __min(100,bonus); + + return( bonus ); +} + +// Get Accuracy Modifier from an item and its attachments +INT32 GetAccuracyModifier( OBJECTTYPE *pObj ) +{ + INT32 bonus = 0; + if ( pObj->exists() == true ) + { + bonus += Item[ pObj->usItem ].percentaccuracymodifier; + + if ( (*pObj)[0]->data.gun.ubGunShotsLeft > 0 ) + bonus += Item[(*pObj)[0]->data.gun.usGunAmmoItem].percentaccuracymodifier; + + for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) + { + if (iter->exists()) + { + bonus += BonusReduceMore( (INT32) Item[iter->usItem].percentaccuracymodifier, (*iter)[0]->data.objectStatus ); + } + } + } + + return bonus; +} + // HEADROCK HAM 3.6: This is meant to squash an exploit where a backpack can be moved to your hand to avoid AP penalties. INT8 FindBackpackOnSoldier( SOLDIERTYPE * pSoldier ) { @@ -8971,6 +11914,11 @@ INT8 FindBackpackOnSoldier( SOLDIERTYPE * pSoldier ) // HEADROCK HAM 3.6: This applies the INI modifier to explosives UINT8 GetModifiedExplosiveDamage( UINT16 sDamage ) { + if (sDamage == 0) + { + return(0); + } + sDamage = (INT16)(( sDamage * gGameExternalOptions.iExplosivesDamageModifier ) / 100); sDamage = __max(1, sDamage); sDamage = __min(255, sDamage); @@ -8980,6 +11928,11 @@ UINT8 GetModifiedExplosiveDamage( UINT16 sDamage ) UINT8 GetModifiedMeleeDamage( UINT16 sDamage ) { + if (sDamage == 0) + { + return(0); + } + sDamage = (INT16)(( sDamage * gGameExternalOptions.iMeleeDamageModifier ) / 100); sDamage = __max(1, sDamage); sDamage = __min(255, sDamage); @@ -8989,6 +11942,11 @@ UINT8 GetModifiedMeleeDamage( UINT16 sDamage ) UINT8 GetModifiedGunDamage( UINT16 sDamage ) { + if (sDamage == 0) + { + return(0); + } + sDamage = (INT16)(( sDamage * gGameExternalOptions.iGunDamageModifier ) / 100); sDamage = __max(1, sDamage); sDamage = __min(255, sDamage); @@ -8996,4 +11954,202 @@ UINT8 GetModifiedGunDamage( UINT16 sDamage ) return (UINT8)sDamage; } +UINT16 GetModifiedGunRange(UINT16 usWeaponIndex) +{ + UINT16 ubRange = Weapon[usWeaponIndex].usRange; + + if (ubRange == 0) + { + return(0); + } + + // Only apply range modifier on "real" guns! + if (Item[Weapon[usWeaponIndex].uiIndex].usItemClass == IC_GUN || + Item[Weapon[usWeaponIndex].uiIndex].usItemClass == IC_LAUNCHER) + { + ubRange = (INT16)(( ubRange * gGameExternalOptions.iGunRangeModifier ) / 100); + } + + return (UINT16)ubRange; +} + + + +///////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - Added a procedure to reduce camo on soldier, used when applying camo kit +INT16 ReduceCamoFromSoldier( SOLDIERTYPE * pSoldier, INT16 iCamoToRemove, INT16 iCamoToSkip ) +{ + INT32 i; + UINT16 iCamoToRemovePart = 3; + + if( iCamoToSkip > 0 ) // iCamoToSkip determines what camo type should not be reduced + iCamoToRemovePart = 2; + + if ( (pSoldier->bCamo == 0) && (iCamoToSkip != 1) ) + iCamoToRemovePart -= 1; + if ( (pSoldier->urbanCamo == 0) && (iCamoToSkip != 2) ) + iCamoToRemovePart -= 1; + if ( (pSoldier->desertCamo == 0) && (iCamoToSkip != 3) ) + iCamoToRemovePart -= 1; + if ( (pSoldier->snowCamo == 0) && (iCamoToSkip != 4) ) + iCamoToRemovePart -= 1; + + // this should never happen, but if, we still might try to go through the procedure below + if ( iCamoToRemovePart < 0 ) + iCamoToRemovePart = 0; + + for (i = 0; i < 4; i++ ) // 4 times should be enough, a little paranoya here + { + // first, try to reduce jungle camo + if ( ((iCamoToRemove / (1 + iCamoToRemovePart)) <= pSoldier->bCamo) && (pSoldier->bCamo > 0) && (iCamoToSkip != 1) ) + { + // jungle camo enough to reduce + pSoldier->bCamo -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemove -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + else if ((pSoldier->bCamo > 0) && (iCamoToSkip != 1)) + { + // jungle camo not enough to reduce by intended value, reduce only by what we have + iCamoToRemove -= pSoldier->bCamo; + pSoldier->bCamo = 0; + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + // second, try to reduce urban camo + if ( ((iCamoToRemove / (1 + iCamoToRemovePart)) <= pSoldier->urbanCamo) && (pSoldier->urbanCamo > 0) && (iCamoToSkip != 2) ) + { + // urban camo enough to reduce + pSoldier->urbanCamo -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemove -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + else if ((pSoldier->urbanCamo > 0) && (iCamoToSkip != 2)) + { + // urban camo not enough to reduce by intended value, reduce only by what we have + iCamoToRemove -= pSoldier->urbanCamo; + pSoldier->urbanCamo = 0; + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + // third, try to reduce desert camo + if ( ((iCamoToRemove / (1 + iCamoToRemovePart)) <= pSoldier->desertCamo) && (pSoldier->desertCamo > 0) && (iCamoToSkip != 3) ) + { + // desert camo enough to reduce + pSoldier->desertCamo -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemove -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + else if ((pSoldier->desertCamo > 0) && (iCamoToSkip != 3)) + { + // desert camo not enough to reduce by intended value, reduce only by what we have + iCamoToRemove -= pSoldier->desertCamo; + pSoldier->desertCamo = 0; + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + // fourth, try to reduce snow camo + if ( ((iCamoToRemove / (1 + iCamoToRemovePart)) <= pSoldier->snowCamo) && (pSoldier->snowCamo > 0) && (iCamoToSkip != 4) ) + { + // snow camo enough to reduce + pSoldier->snowCamo -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemove -= max(1,(iCamoToRemove / (1 + iCamoToRemovePart))); + iCamoToRemovePart = max( 0,(iCamoToRemovePart - 1)); + if( iCamoToRemove <= 0 ) + break; + } + else if ((pSoldier->snowCamo > 0) && (iCamoToSkip != 4)) + { + // snow camo not enough to reduce by intended value, reduce only by what we have + iCamoToRemove -= pSoldier->snowCamo; + pSoldier->snowCamo = 0; + if( iCamoToRemove <= 0 ) + break; + } + } + + // return remaining value or zero + return( max( 0, iCamoToRemove)); +} + +// SANDRO - added function to determine if we have Extended Ear on +BOOLEAN HasExtendedEarOn( SOLDIERTYPE * pSoldier ) +{ + // optimistically assume, that anything electronic with hearing range bonus serves as extended ear as well + if ( pSoldier->inv[HEAD1POS].exists() && (pSoldier->inv[HEAD1POS].usItem == EXTENDEDEAR || + (Item[pSoldier->inv[HEAD1POS].usItem].hearingrangebonus > 0 && Item[pSoldier->inv[HEAD1POS].usItem].electronic)) ) + { + return( TRUE ); + } + else if ( pSoldier->inv[HEAD2POS].exists() && (pSoldier->inv[HEAD2POS].usItem == EXTENDEDEAR || + (Item[pSoldier->inv[HEAD2POS].usItem].hearingrangebonus > 0 && Item[pSoldier->inv[HEAD2POS].usItem].electronic)) ) + { + return( TRUE ); + } + return( FALSE ); +} + + +BOOLEAN UseTotalMedicalKitPoints( SOLDIERTYPE * pSoldier, UINT16 usPointsToConsume ) +{ + OBJECTTYPE * pObj; + UINT8 ubPocket; + INT8 bLoop; + + // add up kit points of all medkits + // CHRISL: Changed to dynamically determine max inventory locations. + for (ubPocket = HANDPOS; ubPocket < NUM_INV_SLOTS; ubPocket++) + { + if ( IsMedicalKitItem( &( pSoldier->inv[ ubPocket ] ) ) ) + { + pObj = &(pSoldier->inv[ ubPocket ]); + // start consuming from the last kit in, so we end up with fewer fuller kits rather than + // lots of half-empty ones. + for (bLoop = pObj->ubNumberOfObjects - 1; bLoop >= 0; bLoop--) + { + if( (usPointsToConsume * (max( 0, (100 - Item[pObj->usItem].percentstatusdrainreduction)))/100) < (*pObj)[bLoop]->data.objectStatus ) + { + (*pObj)[bLoop]->data.objectStatus -= (INT8)(usPointsToConsume * (max( 0, (100 - Item[pObj->usItem].percentstatusdrainreduction) ) )/100); + usPointsToConsume = 0; + break; + } + else + { + // consume this kit totally + usPointsToConsume -= (((*pObj)[bLoop]->data.objectStatus) / (max( 0, (100 - Item[pObj->usItem].percentstatusdrainreduction))) /100); + (*pObj)[bLoop]->data.objectStatus = 0; + + pObj->ubNumberOfObjects--; + } + } + // check if pocket/hand emptied..update inventory, then update panel + if( pObj->exists() == false ) + { + // Delete object + DeleteObj( pObj ); + + // dirty interface panel + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); + } + + if( usPointsToConsume <= 0 ) + break; + } + } + + if (usPointsToConsume > 0) + return( FALSE ); + else + return( TRUE ); +} + diff --git a/Tactical/Items.h b/Tactical/Items.h index 1e8aa699..cdc8f304 100644 --- a/Tactical/Items.h +++ b/Tactical/Items.h @@ -2,6 +2,7 @@ #define ITEMS_H #include "Soldier Control.h" #include "Overhead Types.h" +#include "Weapons.h" //forward declarations of common classes to eliminate includes @@ -22,6 +23,7 @@ INT8 FindAmmo( SOLDIERTYPE * pSoldier, UINT8 ubCalibre, UINT16 ubMagSize, UINT8 INT8 FindBestWeaponIfCurrentIsOutOfRange(SOLDIERTYPE * pSoldier, INT8 bCurrentWeaponIndex, UINT16 bWantedRange); +INT16 FindAttachmentSlot( OBJECTTYPE* pObj, UINT16 usItem, UINT8 subObject = 0); OBJECTTYPE* FindAttachment( OBJECTTYPE * pObj, UINT16 usItem, UINT8 subObject = 0 ); extern INT8 FindObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass ); extern INT8 FindAIUsableObjClass( SOLDIERTYPE * pSoldier, UINT32 usItemClass ); @@ -98,8 +100,11 @@ bool TryToPlaceInSlot(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, bool fNewItem, in void RemoveInvObject( SOLDIERTYPE *pSoldier, UINT16 usItem ); -void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usItem); -void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj); +void InitItemAttachments(OBJECTTYPE* pObj); +std::vector GetItemSlots(OBJECTTYPE* pObj, UINT8 subObject = 0, BOOLEAN fAttachment = FALSE); +void RemoveProhibitedAttachments(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usItem, BOOLEAN fOnlyRemoveWhenSlotsChange = 1); +void ReInitMergedItem(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT16 usOldItem); +void EjectAmmoAndPlace(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj, UINT8 subObject = 0); BOOLEAN CanItemFitInVehicle( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos, BOOLEAN fDoingPlacement ); BOOLEAN CanItemFitInPosition( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 bPos, BOOLEAN fDoingPlacement ); @@ -135,7 +140,12 @@ BOOLEAN ItemHasAttachments( OBJECTTYPE *pItem, SOLDIERTYPE * pSoldier = NULL, UI //Determine if this item can receive this attachment. This is different, in that it may //be possible to have this attachment on this item, but may already have an attachment on //it which doesn't work simultaneously with the new attachment (like a silencer and duckbill). -BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage = TRUE, UINT8 subObject = 0); +BOOLEAN ValidItemAttachment( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage = TRUE, UINT8 subObject = NULL, std::vector usAttachmentSlotIndexVector = std::vector()); +//Return true if usAttachment would fit on an item with usItem, without considering possible other attachments on this gun. This may be inaccurate for NAS, because slots can change. +BOOLEAN ValidAttachment( UINT16 usAttachment, UINT16 usItem, UINT8* ubAPCost = NULL ); +//This function does the same as the above, but is more accurate. +BOOLEAN ValidAttachment( UINT16 usAttachment, OBJECTTYPE * pObj, UINT8* ubAPCost = NULL, UINT8 subObject = 0, std::vector usAttachmentSlotIndexVector = std::vector() ); +BOOLEAN ValidItemAttachmentSlot( OBJECTTYPE * pObj, UINT16 usAttachment, BOOLEAN fAttemptingAttachment, BOOLEAN fDisplayMessage = TRUE, UINT8 subObject = 0, INT16 slotCount = -1, BOOLEAN fIgnoreAttachmentInSlot = FALSE, OBJECTTYPE ** ppAttachInSlot = NULL, std::vector usAttachmentSlotIndexVector = std::vector()); // Determines if it is possible to merge an item with any item whose class // is the same as the indicated item @@ -149,8 +159,10 @@ BOOLEAN TwoHandedItem( UINT16 usItem ); //Existing functions without header def's, added them here, just incase I'll need to call //them from the editor. -BOOLEAN ValidAttachment( UINT16 usAttachment, UINT16 usItem, UINT8* ubAPCost = NULL); -UINT8 AttachmentAPCost( UINT16 usAttachment, UINT16 usItem ); + +UINT8 AttachmentAPCost( UINT16 usAttachment, UINT16 usItem, SOLDIERTYPE * pSoldier ); // SANDRO - added argument +UINT8 AttachmentAPCost( UINT16 usAttachment, OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier, UINT8 subObject = 0, std::vector usAttachmentSlotIndexVector = std::vector() ); + BOOLEAN ValidLaunchable( UINT16 usLaunchable, UINT16 usItem ); UINT16 GetLauncherFromLaunchable( UINT16 usLaunchable ); @@ -180,7 +192,7 @@ UINT8 ConvertObjectTypeMoneyValueToProfileMoneyValue( UINT32 uiMoneyAmount ); BOOLEAN CheckForChainReaction( UINT16 usItem, INT16 bStatus, INT16 bDamage, BOOLEAN fOnGround ); -BOOLEAN ItemIsLegal( UINT16 usItemIndex ); +BOOLEAN ItemIsLegal( UINT16 usItemIndex, BOOLEAN fIgnoreCoolness = FALSE ); BOOLEAN ExtendedGunListGun( UINT16 usGun ); UINT16 StandardGunListReplacement( UINT16 usGun ); UINT16 FindReplacementMagazine( UINT8 ubCalibre, UINT16 ubMagSize, UINT8 ubAmmoType); @@ -205,6 +217,7 @@ void CheckEquipmentForFragileItemDamage( SOLDIERTYPE *pSoldier, INT32 iDamage ); extern void ActivateXRayDevice( SOLDIERTYPE * pSoldier ); extern void TurnOffXRayEffects( SOLDIERTYPE * pSoldier ); OBJECTTYPE* FindLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon ); +UINT16 FindLegalGrenade(UINT16 usItem); void DamageObj( OBJECTTYPE * pObj, INT8 bAmount, UINT8 subObject = 0 ); @@ -213,12 +226,16 @@ UINT16 MagazineClassIndexToItemType(UINT16 usMagIndex); // Item property-related stuff added by Madd Mugsy BOOLEAN IsScoped( OBJECTTYPE * pObj ); +BOOLEAN NCTHIsScoped( OBJECTTYPE * pObj ); +INT16 GetReliability( OBJECTTYPE * pObj ); INT16 GetAimBonus( OBJECTTYPE * pObj, INT32 iRange, INT16 ubAimTime ); +//WarmSteel - Used to determine the base aim bonus of the most powerful scope. +INT16 GetBaseScopeAimBonus( OBJECTTYPE * pObj, INT32 iRange ); // HEADROCK: Function to get the natural aimbonus of the weapon and its attachments INT16 GetFlatAimBonus( OBJECTTYPE * pObj ); // HEADROCK: Function to get the final loudness value of a weapon, after reduction from its own characteristics, ammo and attachments INT16 GetFinalLoudness( OBJECTTYPE * pObj ); -INT16 GetMinAimBonusRange( OBJECTTYPE * pObj ); +//INT16 GetMinAimBonusRange( OBJECTTYPE * pObj ); INT16 GetToHitBonus( OBJECTTYPE * pObj, INT32 iRange, UINT8 bLightLevel, BOOLEAN fProneStance = FALSE ); // HEADROCK: Added alternate function that only returns the natural to-hit-bonii of a weapon, ammo and attachments INT16 GetFlatToHitBonus( OBJECTTYPE * pObj ); @@ -226,9 +243,38 @@ INT16 GetFlatToHitBonus( OBJECTTYPE * pObj ); INT16 GetAverageBestLaserRange( OBJECTTYPE * pObj ); // HEADROCK: Function to get bipod bonus from weapon and its attachments INT16 GetBipodBonus( OBJECTTYPE * pObj ); +INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance = FALSE ); +INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance = FALSE ); +INT16 GetGearAimBonus( SOLDIERTYPE * pSoldier, INT32 iRange, INT16 ubAimTime); +INT16 GetGearToHitBonus( SOLDIERTYPE * pSoldier ); +INT16 GetMinRangeForAimBonus( OBJECTTYPE * pObj ); + +// HEADROCK: Function to get the final loudness value of a weapon, after reduction from its own characteristics, ammo and attachments +INT16 GetFinalLoudness( OBJECTTYPE * pObj ); UINT32 FindRangeBonusAttachment( OBJECTTYPE * pObj ); INT16 GetRangeBonus( OBJECTTYPE * pObj ); -INT16 GetBurstToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance = FALSE ); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HEADROCK HAM 4: The following functions return the value of new NCTH-related modifiers from an item and all its +// attachments. They are stance-based, meaning that the soldier's stance determines which modifier is referenced. +// For a "default" value, feed the function a value of ubStance=ANIM_STAND. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +INT32 GetFlatBaseModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetPercentBaseModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetFlatAimModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetPercentAimModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetPercentCapModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetPercentHandlingModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetDropCompensationModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetCounterForceMaxModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetCounterForceAccuracyModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetCounterForceFrequencyModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetTargetTrackingModifier( OBJECTTYPE *pObj, UINT8 ubStance ); +INT32 GetAimLevelsModifier( OBJECTTYPE *pObj, UINT8 ubStance ); + +// Returns the character's stance as 0/1/2. +INT8 GetStanceModifierRef( INT8 ubStance ); INT16 GetDamageBonus( OBJECTTYPE * pObj ); INT16 GetMeleeDamageBonus( OBJECTTYPE * pObj ); @@ -238,11 +284,17 @@ INT16 GetPercentAutofireAPReduction( OBJECTTYPE * pObj ); INT16 GetPercentBurstFireAPReduction( OBJECTTYPE * pObj ); INT16 GetPercentReadyTimeAPReduction( OBJECTTYPE * pObj ); INT16 GetPercentReloadTimeAPReduction( OBJECTTYPE * pObj ); -INT16 GetAutoToHitBonus( OBJECTTYPE * pObj, BOOLEAN fProneStance = FALSE ); INT16 GetRateOfFireBonus( OBJECTTYPE * pObj ); INT16 GetBurstSizeBonus( OBJECTTYPE * pObj ); BOOLEAN HasFastBurst( OBJECTTYPE * pObj ); -INT16 GetMagSizeBonus( OBJECTTYPE * pObj ); +INT16 GetMagSizeBonus( OBJECTTYPE * pObj, UINT8 subObject = 0 ); + +// HEADROCK HAM 4: This function now calculates and returns the weapon's recoil as X/Y offsets. +void GetRecoil( OBJECTTYPE *pObj, INT8 *bRecoilX, INT8 *bRecoilY, UINT8 ubNumBullet ); +void GetFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY ); +INT16 GetPercentRecoilModifier( OBJECTTYPE *pObj ); +// HEADROCK HAM 4: This function returns whether the last bullet in a burst/autofire volley was a tracer. +BOOLEAN WasPrevBulletATracer( SOLDIERTYPE *pSoldier, OBJECTTYPE *pWeapon ); // Snap: GetTotalVisionRangeBonus checks for light levels // and returns cumulative bonus from the following functions: @@ -273,7 +325,7 @@ INT16 GetItemHearingRangeBonus( OBJECTTYPE * pObj ); INT8 IsGrenadeLauncher( OBJECTTYPE * pObj ); INT16 GetGrenadeLauncherStatus( OBJECTTYPE * pObj ); -BOOLEAN IsGrenadeLauncherAttached( OBJECTTYPE * pObj ); +BOOLEAN IsGrenadeLauncherAttached( OBJECTTYPE * pObj, UINT8 subObject = 0 ); OBJECTTYPE* FindAttachment_GrenadeLauncher( OBJECTTYPE * pObj ); UINT16 GetAttachedGrenadeLauncher( OBJECTTYPE * pObj ); INT8 FindRocketLauncher( SOLDIERTYPE * pSoldier ); @@ -333,8 +385,16 @@ UINT16 GetFirstExplosiveOfType(UINT16 expType); OBJECTTYPE* FindSunGogglesInInv( SOLDIERTYPE * pSoldier, BOOLEAN searchAllInventory = FALSE ); OBJECTTYPE* FindNightGogglesInInv( SOLDIERTYPE * pSoldier, BOOLEAN searchAllInventory = FALSE ); -INT16 GetMinRangeForAimBonus( OBJECTTYPE * pObj ); -UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier); +UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier, INT32 sGridNo); +// HEADROCK HAM 4: New functions to determine Scope and Laser factors on a weapon. +FLOAT GetHighestScopeMagnificationFactor( OBJECTTYPE *pObj ); +FLOAT GetBestScopeMagnificationFactor( OBJECTTYPE *pObj, UINT32 uiRange ); +FLOAT GetProjectionFactor( OBJECTTYPE *pObj ); +INT32 GetGunAccuracy( OBJECTTYPE *pObj ); +INT32 GetAccuracyModifier( OBJECTTYPE *pObj ); +// HEADROCK HAM 4: Added range factor +UINT8 AllowedAimingLevelsNCTH( SOLDIERTYPE *pSoldier, INT32 sGridNo); +UINT8 GetAllowedAimingLevelsForItem( OBJECTTYPE *pObj, UINT8 ubStance ); INT16 GetWornUrbanCamo( SOLDIERTYPE * pSoldier ); INT16 GetUrbanCamoBonus( OBJECTTYPE * pObj ); @@ -351,6 +411,14 @@ UINT8 GetModifiedExplosiveDamage( UINT16 ubDamage ); UINT8 GetModifiedMeleeDamage( UINT16 ubDamage ); UINT8 GetModifiedGunDamage( UINT16 ubDamage ); +UINT16 GetModifiedGunRange( UINT16 usWeaponIndex ); + + +// SANDRO - added some procedures +INT16 ReduceCamoFromSoldier( SOLDIERTYPE * pSoldier, INT16 iCamoToRemove, INT16 iCamoToSkip ); +BOOLEAN HasExtendedEarOn( SOLDIERTYPE * pSoldier ); +BOOLEAN UseTotalMedicalKitPoints( SOLDIERTYPE * pSoldier, UINT16 usPointsToConsume ); + #endif diff --git a/Tactical/Keys.cpp b/Tactical/Keys.cpp index 04928267..5c83116d 100644 --- a/Tactical/Keys.cpp +++ b/Tactical/Keys.cpp @@ -38,6 +38,7 @@ #include "Game Clock.h" #include "handle doors.h" #include "Map Screen Interface.h" + #include "GameSettings.h" // added by SANDRO #endif @@ -357,8 +358,12 @@ BOOLEAN AttemptToCrowbarLock( SOLDIERTYPE * pSoldier, DOOR * pDoor ) if (iResult > 0) { - // STR GAIN (20) - Pried open a lock - StatChange( pSoldier, STRAMT, 20, FALSE ); + // STR GAIN (20) - Pried open a lock + StatChange( pSoldier, STRAMT, 20, FALSE ); + + // SANDRO - merc records - locks breached + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usLocksBreached++; // succeeded! door can never be locked again, so remove from door list... RemoveDoorInfoFromTable( pDoor->sGridNo ); @@ -436,8 +441,12 @@ BOOLEAN AttemptToSmashDoor( SOLDIERTYPE * pSoldier, DOOR * pDoor ) } if (iResult > 0) { - // STR GAIN (20) - Pried open a lock - StatChange( pSoldier, STRAMT, 20, FALSE ); + // STR GAIN (20) - Pried open a lock + StatChange( pSoldier, STRAMT, 20, FALSE ); + + // SANDRO - merc records - locks breached + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usLocksBreached++; // succeeded! door can never be locked again, so remove from door list... RemoveDoorInfoFromTable( pDoor->sGridNo ); @@ -523,7 +532,9 @@ BOOLEAN AttemptToPickLock( SOLDIERTYPE * pSoldier, DOOR * pDoor ) else StatChange( pSoldier, WISDOMAMT, ( UINT16 ) ( pLock->ubPickDifficulty / 15 ), FALSE ); - + // SANDRO - merc records - another lock picked + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usLocksPicked++; // succeeded! pDoor->fLocked = FALSE; @@ -554,6 +565,23 @@ BOOLEAN AttemptToUntrapDoor( SOLDIERTYPE * pSoldier, DOOR * pDoor ) if (iResult > 0) { + // SANDRO - added some exp for removing traps (why was it not here anyway?) + // MECHANICAL/EXPLOSIVES GAIN + if ( pDoor->ubTrapID == EXPLOSION ) + StatChange( pSoldier, EXPLODEAMT, ( UINT16 ) ( pDoor->ubTrapLevel * 5 ), FALSE ); + else + StatChange( pSoldier, MECHANAMT, ( UINT16 ) ( pDoor->ubTrapLevel * 5 ), FALSE ); + + // DEXTERITY GAIN + StatChange( pSoldier, DEXTAMT, ( UINT16 ) ( pDoor->ubTrapLevel * 5 ), FALSE ); + + // WISDOM GAIN + StatChange( pSoldier, WISDOMAMT, ( UINT16 ) ( pDoor->ubTrapLevel * 2 ), FALSE ); + + // SANDRO - merc records - another lock picked + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usTrapsRemoved++; + // succeeded! pDoor->ubTrapLevel = 0; pDoor->ubTrapID = NO_TRAP; @@ -592,6 +620,8 @@ BOOLEAN ExamineDoorForTraps( SOLDIERTYPE * pSoldier, DOOR * pDoor ) else { pDoor->bPerceivedTrapped = DOOR_PERCEIVED_TRAPPED; + // SANDRO - add some exp for trap exposion + StatChange( pSoldier, WISDOMAMT, ( UINT16 ) ( max(1,(pDoor->ubTrapLevel - 1)) ), FALSE ); return( TRUE ); } } @@ -755,12 +785,25 @@ BOOLEAN AttemptToBlowUpLock( SOLDIERTYPE * pSoldier, DOOR * pDoor ) // Not sure if this makes sense, but the explosive is small. // Double the damage here as we are damaging a lock rather than a person - pDoor->bLockDamage += Explosive[Item[pSoldier->inv[bSlot].usItem].ubClassIndex].ubDamage * 2; + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT )) + { + // greatly increase the effectiveness of shaped charge + pDoor->bLockDamage += (Explosive[Item[pSoldier->inv[bSlot].usItem].ubClassIndex].ubDamage * 2 * gSkillTraitValues.ubDEShapedChargeDamageMultiplier); + } + else + { + pDoor->bLockDamage += Explosive[Item[pSoldier->inv[bSlot].usItem].ubClassIndex].ubDamage * 2; + } + if (pDoor->bLockDamage > LockTable[ pDoor->ubLockID ].ubSmashDifficulty ) { // succeeded! door can never be locked again, so remove from door list... RemoveDoorInfoFromTable( pDoor->sGridNo ); - // award experience points? + // award experience points? ... SANDRO - sure! + StatChange( pSoldier, EXPLODEAMT, ( 10 ), FALSE ); + // also add to records - door successfuly breached + gMercProfiles[ pSoldier->ubProfile ].records.usLocksBreached++; + return( TRUE ); } } diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index de01a0db..21438b1f 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -45,7 +45,6 @@ #include "Item Types.h" #endif #include "fresh_header.h" -#include "test_space.h" #include "WorldDat.h" // HEADROCK HAM 3.6: This must be included, for testing whether Bloodcats and Enemies can see one another. #include "Campaign Types.h" @@ -67,6 +66,7 @@ extern INT16 DirIncrementer[8]; extern BOOLEAN fTracer; + static FIXEDPT gqStandardWallHeight = INT32_TO_FIXEDPT( WALL_HEIGHT_UNITS ); static FIXEDPT gqStandardWindowBottomHeight = INT32_TO_FIXEDPT( WINDOW_BOTTOM_HEIGHT_UNITS ); static FIXEDPT gqStandardWindowTopHeight = INT32_TO_FIXEDPT( WINDOW_TOP_HEIGHT_UNITS ); @@ -172,11 +172,11 @@ INT32 GetSpreadPattern( OBJECTTYPE * pObj ) if( !pObj || !pObj->usItem || !pObj->exists() ) return 0; //If there are attachments, check them. Stop on the first one with something defined. - //Dear God, I hate C++ iterators. What a fugly mess. + //Dear God, I hate C++ iterators. What a fugly mess. //WarmSteel - I made it even messier ;3 for (attachmentList::iterator iter = pObj[0][0]->attachments.begin(); iter != pObj[0][0]->attachments.end(); ++iter){ - if( n=Item[ iter->usItem ].spreadPattern ) + if( n=Item[ iter->usItem ].spreadPattern && iter->exists()){ //An attachment has it, and it trumps everything, so return it's value. - return n; + return n;} } //The object's own spread pattern, if it has one. @@ -378,12 +378,9 @@ enum } LocationCode; -// TODO: Relocate functions in appropriate class (soldiertype obviously) /** * Calculates the height and gives it back as one of the ANIM_* defines * -* @comment I don't want to repetitivly use code that should be part of the pSoldier class, so I made a oo-c-based-method -* * @param pSoldier * @return ANIM_STAND or ANIM_CROUCH or ANIM_PRONE */ @@ -400,7 +397,6 @@ inline UINT8 GetCurrentHeightOfSoldier( SOLDIERTYPE* pSoldier ) /* * Calculates the total camouflage for the corresponding type. * -* @comment I don't want to repetitivly use code that should be part of the pSoldier class, so I made a oo-c-based-method * @comment we don't need the snow camo as we don't have a terrain type -> camouflage association for snow * (meaning we would need externalisation for specifing camo effectivness based on terrain textures and not terrain types) * (unfortunatly that's not only programming but alot of content-heavy work, which doesn't seem probable to happen) @@ -411,66 +407,74 @@ inline UINT8 GetCurrentHeightOfSoldier( SOLDIERTYPE* pSoldier ) */ inline INT8 GetJungleCamouflage( SOLDIERTYPE* pSoldier ) { - if (HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED )) { - return 100; - } + // SANDRO - the Camouflage trait has been solved differently + //if (HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED )) { + // return 100; + //} return MINMAX100N(pSoldier->bCamo + pSoldier->wornCamo); } inline INT8 GetDesertCamouflage( SOLDIERTYPE* pSoldier ) { - if (HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT )) { - return 100; - } + // SANDRO - the Camouflage trait has been solved differently + //if (HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT )) { + // return 100; + //} return MINMAX100N(pSoldier->desertCamo + pSoldier->wornDesertCamo); } inline INT8 GetUrbanCamouflage( SOLDIERTYPE* pSoldier ) { - if (HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN )) { - return 100; - } + // SANDRO - the Camouflage trait has been solved differently + //if (HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN )) { + // return 100; + //} return MINMAX100N(pSoldier->urbanCamo + pSoldier->wornUrbanCamo); } +// should be in lightning, 0-100 definition of brightness +inline UINT8 GetBrightness(const UINT8& ubLightLevel) +{ + return 100 * (ubLightLevel-SHADE_MAX)/(SHADE_MIN-SHADE_MAX); +} + /** * Calculates the total stealth value of a player. * -* @comment I don't want to repetitivly use code that should be part of the pSoldier class, so I made a oo-c-based-method -* * @param pSoldier * @return ANIM_STAND or ANIM_CROUCH or ANIM_PRONE */ inline INT8 GetStealth( SOLDIERTYPE* pSoldier ) { INT16 stealth = GetWornStealth( pSoldier ); - if (HAS_SKILL_TRAIT( pSoldier, STEALTHY )) + // SANDRO - this only counts with old traits + if (HAS_SKILL_TRAIT( pSoldier, STEALTHY_OT ) && !gGameOptions.fNewTraitSystem) { - stealth += gGameExternalOptions.ubStealthTraitCoverValue * NUM_SKILL_TRAITS( pSoldier, STEALTHY ); + stealth += gGameExternalOptions.ubStealthTraitCoverValue * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT ); } return MINMAX100N(stealth); } /** -* Gives back a valid terrainId for a specified GridNo -* -* @comment I don't want to repetitivly use code that should be part of the pSoldier class, so I made a oo-c-based-method -* @comment the current method GetTerrainType doesn't check for more info, but for camouflage we need that extra info +* Gives back a valid terrainId for a specified GridNo and bLevel * * @param pSoldier -* @return ANIM_STAND or ANIM_CROUCH or ANIM_PRONE */ -INT8 GetTerrainTypeForGrid( const INT32& sGridNo ) +INT8 GetTerrainTypeForGrid( const INT32& sGridNo, const INT16& bLevel ) { - if (gpWorldLevelData[sGridNo].ubTerrainID != NO_TERRAIN) + LEVELNODE* pNode; + if (bLevel == I_ROOF_LEVEL) { - return gpWorldLevelData[sGridNo].ubTerrainID; + pNode = gpWorldLevelData[ sGridNo ].pOnRoofHead; + } + else + { + pNode = gpWorldLevelData[ sGridNo ].pObjectHead; } // Check if we have anything in object layer which has a terrain modifier - LEVELNODE* pNode = gpWorldLevelData[ sGridNo ].pObjectHead; if ( pNode != NULL ) { if ( gTileDatabase[ pNode->usIndex ].ubTerrainID != NO_TERRAIN ) @@ -479,7 +483,13 @@ INT8 GetTerrainTypeForGrid( const INT32& sGridNo ) } } - // Now try terrain! + // map element layer + if (gpWorldLevelData[sGridNo].ubTerrainID != NO_TERRAIN) + { + return gpWorldLevelData[sGridNo].ubTerrainID; + } + + // Now try terrain special pNode = gpWorldLevelData[ sGridNo ].pLandHead; return gTileDatabase[ pNode->usIndex ].ubTerrainID; @@ -536,7 +546,7 @@ INT8 GetSightAdjustmentCamouflageOnTerrain( SOLDIERTYPE* pSoldier, const UINT8& * @param pSoldier the target * @return a negative value will indicate a reduction of sight, a positive one an addition to sight */ -INT8 GetSightAdjustmentThroughMovement( SOLDIERTYPE* pSoldier, const INT8& bTilesMoved, const UINT8& ubLightlevel ) +INT8 GetSightAdjustmentThroughMovement( SOLDIERTYPE* pSoldier, const INT8& bTilesMoved, const UINT8& ubLightLevel ) { if (gGameExternalOptions.ubMovementEffectiveness == 0) { return 0; @@ -546,10 +556,13 @@ INT8 GetSightAdjustmentThroughMovement( SOLDIERTYPE* pSoldier, const INT8& bTile INT8 bMovementAdjustment = bTilesMoved * ( 100 - stealth ) / 100; - UINT8 ubBrightness = SHADE_MIN - ubLightlevel; // 3: starlight, 5: evening dark, 15: day - UINT8 ubScalerInPercent = 6 * ubBrightness; //0:0, 15:90 + // SANDRO - added reduction of penalty for moving for Stealthy trait with new traits + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) + bMovementAdjustment = max(0, (bMovementAdjustment * (100 - gSkillTraitValues.ubSTStealthPenaltyForMovingReduction) / 100) ); - return bMovementAdjustment * ubScalerInPercent / 100 * gGameExternalOptions.ubMovementEffectiveness / 100; + UINT8 ubBrightness = GetBrightness( ubLightLevel ); + + return MINMAX100N( bMovementAdjustment * ubBrightness / 100 * gGameExternalOptions.ubMovementEffectiveness / 100 ); } INT8 GetSightAdjustmentThroughStance( const UINT8& ubStance ) @@ -560,7 +573,7 @@ INT8 GetSightAdjustmentThroughStance( const UINT8& ubStance ) INT8 bStanceAdjustment = -(ANIM_STAND - ubStance) * 20; // stand = 6-6 => 0%, crouch = 6-3 => 60%, prone = 6-1 => 100%; - return gGameExternalOptions.ubStanceEffectiveness * bStanceAdjustment / 100; + return MINMAX100N( gGameExternalOptions.ubStanceEffectiveness * bStanceAdjustment / 100 ); } /** @@ -619,22 +632,21 @@ INT8 GetSightAdjustmentBasedOnLBE( SOLDIERTYPE* pSoldier ) * @param ubLightLevel light level given back by the LightTrueLevel function * @return a negative value will indicate a reduction of sight, a positive one an addition to sight */ -INT8 GetSightAdjustmentStealthAtLightLevel( SOLDIERTYPE* pSoldier, const UINT8& ubLightlevel ) +INT8 GetSightAdjustmentStealthAtLightLevel( SOLDIERTYPE* pSoldier, const UINT8& ubLightLevel ) { if (gGameExternalOptions.ubStealthEffectiveness == 0) { return 0; } - INT8 ibStealthInPercent = GetStealth( pSoldier ); - - // set scaler to scale with light level - UINT8 ubBrightness = SHADE_MIN - ubLightlevel; // 3: starlight, 5: evening dark, 15: day - UINT8 ubScaler = -4 * ubBrightness + 60; //0:60, 15:0 + // set scaler to scale with light level (dark = 100%) + UINT8 ubScaler = GetBrightness( ubLightLevel ); // last term corresponds to the maximum of ubScaler before - ubScaler *= gGameExternalOptions.ubStealthEffectiveness / 60; + ubScaler *= gGameExternalOptions.ubStealthEffectiveness / 100; - return (INT8) MINMAX100N( - ibStealthInPercent * ubScaler / 100); + INT8 ibStealthInPercent = GetStealth( pSoldier ); + + return MINMAX100N( - ibStealthInPercent * ubScaler / 100); } /** @@ -681,26 +693,28 @@ INT8 GetSightAdjustmentBehindStructure( const INT16& iRange, STRUCTURE* pStructu // we make the fill less effective INT8 ubSolidityInPercent = ubFillInPercent * gGameExternalOptions.ubTreeCoverEffectiveness / 100; - INT8 ubResult = MINMAX100N(- ubSolidityInPercent * ubCloseRangeScaler * ubLongRangeScaler); - - return ubResult; + return MINMAX100N(- ubSolidityInPercent * ubCloseRangeScaler * ubLongRangeScaler); } /* * Easy way to get all sight adjustments into one that affect a soldier */ -INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT8 bStance ) +INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo, INT16 bLevel, INT8 bStance ) { if (sGridNo == -1) { sGridNo = pSoldier->sGridNo; } + if (bLevel == -1) { + bLevel = gpWorldLevelData[pSoldier->sGridNo].sHeight; + } + if (bStance == -1) { bStance = GetCurrentHeightOfSoldier( pSoldier ); } - UINT8 ubTerrainType = GetTerrainTypeForGrid( sGridNo ); - UINT8 ubLightLevel = LightTrueLevel( sGridNo, gsInterfaceLevel ); + UINT8 ubTerrainType = GetTerrainTypeForGrid( sGridNo, bLevel ); + UINT8 ubLightLevel = LightTrueLevel( sGridNo, bLevel ); INT16 iSightAdjustment = 0; @@ -1069,7 +1083,7 @@ BOOLEAN ResolveHitOnWall( STRUCTURE * pStructure, INT32 iGridNo, INT8 bLOSIndexX * - stops at other obstacles * */ -INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, int iTileSightLimit, INT8 bAware, BOOLEAN fSmell, INT32 * psWindowGridNo, bool adjustForSight = true ) +INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, int iTileSightLimit, INT8 bAware, BOOLEAN fSmell, INT32 * psWindowGridNo, bool adjustForSight = true, bool cthCalc = false ) { // Parameters... // the X,Y,Z triplets should be obvious @@ -1604,7 +1618,7 @@ INT32 LineOfSightTest( FLOAT dStartX, FLOAT dStartY, FLOAT dStartZ, FLOAT dEndX, gLOSTestResults.ubTreeSpotsHit++; gLOSTestResults.iMaxDistance = iSightLimit; #endif - if (iDistance > iAdjSightLimit) + if (iDistance > iAdjSightLimit && !cthCalc) { // out of visual range #ifdef LOS_DEBUG @@ -1998,7 +2012,7 @@ BOOLEAN CalculateSoldierZPos( SOLDIERTYPE * pSoldier, UINT8 ubPosType, FLOAT * p return( TRUE ); } -INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit, UINT8 ubAimLocation, bool adjustForSight ) +INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit, UINT8 ubAimLocation, bool adjustForSight, bool cthCalc ) { FLOAT dStartZPos, dEndZPos; BOOLEAN fOk; @@ -2119,6 +2133,7 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE // needed for gun hit calculation (can you even hit him) else if (iTileSightLimit == NO_DISTANCE_LIMIT) { iTileSightLimit = pStartSoldier->GetMaxDistanceVisible( pEndSoldier->sGridNo, pEndSoldier->pathing.bLevel, CALC_FROM_ALL_DIRS ); + iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier) / 100; iTileSightLimit += 255; // this shifts the limit for something special (we don't know yet) } @@ -2128,7 +2143,7 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE iTileSightLimit += iTileSightLimit * GetSightAdjustment(pEndSoldier) / 100; } - return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, iTileSightLimit, bAware, fSmell, NULL, adjustForSight ) ); + return( LineOfSightTest( (FLOAT) CenterX( pStartSoldier->sGridNo ), (FLOAT) CenterY( pStartSoldier->sGridNo ), dStartZPos, (FLOAT) CenterX( pEndSoldier->sGridNo ), (FLOAT) CenterY( pEndSoldier->sGridNo ), dEndZPos, iTileSightLimit, bAware, fSmell, NULL, adjustForSight, cthCalc ) ); } INT32 SoldierToLocationWindowTest( SOLDIERTYPE * pStartSoldier, INT32 sEndGridNo ) @@ -2530,7 +2545,18 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // handle hit here... if( ( pFirer->bTeam == 0 ) ) { - gMercProfiles[ pFirer->ubProfile ].usShotsHit++; + // SANDRO - new mercs' records + // if we shoot with buckshot or similar, do not count a hit for every pellet + if ( pBullet->usFlags & BULLET_FLAG_BUCKSHOT ) + { + // if just one pellet hits the target, record it as successful hit, ignore the rest + if ( pTarget->bNumPelletsHitBy == 0 ) + gMercProfiles[ pFirer->ubProfile ].records.usShotsHit++; + } + else + { + gMercProfiles[ pFirer->ubProfile ].records.usShotsHit++; + } } // intentionally shot @@ -2540,6 +2566,46 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend { pTarget->bNumPelletsHitBy++; } + + ////////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Experience Gain + // + // The old CTH system gave extra experience points for extra aiming and difficult shots. However, + // it relied upon knowing BEFOREHAND that the target was going to be hit by the bullet (thanks + // to how the OCTH value operated). + // In NCTH, we have no idea how accurate our bullet is until it hits the target. We know how carefully + // we aimed though, so now that the bullet hits the intended target, we can calculate extra experience + // based on the aiming value. + + if (UsingNewCTHSystem() == true && pFirer->bTeam == gbPlayerNum && pBullet->fAimed) // Only for single shot, first bullet in volley, or first bullet in spread. + { + UINT16 usExpGain = 10; + usExpGain = (usExpGain * pBullet->sHitBy) / 100; + + if ( pTarget->ubBodyType == COW || pTarget->ubBodyType == CROW ) + { + usExpGain /= 2; + } + else if ( pTarget->flags.uiStatusFlags & SOLDIER_VEHICLE || AM_A_ROBOT( pTarget ) || TANK( pTarget ) ) + { + // no exp from shooting a vehicle that you can't damage and can't move! + usExpGain = 0; + } + + if (!(pBullet->usFlags & BULLET_FLAG_KNIFE)) + { + // MARKSMANSHIP/DEXTERITY GAIN: gun attack + StatChange( pFirer, MARKAMT, ( UINT16 )( (usExpGain * 2) / 3 ), FROM_SUCCESS ); + StatChange( pFirer, DEXTAMT, ( UINT16 )( usExpGain / 3 ), FROM_SUCCESS ); + } + else + { + // MARKSMANSHIP/DEXTERITY/AGILITY GAIN: throwing knife attack + StatChange( pFirer, MARKAMT, ( UINT16 )( usExpGain / 5 ), FROM_SUCCESS ); + StatChange( pFirer, DEXTAMT, ( UINT16 )( (usExpGain * 2) / 5 ), FROM_SUCCESS ); + StatChange( pFirer, AGILAMT, ( UINT16 )( (usExpGain * 2) / 5 ), FROM_SUCCESS ); + } + } } else { @@ -2593,7 +2659,19 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend // check to see if the guy is a friendly?..if so, up the number of times wounded if( ( pTarget->bTeam == gbPlayerNum ) ) { - gMercProfiles[ pTarget->ubProfile ].usTimesWounded++; + if ( pBullet->usFlags & BULLET_FLAG_BUCKSHOT ) + { + // SANDRO - if just one pellet hits the target, record it as being wounded, ignore the rest + if ( pTarget->bNumPelletsHitBy == 0 ) + gMercProfiles[ pTarget->ubProfile ].records.usTimesWoundedShot++; + } + else if ( iDamage > 1 ) // damage of 1 is just a scratch, not a real wound + { + if ( pBullet->usFlags & BULLET_FLAG_KNIFE ) + gMercProfiles[ pTarget->ubProfile ].records.usTimesWoundedStabbed++; + else + gMercProfiles[ pTarget->ubProfile ].records.usTimesWoundedShot++; + } } // check to see if someone was accidentally hit when no target was specified by the player @@ -2683,7 +2761,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend if(SWeaponHit.ubAttackerID < 20 ||(is_server && SWeaponHit.ubAttackerID < 120)|| !is_client ) // 124 last possible ai { if(is_client) - SWeaponHit.sDamage=(INT16)(SWeaponHit.sDamage * DAMAGE_MULTIPLIER); // adjust damage from external variable //hayden + SWeaponHit.sDamage=(INT16)(SWeaponHit.sDamage * cDamageMultiplier); // adjust damage from external variable //hayden WeaponHit( SWeaponHit.usSoldierID, SWeaponHit.usWeaponIndex, SWeaponHit.sDamage, SWeaponHit.sBreathLoss, SWeaponHit.usDirection, SWeaponHit.sXPos, SWeaponHit.sYPos, SWeaponHit.sZPos, SWeaponHit.sRange, SWeaponHit.ubAttackerID, SWeaponHit.fHit, SWeaponHit.ubSpecial, SWeaponHit.ubLocation ); @@ -2815,7 +2893,11 @@ UINT32 ChanceOfBulletHittingStructure( INT32 iDistance, INT32 iDistanceToTarget, { iCloseToCoverPenalty = 0; } - if (sHitBy < 0) + // HEADROCK HAM 4: HitBy is not longer handled this way, and will never drop below 0 anyway. + // A new method might be devised to handle this, but in practice there's really no reason to. + // I'm commenting this part out for now. If we discover that bullets are far too likely to go + // through objects for any reason, we'll put it back in somehow. + if (UsingNewCTHSystem() == false && sHitBy < 0) { // add 20% to distance so that misses hit nearer obstacles a bit more iDistance += iDistance / 5; @@ -2929,6 +3011,9 @@ INT32 HandleBulletStructureInteraction( BULLET * pBullet, STRUCTURE * pStructure // MARKSMANSHIP GAIN (marksPts): Opened/Damaged a door StatChange( pBullet->pFirer, MARKAMT, 10, FALSE ); + // SANDRO - merc records - locks breached + if ( pBullet->pFirer->ubProfile != NO_PROFILE ) + gMercProfiles[ pBullet->pFirer->ubProfile ].records.usLocksBreached++; } } } @@ -3475,7 +3560,9 @@ UINT8 CalcChanceToGetThrough( BULLET * pBullet ) DebugLOS(String("CalcChanceToGetThrough check for bullet drop")); pBullet->sGridNo = MAPROWCOLTOPOS( pBullet->iCurrTileY , pBullet->iCurrTileX ); - if (pBullet->iLoop > pBullet->iRange * 2) + // HEADROCK HAM 4: Using new gravity constant from INI. See also a second change below. + if ((UsingNewCTHSystem() == false && pBullet->iLoop > pBullet->iRange * 2) || + (UsingNewCTHSystem() == true && pBullet->iLoop > pBullet->iRange * gGameCTHConstants.GRAVITY_COEFFICIENT)) { // beyond max effective range, bullet starts to drop! // since we're doing an increment based on distance, not time, the @@ -3486,7 +3573,7 @@ UINT8 CalcChanceToGetThrough( BULLET * pBullet ) } - pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); + pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * (UsingNewCTHSystem()?gGameCTHConstants.GRAVITY_COEFFICIENT:2)); } // end of the tile... @@ -3756,7 +3843,7 @@ void CalculateFiringIncrements( DOUBLE ddHorizAngle, DOUBLE ddVerticAngle, DOUBL DOUBLE ddMaximumMiss; DOUBLE ddAmountOfMiss; - if (iMissedBy > 0) + if (UsingNewCTHSystem() == false && iMissedBy > 0) { ddVerticPercentOfMiss = PreRandom( 50 ); @@ -3879,11 +3966,21 @@ INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ) //} // increment shots fired if shooter has a merc profile - if( ( pFirer->ubProfile != NO_PROFILE ) && ( pFirer->bTeam == 0 ) ) - { - // another shot fired - gMercProfiles[ pFirer->ubProfile ].usShotsFired++; - } + // SANDRO - this was moved elsewhere + //if( ( pFirer->ubProfile != NO_PROFILE ) && ( pFirer->bTeam == gbPlayerNum ) ) + //{ + // // another shot fired + // ///////////////////////////////////////////////////////////////////////////////////// + // // SANDRO - new mercs' records + // if ( Item[ pFirer->usAttackingWeapon ].usItemClass == IC_LAUNCHER || Item[pFirer->usAttackingWeapon].grenadelauncher || Item[pFirer->usAttackingWeapon].rocketlauncher || Item[pFirer->usAttackingWeapon].singleshotrocketlauncher || Item[pFirer->usAttackingWeapon].mortar) + // gMercProfiles[ pFirer->ubProfile ].records.usMissilesLaunched++; + // else if ( Item[ pFirer->usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE ) + // gMercProfiles[ pFirer->ubProfile ].records.usKnivesThrown++; + // else + // gMercProfiles[ pFirer->ubProfile ].records.usShotsFired++; + // + // ///////////////////////////////////////////////////////////////////////////////////// + //} if ( Item[ pFirer->usAttackingWeapon ].usItemClass == IC_THROWING_KNIFE ) { @@ -3895,7 +3992,7 @@ INT8 FireBullet( SOLDIERTYPE * pFirer, BULLET * pBullet, BOOLEAN fFake ) if ( pBullet->usFlags & ( BULLET_FLAG_CREATURE_SPIT | BULLET_FLAG_KNIFE | BULLET_FLAG_MISSILE | BULLET_FLAG_SMALL_MISSILE | BULLET_FLAG_TANK_CANNON | BULLET_FLAG_FLAME /*| BULLET_FLAG_TRACER*/ ) ) pBullet->usClockTicksPerUpdate = (Weapon[ pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pFirer->inv[pFirer->ubAttackingHand]) ) / 10; else - if (gGameExternalOptions.gbBulletTracer) + if (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS]) pBullet->usClockTicksPerUpdate = (Weapon[ pFirer->usAttackingWeapon ].ubBulletSpeed + GetBulletSpeedBonus(&pFirer->inv[pFirer->ubAttackingHand]) ) / 10; else pBullet->usClockTicksPerUpdate = 1; @@ -3932,9 +4029,478 @@ ddOrigHorizAngle = atan2( dDeltaY, dDeltaX ); } */ +// HEADROCK HAM 4: This formula no longer causes the bullet to deviate. That is handled by AdjustCenterPoint(). This +// formula is now only responsible for setting the bullet to go where it's told to, and create spread patterns around +// the bullet. +INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sApertureRatio, BOOLEAN fBuckshot, BOOLEAN fFake ) +{ + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"FireBulletGivenTarget"); + // fFake indicates that we should set things up for a call to ChanceToGetThrough + FLOAT dStartZ=0; + + FLOAT d2DDistance=0; + FLOAT dDeltaX=0; + FLOAT dDeltaY=0; + FLOAT dDeltaZ=0; + + FLOAT dStartX=0; + FLOAT dStartY=0; + + DOUBLE ddOrigHorizAngle=0; + DOUBLE ddOrigVerticAngle=0; + DOUBLE ddHorizAngle=0; + DOUBLE ddVerticAngle=0; + DOUBLE ddAdjustedHorizAngle=0; + DOUBLE ddAdjustedVerticAngle=0; + DOUBLE ddDummyHorizAngle=0; + DOUBLE ddDummyVerticAngle=0; + + BULLET * pBullet=NULL; + INT32 iBullet=0; + + INT32 iDistance=0; + + UINT8 ubLoop=0; + UINT8 ubShots=0; + UINT8 ubImpact=0; + INT8 bCTGT; + UINT8 ubSpreadIndex = 0; + UINT16 usBulletFlags = 0; + int n=0; + + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBulletGivenTarget")); + + CalculateSoldierZPos( pFirer, FIRING_POS, &dStartZ ); + + dStartX = (FLOAT) CenterX( pFirer->sGridNo ); + dStartY = (FLOAT) CenterY( pFirer->sGridNo ); + + dDeltaX = dEndX - dStartX; + dDeltaY = dEndY - dStartY; + dDeltaZ = dEndZ - dStartZ; + + //lal bugfix + if( dDeltaZ > 0 ) + d2DDistance = Distance3D( dDeltaX, dDeltaY, dDeltaZ ); + else + d2DDistance = Distance2D( dDeltaX, dDeltaY ); + + //d2DDistance = Distance2D( dDeltaX, dDeltaY ); + + iDistance = (INT32) d2DDistance; + + if ( d2DDistance != iDistance ) + { + iDistance += 1; + d2DDistance = (FLOAT) ( iDistance); + } + + ddOrigHorizAngle = atan2( dDeltaY, dDeltaX ); + ddOrigVerticAngle = atan2( dDeltaZ, (d2DDistance * 2.56f) ); + ddAdjustedHorizAngle = ddOrigHorizAngle; + ddAdjustedVerticAngle = ddOrigVerticAngle; + + ubShots = 1; + fTracer = FALSE; + + // Check if we have spit as a weapon! + if ( Weapon[ usHandItem ].ubWeaponClass == MONSTERCLASS ) + { + usBulletFlags |= BULLET_FLAG_CREATURE_SPIT; + } + else if ( Item[ usHandItem ].usItemClass == IC_THROWING_KNIFE ) + { + usBulletFlags |= BULLET_FLAG_KNIFE; + } + else if ( Item[usHandItem].rocketlauncher ) + { + usBulletFlags |= BULLET_FLAG_MISSILE; + } + else if ( Item[usHandItem].cannon ) + { + usBulletFlags |= BULLET_FLAG_TANK_CANNON; + } + else if ( Item[usHandItem].rocketrifle ) + { + usBulletFlags |= BULLET_FLAG_SMALL_MISSILE; + } + else if ( usHandItem == FLAMETHROWER ) + { + usBulletFlags |= BULLET_FLAG_FLAME; + ubSpreadIndex = 2; + } + // HEADROCK HAM B2.5: Set tracer effect on/off for individual bullets in a Tracer Magazine, as part of the + // New Tracer System. + else if (gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0) + && AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect ) + { + UINT16 iBulletsLeft, iBulletsPerTracer; + iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer; + iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst; + + if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1) + { + fTracer = TRUE; + } + else + { + fTracer = FALSE; + } + } + else if ( AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect && (pFirer->bDoBurst || gGameSettings.fOptions[ TOPTION_TRACERS_FOR_SINGLE_FIRE ]) ) + { + //usBulletFlags |= BULLET_FLAG_TRACER; + fTracer = TRUE; + } + + ubImpact =(UINT8) GetDamage(&pFirer->inv[pFirer->ubAttackingHand]); + //zilpin: Begin new code block for spread patterns, number of projectiles, impact adjustment, etc. + { + ObjectData *weapon = &(pFirer->inv[pFirer->ubAttackingHand][0]->data); + ubShots = AmmoTypes[ weapon->gun.ubGunAmmoType].numberOfBullets; + ubSpreadIndex = GetSpreadPattern( &pFirer->inv[pFirer->ubAttackingHand] ); + if( ubShots>1 && !fFake ) + { + fBuckshot = true; + usBulletFlags |= BULLET_FLAG_BUCKSHOT; + ubImpact = (UINT8) (ubImpact * AmmoTypes[weapon->gun.ubGunAmmoType].multipleBulletDamageMultiplier / max(1,AmmoTypes[weapon->gun.ubGunAmmoType].multipleBulletDamageDivisor) ); + if (pFirer->ubTargetID != NOBODY) + { + MercPtrs[ pFirer->ubTargetID ]->bNumPelletsHitBy = 0; + } + } + weapon=NULL; + } + //zilpin: End of new code block. + + // GET BULLET + for (ubLoop = 0; ubLoop < ubShots; ubLoop++) + { + iBullet = CreateBullet( pFirer->ubID, fFake, usBulletFlags,usHandItem ); + if (iBullet == -1) + { + //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Failed to create bullet") ); + + return( FALSE ); + } + pBullet = GetBulletPtr( iBullet ); + + // HEADROCK HAM 4: The HitBy value now holds the ratio between the Distance Aperture and the Final Aperture. + // Basically, this represents by how much our shooter has managed to make the shot more accurate than it would + // be without any extra aiming or optical equipment. HitBy can now only be positive, and equals 100 when the + // shot is perfectly on-target, or 0 when it is as inaccurate as the shooting system can possibly allow. + // In this sense, sApertureRatio is the closest "relative" that the NCTH system has to the old system. it tells + // us, on a scale of 0-100, how accurate we are compared to "Best" and "Worst" accuracy. + // Note also that references to this value have been changed accordingly. Most imporantly, functions that alter + // the path of the bullet, or determine whether collisions are more likely thanks to low HitBy, have been + // altered to _not use this value at all_. + // At the moment, HitBy is used only for determining extra damage (0-50% extra), and for determining + // how much extra experience is gained by the shooter if the target is actually hit by the bullet. + pBullet->sHitBy = sApertureRatio; + + // HEADROCK HAM 4: TODO: Determine whether this value is required anymore. Why ever let bullets + // pass through the roof at all?? + if (dStartZ < WALL_HEIGHT_UNITS) + { + if (dEndZ > WALL_HEIGHT_UNITS) + { + pBullet->fCheckForRoof = TRUE; + } + else + { + pBullet->fCheckForRoof = FALSE; + } + } + else // dStartZ >= WALL_HEIGHT_UNITS; presumably > + { + if (dEndZ < WALL_HEIGHT_UNITS) + { + pBullet->fCheckForRoof = TRUE; + } + else + { + pBullet->fCheckForRoof = FALSE; + } + } + + //zilpin: pellet spread patterns externalized in XML + //Now the first shot will use the pattern, as well. + //Single shot weapons will still be stuck with straight-ahead only, though. + //if ( ubLoop == 0 ) + if( ubShots == 1 ) + { + // HEADROCK HAM 4: Firing increments no longer required here (NCTH) + // calculate by hand (well, without angles) to match LOS + pBullet->qIncrX = FloatToFixed( dDeltaX / (FLOAT)iDistance ); + pBullet->qIncrY = FloatToFixed( dDeltaY / (FLOAT)iDistance ); + pBullet->qIncrZ = FloatToFixed( dDeltaZ / (FLOAT)iDistance ); + } + else if( ubShots > 1 ) + { + //Calculate the deviation due to to-hit, but only for the first shot. + //The bullet is only used temporarily. It gets reset later. + //Should this use d3DDistance? + //if( ubLoop<1 ){ + // CalculateFiringIncrements( ddOrigHorizAngle, ddOrigVerticAngle, d2DDistance, pBullet, &ddAdjustedHorizAngle, &ddAdjustedVerticAngle ); + //} + + // temporarily set bullet's sHitBy value to 0 to get unadjusted angles + //Note: this no longer needs to be done since the CalculateFiringIncrementsSimple is being used below. + //pBullet->sHitBy = 0; + + //Also prevent out-of-bounds overflows. + //Rotates through the array if more pellets than expected, and uses pattern index 0 if requested pattern does not exist. + if( gpSpreadPattern == NULL || giSpreadPatternCount<1 ){ + //XML file missing, or empty, or error while loading. Use hard-coded defaults. + //This is from the original code. + if( ubSpreadIndex > 2 || ubSpreadIndex<0 ) ubSpreadIndex=0; + n = ubLoop % BUCKSHOT_SHOTS; + ddHorizAngle = ddAdjustedHorizAngle + ddShotgunSpread[ubSpreadIndex][n][0]; + ddVerticAngle = ddAdjustedVerticAngle + ddShotgunSpread[ubSpreadIndex][n][1]; + }else{ + double d=0,r=0,xspread=0,yspread=0; + int n=0; + + //Use spread patterns loaded from XML. + if( ubSpreadIndex >= giSpreadPatternCount || ubSpreadIndex < 0) + ubSpreadIndex=0; + + xspread=gpSpreadPattern[ubSpreadIndex].xspread; + yspread=gpSpreadPattern[ubSpreadIndex].yspread; + + //Only use randomized spread pattern if the random spread is defined AND each static angle already fired once. + if( ubLoop >= gpSpreadPattern[ubSpreadIndex].iCount && (xspread + yspread) ){ + //Create random angle within range, positive and negative. + switch( gpSpreadPattern[ubSpreadIndex].method ) + { + case SPREADPATTERNMETHOD_RECT: //Rectangle Method. (Simple) + //Applying a new random number to each angle results in a rectangular spread pattern, rather than an oval one. + ddHorizAngle = (double)rand() * 2 * xspread / RAND_MAX - xspread; + ddVerticAngle = (double)rand() * 2 * yspread / RAND_MAX - yspread; + break; + case SPREADPATTERNMETHOD_DIAMOND: //Diamond Method. (Kinda Simple) + //Angles are generated within a diamond shaped region. + //This is more natural than the rectangular pattern, but still not optimal. + //The first random number is in a range of 0 to (x+y). + d = (xspread+yspread) * (double)rand() / (double)RAND_MAX; + //The second random number determines the percentage of that value to use on x. The rest is spent on y. + r = (double)rand() / (double)RAND_MAX; + ddHorizAngle = r*d; + ddVerticAngle = (1-r)*d; + //Positive and negative are then randomly determined. Otherwise, everthing would always shoot to the high right (+,+). + n = rand()%4; + if(n&1) ddHorizAngle *= -1; + if(n&2) ddVerticAngle *= -1; + break; + case SPREADPATTERNMETHOD_ELLIPSE: //Ellipse Method. + //Angles are generated within an ellipse. + //This is getting close to true spread behaviour, and may be the preferred general purpose method. + //However, due to the distribution of random numbers for r, the pattern generated tends to have + //more pellets land along the axis, making the pattern look a bit like the Swiss cross sometimes. + //(It only becomes noticable in simulations I do in an external program. In-game it looks fine.) + // + //First, get our random range of -pi to pi. This could be recalculated for every use, but doesn't need to be. + r=(double)rand()*2*PI/RAND_MAX - PI; + //Which axis is our major axis? + if( xspread > yspread ) + { + //The Ellipse. + // Any point on an Ellipse border line = (x,y) + // where x = m * cos(r) and y = n * sin(r) + // where m = major axis radius and n = minor axis radius and r = all values -pi <= r <= pi + //We use any random value between -pi and pi, but vary the radius to get points inside the ellipse as well. + ddHorizAngle = ( (double)rand()*xspread / RAND_MAX ) * cos(r); + ddVerticAngle = ( (double)rand()*yspread / RAND_MAX ) * sin(r); + }else{ + //Reverse sine and cosine if our major axis is y. + ddHorizAngle = ( (double)rand()*xspread / RAND_MAX ) * sin(r); + ddVerticAngle = ( (double)rand()*yspread / RAND_MAX ) * cos(r); + } + break; + case -1: //Optimal Method. (Most realistic) + //Not yet implemented. + //Using the random distribution above, normal distrubution causes more pellets to end up toward the middle. + //This is generally not noticable, and in fact feels more natural to some people (not zilpin), + //but is not _even_ distribution. + //In addition, since it is random, it is possible for all of the pellets to vear off center, + //resulting in rare unnatural freak shots, which would never occur in a real shotgun. + //This may add to gameplay, but it may bother some people (like zilpin). + //Should anyone devise a way to adjust the ellipse distribution to account for this, here is where to put it. + //This would probably be done by adjusting the random value of 'r' above. + //Contact zilpin for real life shotgun spread pattern data, if you happen to be one of those mathematicians + //who can extrapolate a succinct algorithm from raw data. But keep in mind that there's not much data to go on. + // + //Also note that in the real world, shot spread tends to take the shape of a sagging funnel, rather than a cone. + //That is to say, the path of each pellet follows a mild curve, not a straight line. + //I'm really not going to worry about that here. Ever. + break; + default: + //If an invalid method is set in the structure, no randomized pellets are shot. + //Note that there still may have been static angle pellets fired. + //This should never happen, since the XML loading function will set them to giSpreadPatternMethod_Default. + break; + } + }else if( gpSpreadPattern[ubSpreadIndex].iCount>0 ){ + //Use static angle, if they exist. + n = ubLoop % gpSpreadPattern[ubSpreadIndex].iCount; + ddHorizAngle = gpSpreadPattern[ubSpreadIndex].x[n]; + ddVerticAngle = gpSpreadPattern[ubSpreadIndex].y[n]; + }else{ + //No angles defined, so just fire straight. + ddHorizAngle = ddVerticAngle = 0.0; + } + + + //#ifdef JA2TESTVERSION + DOUBLE ddRawHorizAngle = ddHorizAngle; + DOUBLE ddRawVerticAngle = ddVerticAngle; + //#endif + + //Adjust based on the to-hit deviation calculated when the first pellet was fired. + ddHorizAngle += ddAdjustedHorizAngle; + ddVerticAngle += ddAdjustedVerticAngle; + + //Logging for debugging + //#ifdef JA2TESTVERSION + if(!fFake) + { + FILE *OutFile; + if ((OutFile = fopen("SpreadPatternLog.txt", "a+t")) != NULL) + { + //To easily cut-and-paste these values from the log into a C/C++ source file for later analysis + //Lots of reference debug info in a comment. + fprintf(OutFile, "{ % 9.8f , % 9.8f , % 9.8f , % 9.8f }, //DEBUG: merc %4d fired pellet %4d of %4d using method %4d %12s with SpreadPattern %4d %s\n", + ddRawHorizAngle, ddRawVerticAngle, + ddHorizAngle, ddVerticAngle, + pFirer->ubID, ubLoop, ubShots, + gpSpreadPattern[ubSpreadIndex].method, gSpreadPatternMethodNames[gpSpreadPattern[ubSpreadIndex].method], + ubSpreadIndex, gpSpreadPattern[ubSpreadIndex].Name, + NULL + ); + fclose(OutFile); + } + } + //#endif + } + + //Just calculate the increments the bullet will use, not any of the to-hit adjustments, because we already did. + CalculateFiringIncrementsSimple( ddHorizAngle, ddVerticAngle, pBullet ); + } + + + pBullet->ddHorizAngle = ddHorizAngle; + + if (ubLoop == 0 && pFirer->bDoBurst < 2) + { + pBullet->fAimed = TRUE; + } + else + { + // buckshot pellets after the first can hit friendlies even at close range + pBullet->fAimed = FALSE; + } + + if ( pBullet->usFlags & BULLET_FLAG_KNIFE ) + { + pBullet->ubItemStatus = pFirer->inv[pFirer->ubAttackingHand][0]->data.objectStatus; + } + + // apply increments for first move + + //zilpin: pellet spread patterns externalized in XML + //This is a bugfix for strange behavior when firing, such as the projectile hitting walls behind a merc. + //The bullet should start it's journey at the beginning, not down range. + //Commented out the qIncr adjustments. + pBullet->qCurrX = FloatToFixed( dStartX ) ; //+ pBullet->qIncrX; + pBullet->qCurrY = FloatToFixed( dStartY ) ; //+ pBullet->qIncrY; + pBullet->qCurrZ = FloatToFixed( dStartZ ) ; //+ pBullet->qIncrZ; + + //zilpin: pellet spread patterns externalized in XML + //Also bugfix. I understand why this was added, but it causes problems. + /* + // NB we can only apply correction for leftovers if the bullet is going to hit + // because otherwise the increments are not right for the calculations! + if ( pBullet->sHitBy >= 0 ) + { + pBullet->qCurrX += ( FloatToFixed( dDeltaX ) - pBullet->qIncrX * iDistance ) / 2; + pBullet->qCurrY += ( FloatToFixed( dDeltaY ) - pBullet->qIncrY * iDistance ) / 2; + pBullet->qCurrZ += ( FloatToFixed( dDeltaZ ) - pBullet->qIncrZ * iDistance ) / 2; + } + */ + + pBullet->iImpact = ubImpact; + + pBullet->iRange = GunRange( &(pFirer->inv[pFirer->ubAttackingHand]), pFirer ); // SANDRO - added argument + pBullet->sTargetGridNo = ((INT32)dEndX) / CELL_X_SIZE + ((INT32)dEndY) / CELL_Y_SIZE * WORLD_COLS; + + pBullet->bStartCubesAboveLevelZ = (INT8) CONVERT_HEIGHTUNITS_TO_INDEX( (INT32)dStartZ - CONVERT_PIXELS_TO_HEIGHTUNITS( gpWorldLevelData[ pFirer->sGridNo ].sHeight ) ); + pBullet->bEndCubesAboveLevelZ = (INT8) CONVERT_HEIGHTUNITS_TO_INDEX( (INT32)dEndZ - CONVERT_PIXELS_TO_HEIGHTUNITS( gpWorldLevelData[ pBullet->sTargetGridNo ].sHeight ) ); + + // this distance limit only applies in a "hard" sense to fake bullets for chance-to-get-through, + // but is used for determining structure hits by the regular code + pBullet->iDistanceLimit = iDistance; + // HEADROCK HAM BETA2.5: New method for signifying whether a bullet is a tracer or not, using an individual + // bullet structure flag. Hehehehe, I think this is kind of reverting to old code, isn't it? + if (gGameExternalOptions.ubRealisticTracers > 0 && gGameExternalOptions.ubNumBulletsPerTracer > 0 && (pFirer->bDoAutofire > 0 || pFirer->bDoBurst > 0) + && AmmoTypes[ pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType ].tracerEffect ) + { + UINT16 iBulletsLeft, iBulletsPerTracer; + iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer; + iBulletsLeft = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunShotsLeft + pFirer->bDoBurst; + + // Is this specific bullet a tracer? - based on how many tracers there are per regular bullets in + // a tracer magazine (INI-settable). + if ((((iBulletsLeft - (pFirer->bDoBurst - 1)) / iBulletsPerTracer) - ((iBulletsLeft - pFirer->bDoBurst) / iBulletsPerTracer)) == 1) + { + pBullet->fTracer = TRUE; + } + else + { + pBullet->fTracer = FALSE; + } + } + if (fFake) + { + bCTGT = FireBullet( pFirer, pBullet, TRUE ); + RemoveBullet( iBullet ); + return( bCTGT ); + } + else + { + // if (ubLoop + 1 > pFirer->bBulletsLeft) + // { + // // this is an error!! + // ubLoop = ubLoop; + // } + //hayden + if(is_client)send_bullet( pBullet, usHandItem ); + FireBullet( pFirer, pBullet, FALSE ); + } + } + + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if( !fFake && ( pFirer->ubProfile != NO_PROFILE ) && ( pFirer->bTeam == gbPlayerNum ) ) + { + // another shot fired + if ( Item[usHandItem].usItemClass == IC_LAUNCHER || Item[usHandItem].grenadelauncher || Item[usHandItem].rocketlauncher || Item[usHandItem].singleshotrocketlauncher || Item[usHandItem].mortar) + gMercProfiles[ pFirer->ubProfile ].records.usMissilesLaunched++; + else if ( Item[usHandItem].usItemClass == IC_THROWING_KNIFE ) + gMercProfiles[ pFirer->ubProfile ].records.usKnivesThrown++; + else + gMercProfiles[ pFirer->ubProfile ].records.usShotsFired++; + } + ///////////////////////////////////////////////////////////////////////////////////// + + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBulletGivenTargetDone")); + + return( TRUE ); +} INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sHitBy, BOOLEAN fBuckshot, BOOLEAN fFake ) { + if(UsingNewCTHSystem() == true) + return FireBulletGivenTargetNCTH(pFirer, dEndX, dEndY, dEndZ, usHandItem, sHitBy, fBuckshot, fFake); //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"FireBulletGivenTarget"); // fFake indicates that we should set things up for a call to ChanceToGetThrough FLOAT dStartZ=0; @@ -4362,7 +4928,7 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA pBullet->iImpact = ubImpact; - pBullet->iRange = GunRange( &(pFirer->inv[pFirer->ubAttackingHand]) ); + pBullet->iRange = GunRange( &(pFirer->inv[pFirer->ubAttackingHand]), pFirer ); // SANDRO - added argument pBullet->sTargetGridNo = ((INT32)dEndX) / CELL_X_SIZE + ((INT32)dEndY) / CELL_Y_SIZE * WORLD_COLS; pBullet->bStartCubesAboveLevelZ = (INT8) CONVERT_HEIGHTUNITS_TO_INDEX( (INT32)dStartZ - CONVERT_PIXELS_TO_HEIGHTUNITS( gpWorldLevelData[ pFirer->sGridNo ].sHeight ) ); @@ -4405,11 +4971,27 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA // ubLoop = ubLoop; // } //hayden - if(is_client)send_bullet( pBullet, usHandItem ); + if(is_client) + send_bullet( pBullet, usHandItem ); + FireBullet( pFirer, pBullet, FALSE ); } } + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if( !fFake && ( pFirer->ubProfile != NO_PROFILE ) && ( pFirer->bTeam == gbPlayerNum ) ) + { + // another shot fired + if ( Item[usHandItem].usItemClass == IC_LAUNCHER || Item[usHandItem].grenadelauncher || Item[usHandItem].rocketlauncher || Item[usHandItem].singleshotrocketlauncher || Item[usHandItem].mortar) + gMercProfiles[ pFirer->ubProfile ].records.usMissilesLaunched++; + else if ( Item[usHandItem].usItemClass == IC_THROWING_KNIFE ) + gMercProfiles[ pFirer->ubProfile ].records.usKnivesThrown++; + else + gMercProfiles[ pFirer->ubProfile ].records.usShotsFired++; + } + ///////////////////////////////////////////////////////////////////////////////////// + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBulletGivenTargetDone")); return( TRUE ); @@ -4430,7 +5012,8 @@ INT8 ChanceToGetThrough( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT d } } - return( FireBulletGivenTarget( pFirer, dEndX, dEndY, dEndZ, pFirer->usAttackingWeapon, 0, fBuckShot, TRUE ) ); + // HEADROCK HAM 4: Changed argument from "hitBy"->"Aperture". Value 0->100. + return( FireBulletGivenTarget( pFirer, dEndX, dEndY, dEndZ, pFirer->usAttackingWeapon, (UsingNewCTHSystem()?100:0), fBuckShot, TRUE ) ); } else { @@ -4444,7 +5027,8 @@ INT8 ChanceToGetThrough( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT d pFirer->inv[ HANDPOS ] = GLOCK_17_ForUseWithLOS; pFirer->usAttackingWeapon = GLOCK_17; - INT8 retVal = FireBulletGivenTarget( pFirer, dEndX, dEndY, dEndZ, GLOCK_17, 0, FALSE, TRUE ); + // HEADROCK HAM 4: Changed argument from "Hitby"->"Aperture". Value 0->100. + INT8 retVal = FireBulletGivenTarget( pFirer, dEndX, dEndY, dEndZ, GLOCK_17, (UsingNewCTHSystem()?100:0), FALSE, TRUE ); pFirer->inv[ HANDPOS ] = oldItemInHand; pFirer->usAttackingWeapon = oldAttackingWeapon; @@ -4562,6 +5146,9 @@ void MoveBullet( INT32 iBullet ) iNumLocalStructures = 0; pStructure = pMapElement->pStructureHead; // calculate chance of hitting each structure + // HEADROCK HAM 4: This function no longer makes use of the HitBy argument, thanks to its nature having + // been changed by the NCTH system. I've left the argument in the function however, in case we need to + // undo that change later (I.E. find some way to increase collisions based on the new HitBy). uiChanceOfHit = ChanceOfBulletHittingStructure( pBullet->iLoop, pBullet->iDistanceLimit, pBullet->sHitBy ); if (iGridNo == (INT32) pBullet->sTargetGridNo) { @@ -5278,16 +5865,38 @@ void MoveBullet( INT32 iBullet ) pBullet->sGridNo = MAPROWCOLTOPOS( pBullet->iCurrTileY , pBullet->iCurrTileX ); uiTileInc++; - if ( (pBullet->iLoop > pBullet->iRange * 2) ) - { - // beyond max effective range, bullet starts to drop! - // since we're doing an increment based on distance, not time, the - // decrement is scaled down depending on how fast the bullet is (effective range) - pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); - } - else if ( (pBullet->usFlags & BULLET_FLAG_FLAME) && ( pBullet->iLoop > pBullet->iRange ) ) - { - pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); + if(UsingNewCTHSystem()){ + // HEADROCK HAM 4: This is kind of a hack. I'm measuring the distance the tile has moved in 2D space, + // for purposes of determining whether gravity should take effect. + FLOAT dDistanceMoved = PythSpacesAway( pBullet->pFirer->sGridNo, pBullet->sGridNo ) * 10.0f; + + // HEADROCK HAM 4: Now using an INI=set Gravity Constant. + // HEADROCK HAM 4: TODO: Should this also be changed to use the Gravity Coefficient? + if ( (dDistanceMoved > pBullet->iRange) ) + { + // beyond max effective range, bullet starts to drop! + // since we're doing an increment based on distance, not time, the + // decrement is scaled down depending on how fast the bullet is (effective range) + //pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); + pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * gGameCTHConstants.GRAVITY_COEFFICIENT); + } + else if ( (pBullet->usFlags & BULLET_FLAG_FLAME) && (dDistanceMoved > pBullet->iRange) ) + { + //pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); + pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * (gGameCTHConstants.GRAVITY_COEFFICIENT / 2) ); + } + } else { + if ( (pBullet->iLoop > pBullet->iRange * 2) ) + { + // beyond max effective range, bullet starts to drop! + // since we're doing an increment based on distance, not time, the + // decrement is scaled down depending on how fast the bullet is (effective range) + pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); + } + else if ( (pBullet->usFlags & BULLET_FLAG_FLAME) && ( pBullet->iLoop > pBullet->iRange ) ) + { + pBullet->qIncrZ -= INT32_TO_FIXEDPT( 100 ) / (pBullet->iRange * 2); + } } // check to see if bullet is close to target @@ -5874,7 +6483,1419 @@ BOOLEAN CalculateLOSNormal( STRUCTURE *pStructure, INT8 bLOSX, INT8 bLOSY, INT8 } +////////////////////////////////////////////////////////////////////////////////////////// +// HEADROCK HAM 4: New Shooting Mechanism +// +// The Shooting Mechanism has been significantly altered in HAM 4. With the new system, +// any shot has a certain random deviation off the target center. The possible (max) +// size of this deviation is affected by many factors, including primarily the shooter's +// skill and aiming, the scope used, the gun's inherent properties, and so on. This is +// calculated in several distinct steps, each of which is responsible for one type of +// effect, such as the sway of the muzzle or tracking the target's movement. +// +// This function, which basically drives the whole thing, plays with the location of the +// "center point", the point where the gun would shoot if aimed and fired with 100% accuracy. +// The idea is to make gunplay more randomal and less exploitable. +// +// Related changes include an overhaul of the CalcChanceToHit() formula, as well as +// restructuring of UseGun() and its sub-functions. + +void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT *dEndX, FLOAT *dEndY, FLOAT *dEndZ, OBJECTTYPE *pWeapon, UINT32 uiMuzzleSway, INT16 *sApertureRatio ) +{ + /////////////////////////////////////////// + // Calculate shooter's coordinates + + FLOAT dStartX=0; + FLOAT dStartY=0; + FLOAT dStartZ=0; + + // Find start Z for the shooter given his stance and location. This actually marks the point where the gun's + // muzzle is located. + CalculateSoldierZPos( pShooter, FIRING_POS, &dStartZ ); + + // Locate absolute center X,Y of the shooter + dStartX = (FLOAT) CenterX( pShooter->sGridNo ); + dStartY = (FLOAT) CenterY( pShooter->sGridNo ); + + //////////////////////////////////////////////////////////////////////////// + // Calculate difference (Delta) between start and end point of bullet flight + + FLOAT dDeltaX=0; + FLOAT dDeltaY=0; + FLOAT dDeltaZ=0; + + dDeltaX = *dEndX - dStartX; + dDeltaY = *dEndY - dStartY; + dDeltaZ = *dEndZ - dStartZ; + + /////////////////////////////////////////////////////////////////////// + // Find distance between shooter and target, in points. + FLOAT d2DDistance=0; + + d2DDistance = Distance3D( dDeltaX, dDeltaY, CONVERT_HEIGHTUNITS_TO_DISTANCE( dDeltaZ ) ); + + // Round it upwards. + INT32 iDistance = (INT32) d2DDistance; + if ( d2DDistance != iDistance ) + { + iDistance += 1; + d2DDistance = (FLOAT) ( iDistance); + } + + //////////////////////////////////////////////////////////////////////// + // Calculate the "shot angle". This is the angle of a "perfect" shot, from the end of the muzzle straight + // to the center of the target. The resulting angle, in Radians, is relative to the Positive X axis. + DOUBLE ddOrigHorizAngle=0; + DOUBLE ddOrigVerticAngle=0; + + ddOrigHorizAngle = atan2( dDeltaY, dDeltaX ); + ddOrigVerticAngle = atan2( dDeltaZ, (d2DDistance * 2.56f) ); + + ////////////////////////////////////////////////////////////////////////////// + // + // Now that we have the perfect shot coordinates and angle, we can start applying various movements to + // the gun's muzzle. We take into account both the Muzzle Sway factor calculated by the CTH formula, as well + // as compensation for things like firing out of range or firing at a moving target. + // + // Movements are recorded as relative to the center of the target, either left/right, up/down, or both. + // Imagine the center of the target being at 0,0. + // Positive X movement is to the right of the target, Positive Y movement is above the target. + // We'll use these values later to determine where the bullet should actually go. + + // Muzzle Offset values track movements of the gun's barrel. They'll be fed to various formulae here, which + // will alter and return them as necessary. + FLOAT dMuzzleOffsetX = 0.0; + FLOAT dMuzzleOffsetY = 0.0; + + ////////////////////////////////////////////////////////////////////////////////////// + // STEP 1: Shot Aperture + // + // Here we calculate the maximum radius of movement possible for our gun's muzzle, given the Muzzle Sway + // value which was fed into this function. The larger the Muzzle Sway, the larger the radius, and thus the + // more our muzzle can randomly sway away from the target's center. + // We'll later use Shot Aperture to limit the final Muzzle Offset values. + + FLOAT iBasicAperture = 0.0; + FLOAT iDistanceAperture = 0.0; + FLOAT iMaxAperture = 0.0; + FLOAT iAperture = 0.0; + + // First, let's calculate the basic Aperture. This is the size of an unmodified aperture at 1x Normal Distance. + iBasicAperture = CalcBasicAperture( ); + + // Next, find out how large the aperture can be around the target, given range. The further the target is, the + // larger the aperture can be. + iDistanceAperture = iBasicAperture * (d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + + /////////////////////////////////////////////////////////////// + // To make things easier for us, we now calculate the Magnification Factor for this shot. A Mag Factor + // is a divisor to the sway of the muzzle. It's about the same as multiplying CTH by a certain amount. + // Note that both optical magnification devices (like scopes) and dot-projection devices (like lasers and + // reflex sights) provide this sort of bonus. + + FLOAT iMagFactor = CalcMagFactor( pShooter, pWeapon, d2DDistance, (UINT8)pShooter->aiData.bAimTime ); + + // Next step is to apply scope/projection factor to decrease the size of the aperture. This gives us the "Max + // Aperture" value - the size of the shooting circle if the gun is as unstable as possible. + iMaxAperture = iDistanceAperture / iMagFactor; + + // We now use the Muzzle Sway value, calculated by the CTH formula, to decrease the size of the shot aperture. + // It is used as a percentage: a 50% muzzle sway value gives a cone with half the maximum radius. A cone with + // 0% Muzzle Sway is a single line with no width (meaning all shots will fly right down the center, and all will + // hit the target), while a cone with 100% muzzle sway is as wide as possible. + iAperture = (FLOAT)((iMaxAperture * uiMuzzleSway) / 100); + + // Aperture ratio below is used for Experience Gain. The smaller the aperture, compared to the size of the + // Distance Aperture, the more experience we get. + // Since we're using the Distance Aperture for this calculation, the final result is much smaller (better) + // when scopes are in play. + // Note that we calculate experience gain in the Bullet Impact formula now, to allow increasing experience + // gain based on whether the target was actually hit or not. + *sApertureRatio = (INT16)(100.0f - ((iAperture / iDistanceAperture) * 100.0f)); + + /////////////////////////////////////////////////////////////////////////////////////// + // MUZZLE MOVEMENTS + // + // We begin by calculating effects that change the direction of the muzzle. Every change in muzzle direction + // may lead to "missing" the center of the target, although that doesn't mean the target won't be hit anyway. + // + // The calculations in this section are only done for single-shot bullets, or the first bullet in a burst/auto + // volley. If a volley continues, subsequent bullets will "inherit" past muzzle movements from one another. + // As you'll see, this allows the shooter to readjust the weapon WHILE it is firing, rather than randomize + // muzzle movements every time. + + if (pShooter->bDoBurst <= 1) + { + + /////////////////////////////////////////////////////////////////////////////////////////// + // STEP 2: Random Muzzle Sway + // + // Our "Shot Aperture" determines a radius around the target's center, within which our + // muzzle might be pointed when the trigger is squeezed. By reducing Muzzle Sway (through + // aiming and skill), we make this radius smaller. + // Here, we pick a random point within the circle drawn by this radius. This is where + // the muzzle will be pointed, relative to the center of the target, when the trigger is pulled. + + CalcMuzzleSway( pShooter, &dMuzzleOffsetX, &dMuzzleOffsetY, iAperture ); + + ///////////////////////////////////////////////////////////////////////////////////////////// + // STEP 3: Lateral Offset due to Target Movement + // + // Moving targets are harder to hit, because the shooter needs to anticipate motion and point + // his gun accordingly ahead of the target. This is called "Leading". The following function + // measures how much the target has moved, and adjusts the gun to point BEHIND the target. + // Depending on the size of the Shot Aperture, as well as the aptitude of the shooter himself, + // this could mean that shots will all (or most) go behind the target, as though firing at where + // it WAS rather than where it IS. + // Note that the Target Tracking formula only adjusts the muzzle along the X-Axis, I.E. moving the + // shot behind the target, never up or down. + + SOLDIERTYPE *pTarget = SimpleFindSoldier( iTargetGridNo, pShooter->bTargetLevel ); + if (pTarget) + { + CalcTargetMovementOffset( pShooter, pTarget, pWeapon, &dMuzzleOffsetX, ddOrigHorizAngle, (INT32)iAperture ); + } + + ///////////////////////////////////////////// + // First shot in a burst/auto volley + + if (pShooter->bDoBurst == 1 || pShooter->bDoAutofire > 1) + { + // A shooter does not get to exercise counter-force on the first few bullets in a volley. + // These commands reset the counter-force. + pShooter->dPrevCounterForceX = 0.0; + pShooter->dPrevCounterForceY = 0.0; + + //////////////////////////////////////////////////////////////////////////////////////////// + // STEP 4: Pre-Compensating for Future Recoil + // + // Since soldiers can't use counter-force to work against the recoil of the first few bullets + // in a burst (it just happens too fast), they can instead adjust the muzzle of the gun + // BEFORE pulling the trigger. They take the gun's recoil into consideration for this. + // If the muzzle is adjusted by the exact correct amount (and assuming no other deviation from + // the other factors), the muzzle will end up pointed at the center of the target when the + // shooter gets his first chance to apply counter force. This dramatically increases the + // chance to hit the target with those first few bullets, again assuming no other deviation + // was applied. + CalcPreRecoilOffset( pShooter, pWeapon, &dMuzzleOffsetX, &dMuzzleOffsetY, (UINT32)d2DDistance ); + } + } + + // The first bullet in a burst/autofire volley works the same as a single-shot (see above). However, once + // it's time to fire the second bullet, things change radically. Our shooter now knows (broadly) where his + // muzzle is pointing, and can use the time spent firing the volley to adjust his aim. This may or may not + // allow the shooter to actually compensate for aiming errors made with the first bullet! Of course, + // while doing this, the shooter also has to combat the weapon's recoil - a difficult job with some weapons. + else + { + // In a Burst/Autofire volley, we do not need to recalculate muzzle sway or target movement offsets and + // other related muzzle movements. Instead, we inherit the muzzle offset variables from the previous bullet + // in the volley. + dMuzzleOffsetX = pShooter->dPrevMuzzleOffsetX; + dMuzzleOffsetY = pShooter->dPrevMuzzleOffsetY; + + //////////////////////////////////////////////////////////////////////////////////////////// + // STEP 4: Recoil Offset + // + // Guns in NCTH have a defined recoil strength and direction. Different guns will "kick" differently. + // The shooter will need to apply force to counter the effects of recoil while the gun is firing, + // or else end up with bullets being fired up into the sky or down into the earth. Skilled shooters + // can actually productively handle their weapons, using this extra time to improve their aim by + // following the impact of the bullets and adjusting the muzzle direction accordingly. Of course, + // this is made difficult by having to fight the gun's recoil at the same time. + // This function alters the muzzle direction based on the gun's recoil, and the amount of counter-force + // our shooter applies to fight that recoil. + CalcRecoilOffset( pShooter, &dMuzzleOffsetX, &dMuzzleOffsetY, pWeapon, (UINT32)d2DDistance ); + } + + // At this point, basic muzzle deviation is fully calculated. For Autofire/Burst volleys, the next bullet + // in the volley will actually inherit these values and behave accordingly. For this purpose, we store + // the Muzzle Offset values in our shooter's data. + if ( pShooter->bDoBurst > 0 ) + { + // If this is the first shot in a burst/autofire volley, subsequent shots will inherit the same Muzzle + // Direction from this shot. In other words, when we reach the second (or later) bullet in the volley, + // we will no longer calculate the above movements like movement tracking or muzzle sway. Instead, we'll + // just remember were our muzzle was pointed last, and proceed from there. This allows volleys to be adjusted + // while they're being fired, with the hope of redirecting the muzzle towards the center of the target if + // the first shot was off-center. + pShooter->dPrevMuzzleOffsetX = dMuzzleOffsetX; + pShooter->dPrevMuzzleOffsetY = dMuzzleOffsetY; + } + else + { + // Single-shot fire does not require storing Muzzle Offset for later use. The next fired bullet will calculate + // its own offsets. To be on the safe side, we reset the Muzzle Offset values stored in the shooter's data. + pShooter->dPrevMuzzleOffsetX = 0; + pShooter->dPrevMuzzleOffsetY = 0; + } + + UINT16 uiRange = GunRange(pWeapon, pShooter); + // Is the target beyond the gun's range? + if (d2DDistance > (FLOAT)uiRange) + { + ////////////////////////////////////////////////////////////////////////////////////////// + // STEP 5: Bullet Drop Compensation + // + // Bullets reaching their maximum flight range will begin to drop towards the ground. Shooters wishing + // to fire beyond a gun's range can use the simple ballistic principle of raising the muzzle upwards to + // have the bullets fly in a higher angle - allowing the bullet to avoid hitting the ground for a little + // longer, and as a result having more actual range. However, this is tricky, and only the most skilled + // shooters will be able to do this reliably. In any case, this can't extend the range of the gun by more + // than a handful of tiles. + + CalcRangeCompensationOffset( pShooter, &dMuzzleOffsetY, (INT32)d2DDistance, pWeapon ); + } + + // We have now completed altering the direction of the muzzle. From here on in, the muzzle direction is fixed. + // However this doesn't mean that the shot will fly where the muzzle is pointed! We still have a few more + // steps to go. + FLOAT dShotOffsetX = dMuzzleOffsetX; + FLOAT dShotOffsetY = dMuzzleOffsetY; + + ///////////////////////////////////////////////////////////////////////////////////////////// + // STEP 6: Bullet Deviation + // + // In the old JA2 system, a gun's Accuracy value was treated a simple bonus to CTH. NCTH uses + // this value in a completely different fasion: It simulates a weapon's maximum "effective" range, + // the range at which a weapon can reliably hit the target it was aimed at (assuming perfect aim). + // Like Muzzle Sway (see above), the program "draws" a circle over the target whose radius is based + // on the Accuracy value. Higher accuracy = smaller circle. Then, it picks a completely random point + // within that circle, and sends the bullet that way. Over greater distances, this can amount to + // several penalties, thus making accurate weapons essential for any long-range shot. + + CalcBulletDeviation( pShooter, &dShotOffsetX, &dShotOffsetY, pWeapon, (UINT32)d2DDistance ); + + ///////////////////////////////////////////////////////////////////////////////////////////// + // STEP 7: Limit Shot Angle + // + // The system provides an INI-defined constant that tells us the maximum angle to which our + // shot might deviate, given all above factors combined. This is done mainly to avoid shots + // flying off in unrealistic directions, such as sideways or upwards. That can happen as a + // result of too many modifiers by the previous functions. In addition, the INI value also + // affects accuracy of ALL shots in the game, and is enforced here a second time. + + LimitImpactPointToMaxAperture( &dShotOffsetX, &dShotOffsetY, iDistanceAperture ); + + + // DEBUGGING: Remove this! + if (gGameSettings.fOptions[TOPTION_REPORT_MISS_MARGIN]) + { + CHAR16 szLeftRight[10]; + CHAR16 szUpDown[10]; + + if (dShotOffsetX > 0) + { + swprintf(szLeftRight, L"right"); + } + else + { + swprintf(szLeftRight, L"left"); + } + if (dShotOffsetY > 0) + { + swprintf(szUpDown, L"up"); + } + else + { + swprintf(szUpDown, L"down"); + } + + if (pShooter->bDoBurst == 1) + { + ScreenMsg( FONT_MCOLOR_LTRED, MSG_INTERFACE, L"%d. Shot aperture %2.1f, goes %2.1f %s and %2.1f %s", pShooter->bDoBurst, iAperture, dShotOffsetX, szLeftRight, dShotOffsetY, szUpDown ); + } + else + { + if ((pShooter->bDoBurst-1)%3 == 0) + { + ScreenMsg( FONT_MCOLOR_LTRED, MSG_INTERFACE, L"%d. Shot goes %2.1f %s and %2.1f %s", pShooter->bDoBurst, dShotOffsetX, szLeftRight, dShotOffsetY, szUpDown ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%d. Shot goes %2.1f %s and %2.1f %s", pShooter->bDoBurst, dShotOffsetX, szLeftRight, dShotOffsetY, szUpDown ); + } + } + } + + ////////////////////////////////////////////////////////////////////////////// + // STEP 8: 2D to 3D + // + // So far, we've been accumulating the adjustment of muzzle/shot angles in a very peculiar way: + // by moving the point of impact either above/below the target or to its left/right. So now, we have + // a final intended impact point, but only relative to the target. To fire the shot at the intended + // point, we need to find out its 3D location. + // This is not as complicated as it may seem. Several times during the formula, I noted that + // plotting muzzle/shot movement can be imagined as drawing a circle on top of the target, and selecting + // a point within that circle that corresponds to how much we want to move the muzzle. That imaginary + // circle lies on a plane that is 90-degree perpenticular to the angle of the "perfect" shot as we + // calculated at the very start of this function. Therefore, we can use sinus and cosinus to figure + // out the location of any point on that target. + // + // Note that for Z-Elevation (moving the muzzle up/down), we already have the value we require. We only + // need to plot the X/Y coordinates out of what was previously the X-Shot-Offset. + // + // Here we figure out the X/Y coordinates in relation to the target's center: + + FLOAT dSecondDeltaX = (FLOAT)(sin(ddOrigHorizAngle) * dShotOffsetX)*(-1); + FLOAT dSecondDeltaY = (FLOAT)(cos(ddOrigHorizAngle) * dShotOffsetX); + + // Finally, we add our deltas to the coordinates of the target's center. + *dEndX += dSecondDeltaX; + *dEndY += dSecondDeltaY; + *dEndZ = __max(-127, *dEndZ + (dShotOffsetY * 11.3f)); // Y, which represented up/down offset, is actually the Z axis in 3d game terms... + + // These values are returned to the calling function, in this case UseGun(). That function then fires the bullet + // directly at the intended coordinates. + +} + +FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, UINT8 ubAimTime ) +{ + FLOAT iFinalMagFactor = 0; + FLOAT iScopeFactor = 0; + FLOAT iProjectionFactor = 0; + + if (ubAimTime > 0) + { + iScopeFactor = GetBestScopeMagnificationFactor( pWeapon, (UINT32)d2DDistance ); + iProjectionFactor = GetProjectionFactor( pWeapon ); + + // Now calculate the optimal magnification that would be required for the target's current distance. + FLOAT iTargetMagFactor = d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE; + + if (iTargetMagFactor > iProjectionFactor) + { + // Projection items, like lasers or red dot sights, work up to their "best" range without error. + // If the target is closer than that best range, the projection factor remains the same, helping + // all shots at the target be more accurate. + // However, if the target is further away, the projection begins to lose its effectiveness, becoming + // less useful until it loses all value. + iProjectionFactor -= (iTargetMagFactor - iProjectionFactor); + iProjectionFactor = __max(iProjectionFactor, 1.0f); + } + if (iTargetMagFactor < iScopeFactor) + { + // Scopes give their best Mag Factor at a certain distance and beyond that distance. If the target is + // closer however, it's the target's distance that determines the scope's mag factor. This makes scopes + // quite less useful at ranges closer than they are intended for. + iScopeFactor = iTargetMagFactor; + } + // The final factor is the largest of the two. + iFinalMagFactor = __max(iScopeFactor, iProjectionFactor); + } + else + { + iFinalMagFactor = 1.0; + } + + return iFinalMagFactor; +} + +// HEADROCK HAM 4: This function calculates and returns the maximum shot aperture as a radius to which the muzzle of +// the gun might sway off the target center when the trigger is pulled. +FLOAT CalcBasicAperture() +{ + FLOAT iBasicAperture = 0.0; + + // Maximum aperture is the radius of a shot performed with 100% muzzle sway (a completely unstabled gun). + // It is the radius of a circle "drawn" at 1xNormal Shooting Distance, at the end of a cone starting at the + // tip ofour muzzle. + // To get this value, we get a constant read from the INI file which defines the spread angle of the cone - in + // other words, the angle between a line running down the center of the cone and a line running down its side. + // By default, the angle is 22.5 degrees. This gives a cone with a 45-degree spread, covering the entire area + // in front of the shooter. This is done to ensure that shots don't ever appear to go sideways or upwards, + // making weird visuals. + // Decreasing the value of this angle will make ALL shots tighter, so use discretion. + + // Calculate the angle in radians + DOUBLE ddMaxAngleRadians = (gGameCTHConstants.DEGREES_MAXIMUM_APERTURE * RADIANS_IN_CIRCLE) / 360; + + // Calculate the radius of the aperture circle at a distance of 1xNormal from the muzzle's end. + iBasicAperture = (FLOAT)(sin(ddMaxAngleRadians) * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + + // Return this as the Shot Aperture value to be used here on in. + return iBasicAperture; +} + +// HEADROCK HAM 4: This function causes an offset in x/y/z shooting coordinated due to under-compensation +// for target movement. +void CalcTargetMovementOffset( SOLDIERTYPE *pShooter, SOLDIERTYPE *pTarget, OBJECTTYPE *pWeapon, FLOAT *dMuzzleOffsetX, DOUBLE ddShootingAngle, INT32 iAperture ) +{ + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // HEADROCK HAM 4: New Shooting Mechanism, Target Movement + // + // The effect of Target Movement on shooting tries to mimic real-life. It does so by requiring the shooter + // to track the target as it moves. + // + // This is done by measuring the distance and angle that the target has moved since the start of its most recent + // turn. Once this is calculated, we compare this to the angle where the shot will come from, to see how much it's + // going to affect the shooter's ability to hit the target. + // + // Once we know the size of the penalty, we apply it by moving the "center point" for the attack a little behind + // the target. This means that more shots will go behind the target, less in front of it, and generally reduce + // our ability to hit that target properly. Aiming the gun well does help, but can't completely eliminate the + // penalty. + // + // In addition, skilled shooters can figure out the target's speed and heading if they have sufficient time. That + // means that after the target has moved a certain number of tiles, any FURTHER tiles it moves will actually + // give the shooter time to adjust, lowering the penalty somewhat. Skilled shooters can start to adjust very + // quickly, while unskilled ones will find the target very hard to hit unless it runs a long distance, and even then + // can't compensate very much. + + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // We start by figuring out how much distance the target has moved, and at what angle (compared to positive x). + // We do this by comparing the target's position at the start of its recent turn (sStartPos) with its current + // position. + + if (gGameCTHConstants.MOVEMENT_TRACKING_DIFFICULTY == 0) + { + // Movement tracking is defined as nonexistent, and thus doesn't take place. + return; + } + + if (pTarget->sOldXPos == 0 && pTarget->sOldYPos == 0) + { + // HEADROCK HAM 4: Hopefully the right spot for this: This soldier has no "old" coordinates, so just set them + // to wherever he/she is currently standing. + pTarget->sOldXPos = CenterX( pTarget->sGridNo ); + pTarget->sOldYPos = CenterY( pTarget->sGridNo ); + // Since movement is now nonexistent, break the formula here without adjusting coordinates. + return; + } + + // Find previous position of this soldier, recorded when his/her last turn started. + INT16 sStartPosX = pTarget->sOldXPos; + INT16 sStartPosY = pTarget->sOldYPos; + + // Find the current position of this soldier. + INT16 sCurPosX = 0; + INT16 sCurPosY = 0; + ConvertGridNoToCellXY(pTarget->sGridNo, &sCurPosX, &sCurPosY); + + // Figure out the difference between the two coordinates. + INT32 sDeltaX = sStartPosX - sCurPosX; + INT32 sDeltaY = sStartPosY - sCurPosY; + + // Pythagorian distance calculation. + INT16 sDistanceMoved = (INT16)sqrt((double) (sDeltaX * sDeltaX) + (sDeltaY * sDeltaY)); + sDistanceMoved /= CELL_X_SIZE; // convert to Tiles. + + if (sDistanceMoved == 0) + { + //Target hasn't moved. Simply abort the formula, as there will be no movement penalty anyway. + return; + } + + // Figure out the angle of movement compared to positive X axis of the tile grid. The result is in RADIANS. + DOUBLE ddMovementAngle = atan2( (DOUBLE)sDeltaY, (DOUBLE)sDeltaX ); + + /////////////////////////////////////////////////////////////////////////////////////// + // Now we need to figure out the relation between the Shooting Angle and the Movement Angle. This + // will tell us whether the target is moving perpendicular to our shot, directly at/away from us, + // or anywhere in between. + + DOUBLE ddRelativeAngle = ddMovementAngle - ddShootingAngle; + + // The penalty coefficient is a sinus of the relative angle. That means that if the shooting angle and the movement + // angle are the same or 180-degree opposite, there will be no movement penalty (0%). If the shooting angle is + // perpendicular to the movement angle (90 or 270 degrees), there will be full movement penalty (100%). + // Other relative angles fall in between, according to the sinus curve. + FLOAT iPenaltyCoeff = (FLOAT)sin(ddRelativeAngle); + + if (iPenaltyCoeff == 0.0) + { + // Parallel angle (0 or 180) gives no penalty, so stop here without adjusting coordinates. + return; + } + + // Now let's figure out how competent our shooter is. + FLOAT iCombinedSkill = gGameCTHConstants.MOVEMENT_MRK * EffectiveMarksmanship( pShooter ); + iCombinedSkill += gGameCTHConstants.MOVEMENT_WIS * EffectiveWisdom( pShooter ); + iCombinedSkill += gGameCTHConstants.MOVEMENT_DEX * EffectiveDexterity( pShooter ); + iCombinedSkill += gGameCTHConstants.MOVEMENT_EXP_LEVEL * (EffectiveExpLevel( pShooter ) * 10); + + // Average + FLOAT iDivisor = gGameCTHConstants.MOVEMENT_MRK + gGameCTHConstants.MOVEMENT_WIS + gGameCTHConstants.MOVEMENT_DEX + gGameCTHConstants.MOVEMENT_EXP_LEVEL; + iCombinedSkill /= iDivisor; + + // Limit to a 0-100 scale. + UINT32 uiCombinedSkill = (UINT32)__max(__min(iCombinedSkill,100), 0); + + // Here we define the number of tiles the target must move to give our shooter the worst possible penalty. + // Again, if the shooter is skilled, this will occur after fewer tiles have been moved. + // If the target moves *more* tiles than this, the movement penalty will begin to diminish. That's our shooter + // beginning to compensate for the target's speed, pointing the gun ahead of the target ("Leading the target"). + UINT8 uiTilesForMaxPenalty = (100-uiCombinedSkill) / (100 / gGameCTHConstants.MOVEMENT_TRACKING_DIFFICULTY); + + // Add a percentage-based modifier from the weapon and its attachments. Movement tracking devices will + // provide faster compensation for target movement, allowing the shooter to begin adjusting the muzzle + // after the target moves a smaller number of tiles. + uiTilesForMaxPenalty += (uiTilesForMaxPenalty * GetTargetTrackingModifier( pWeapon, gAnimControl[ pShooter->usAnimState ].ubEndHeight )) / 100; + + if (uiTilesForMaxPenalty == 0) + { + // Shooter is skilled enough to avoid ANY movement penalty. Return without adjusting. + return; + } + + ///////////////////////////////////////////////////////////////// + // Now we start adding up the penalty for each tile of movement: + UINT16 usNumPenaltiesAdded; + FLOAT iFinalPenalty = 0; + + // Up to a certain number of tiles, the shooter is disoriented by the target's movement, and the penalty + // increases for each tile moved. This simulates targets moving at various speeds: The more tiles a target has + // moved, the faster it is seen to be going, hence the gun's muzzle will be pointing more behind the target. + for (usNumPenaltiesAdded = 0; usNumPenaltiesAdded < __min(uiTilesForMaxPenalty,sDistanceMoved); usNumPenaltiesAdded++) + { + // Deteriorate aim by one fraction. The size of the fractions is defined in the INI file. + iFinalPenalty += gGameCTHConstants.MOVEMENT_PENALTY_PER_TILE; + } + + // By now, we've hit the end of the penalty zone. Either the target has only moved enough tiles to confuse us, + // or we're simply done being confused and can now compensate. + // If we can start compensating, each further tile of movement will in fact return some of our aim back towards + // the center of the target, indicating that the shooter is trying to "lead". + // Again, skilled shooters will reach the cutoff point earlier, which translates into receiving more of their + // penalty back as the target moves further. In the same situation, a less-experienced shooter will still be + // confused by movement, suffering from extra tiles rather than compensating. + + if (usNumPenaltiesAdded < sDistanceMoved) + { + // First let's add one step where the penalty doesn't change. The target has moved an extra + // tile beyond the cutoff range, but our shooter doesn't suffer extra penalty for that tile. + // If the target keeps moving, the shooter will then begin compensating. + usNumPenaltiesAdded ++; + + // If there's any distance left, each tile moved will actually DECREASE the penalty, thus + // moving the shooting point back towards the target. The more tiles the target moves now, + // the easier it is to hit. + for (usNumPenaltiesAdded; usNumPenaltiesAdded < sDistanceMoved; usNumPenaltiesAdded++ ) + { + // Improve aim by 1/2 the specified penalty per tile moved. Yes, the penalty diminishes SLOWER than + // it was gained. The target needs to move 3x as much as the uiTileForMaxPenaltyValue for our shooter + // to actually compensate for the entire penalty. If it has moved only 2x the required amount, + // our shooter has only compensated for HALF the penalty. + iFinalPenalty -= (gGameCTHConstants.MOVEMENT_PENALTY_PER_TILE / 2); + + // Given enough time, the shooter can completely compensate for movement. + } + } + + // Now we have a Final Penalty value. This is the distance our muzzle is trailing behind the + // target. + + // Let's make sure that the penalty isn't negative. We don't want to over-compensate. That wouldn't be nice. + iFinalPenalty = __max(0, iFinalPenalty); + + // Now we need to figure out exactly how much our muzzle has moved in actual distance points. We do this + // by applying it as a percentage to the size of our Shot Aperture. Since Shot Aperture is an indicator of + // how well our gun is aimed, this means that better-aimed shots will "trail" less than poorly-aimed shots. + // In other words, aiming will effectively reduce the size of the penalty, making it easier to hit the target + // despite its movement. Note that with an appropriately-sized movement penalty, and an inexperienced shooter, + // it's quite possible that even a very-well-aimed shot will stand no chance to hit the target if it is + // moving fast enough. + iFinalPenalty = ((iFinalPenalty * iAperture)/100); + + // Next, we apply the Penalty Coefficient calculated earlier based on direction of movement. Again, if the + // target is moving perpendicular to the angle of the shot, the shooter receives the maximum (100%) size of the + // penalty. Sharper angles provide less. + // Also note that thanks to the use of a sinus in calculating the coefficient, we are also now telling the + // formula whether the shot should lag to the left or the right. A positive coefficient means the shot will head + // right of the target. A negative coefficient will make the shot deviate left of the target. + iFinalPenalty *= iPenaltyCoeff; + + // We now have our final movement penalty value, which represents the distance our muzzle is lagging behind the + // target. We apply this directly to the lateral offset of our muzzle: + *dMuzzleOffsetX += iFinalPenalty; + +} + +void CalcRangeCompensationOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetY, INT32 iRangeToTarget, OBJECTTYPE *pWeapon ) +{ + //////////////////////////////////////////////////////////////////////////////////////// + // + // HEADROCK HAM 4: New Shooting Mechanism, Bullet Drop Compensation + // + // Different guns have different ranges. In the real world, a gun is usually measured by its "effective" range, + // the range at which it can reliably put shots on a man-sized target. However, guns also have a certain + // "maximum" range, the range at which the bullet loses enough velocity to begin tumbling, lose aerodynamic + // stability, and as a result come crashing into the ground. The initial speed of the bullet, its shape and size, + // and how fast it is spinning along its axis will all determine how far it can go before this happens. + // + // The JA2 Bullet Mechanism already simulates this effect, by decreasing a bullet's vertical angle repeatedly + // once it crosses its "maximum range" (as defined by the weapon's Range property). The bullet falls to the + // ground with increasing rapidity, until it collides with the ground. + // + // NCTH uses this principle in reverse - allowing shooters to compensate for this effect and thereby increase + // the range of their guns artificially. They do this by raising the muzzle of the gun upwards, effectively + // aiming *above* the target. This gives the bullet higher vertical velocity, and as a result prolongs the amount + // of time it can fall once it reaches Maximum Range, before colliding with the ground. A shot placed properly + // this way will arch upwards and then fall directly at the target despite being outside maximum range. + // + // In effect, this can only add a small fraction to the gun's maximum range, but in some cases can be crucial. + // However, it is a remarkable feat to be able to guess the correct angle for compensation, and only the most + // skilled shooters can do this reliably (hitting the target with reasonable frequency). Attachments can also + // provide bonuses for doing exactly this sort of thing. + + UINT16 usGunRange = GunRange( pWeapon, pShooter ); + if (usGunRange == 0) + { + // Avoid division by 0. + return; + } + if (usGunRange >= iRangeToTarget) + { + return; + } + + // To begin, we calculate something called a Gravity Constant. Once a bullet reaches its maximum flight distance, + // it will lose exactly this much vertical movement for every step. In reality, this would be related to the + // speed the bullet is traveling in, but since bullet speed is not actually simulated by JA2, we instead use the + // gun's Range as a measure for how fast the bullet is. After all, guns with longer range almost invariably fire + // faster bullets. + FLOAT dGravity = (FLOAT)(100.0 / (usGunRange * gGameCTHConstants.GRAVITY_COEFFICIENT)); + + // We now take the Range to Target and the Maximum Range for the bullet, and find the distance between them. + // This is how much distance the bullet has to cover while dropping out of the sky. In other words, we need to + // make the bullet fly this much longer than it would normally have. + INT32 iRangeDiff = (iRangeToTarget-usGunRange) / 10; + + // To know how much we need to raise our muzzle, what we do is calculate how far below the target the bullet would + // hit, assuming no muzzle adjustment, and pretending there's no ground to collide with. The result is equal to + // exactly the amount of extra upwards angle we need to add to the muzzle to make the bullet hit the target! + FLOAT dOptimalAddY = iRangeDiff * (iRangeDiff+1) * (dGravity/2); + if ( pShooter->pathing.bLevel && pShooter->bTargetLevel == 0 ) + { + dOptimalAddY -= 25.6f; + if (dOptimalAddY < 0) + { + return; + } + } + + // The next step is to figure out how skilled our shooter is. Correctly compensating for gravity is not a simple + // matter, and a skilled shooter will have a far greater chance of guessing the extra muzzle angle required. + FLOAT iCombinedSkill = gGameCTHConstants.MOVEMENT_MRK * EffectiveMarksmanship( pShooter ); + iCombinedSkill += gGameCTHConstants.MOVEMENT_WIS * EffectiveWisdom( pShooter ); + iCombinedSkill += gGameCTHConstants.MOVEMENT_DEX * EffectiveDexterity( pShooter ); + iCombinedSkill += gGameCTHConstants.MOVEMENT_EXP_LEVEL * (EffectiveExpLevel( pShooter ) * 10); + + // Average + FLOAT iDivisor = gGameCTHConstants.MOVEMENT_MRK + gGameCTHConstants.MOVEMENT_WIS + gGameCTHConstants.MOVEMENT_DEX + gGameCTHConstants.MOVEMENT_EXP_LEVEL; + iCombinedSkill /= iDivisor; + + // The weapon and/or its attachments can increase our skill by a certain percentage. Windage sights on long-range + // weapons (like sniper rifles and launchers) are sometimes designed specifically for this purpose. + iCombinedSkill += (iCombinedSkill * GetDropCompensationModifier( pWeapon, gAnimControl[ pShooter->usAnimState ].ubEndHeight )) / 100; + + // Limit this to a scale of 0-100. + UINT32 uiCombinedSkill = (UINT32)__max(__min(iCombinedSkill,100), 0); + + // Invert the value. Now 100=worst, 0=best. + uiCombinedSkill = 100-uiCombinedSkill; + + // Now, let's randomly decide how far "off" our shooter is from the perfect angle: + + // Randomize a number within the combined skill limit. + FLOAT iRandom = (FLOAT)(PreRandom(uiCombinedSkill) / 100.0); + + // Randomly decide whether we're overcompensating (aiming too high) or undercompensating (aiming too low). + INT8 uiUpDown = PreRandom(2)?(1):(-1); + + // We add the randomal deviation to the perfect angle thusly: + dOptimalAddY += (iRandom * dOptimalAddY * uiUpDown); + + // Finally, we add this to our current Vertical Muzzle Offset value. In essence, we are now aiming at a point + // a certain distance directly above the target. + *dMuzzleOffsetY += dOptimalAddY; + +} + + +void CalcMuzzleSway( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, FLOAT iAperture ) +{ + ///////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: New Shooting Mechanism, Muzzle Sway + // + // In the new system, our "CTH" is replaced with a value called "Muzzle Sway". It represents + // a randomal sway of our gun's muzzle as we pull the trigger. The better our aim, the less our + // muzzle might sway from the target's center when we take the shot. + // + // To determine how far a shot can go from the center, we have the Shot Aperture value, calculated earlier + // in the calling function and fed to us here. Imagine it as a circle drawn around the target, with a specific + // radius, within which our muzzle may point anywhere. + // This only tells us how far our muzzle MIGHT deviate from the center. How much it actually deviates is + // completely randomal, allowing perfect (0 deviation) shots to occur even if the Shot Aperture circle is + // gigantic. Of course, the smaller the Aperture, the more likely we are to deviate only a small distance (or none). + + // Start by randomizing the general distance of the muzzle point from the center of the target. + FLOAT RandomMuzzleSway = (FLOAT)((FLOAT)(PreRandom( (UINT32)(iAperture * 100) )) / 100.0); + + // Using this value, we randomly determine how much of the distance is lateral movement (to the left or right + // of the target center), and how much is vertical movement (above or below). + FLOAT dDeltaX = (FLOAT)((FLOAT)(PreRandom( (UINT32)(RandomMuzzleSway * 100)) ) / 100.0); + // Reverse pythagorean formula is used to calculate Y axis deviation (above/below) + FLOAT dDeltaY = sqrt((RandomMuzzleSway*RandomMuzzleSway)-(dDeltaX*dDeltaX)); + + // Randomly decide between up or down, and left or right. + INT8 bLeftRight = PreRandom(2)?(1):(-1); + INT8 bUpDown = PreRandom(2)?(1):(-1); + + // The new Vertical Bias constant turns circular deviation into an ellipse. This can be used to reduce the distance + // of up/down deviation. To balance things out, lateral (left/right) deviation is increased by the same proportion. + // Vertical bias is applied based on stance. You get a flatter ellipse when prone, and no ellipse (a circle) when standing. + FLOAT dVerticalBias = gGameCTHConstants.VERTICAL_BIAS; + switch (gAnimControl[ pShooter->usAnimState ].ubEndHeight) + { + case ANIM_STAND: + dVerticalBias = 1.0; + break; + case ANIM_PRONE: + // No change - full bias. + break; + case ANIM_CROUCH: + dVerticalBias = 1.0f + ((dVerticalBias - 1.0f) * 0.66f); + break; + } + + // Now that we have the distance on both axes, we can apply it to the Muzzle Offset value which we were fed + // from the calling function. + + *dMuzzleOffsetX += (dDeltaX * bLeftRight); + *dMuzzleOffsetY += (dDeltaY * bUpDown) * dVerticalBias; +} + +void CalcBulletDeviation( SOLDIERTYPE *pShooter, FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange ) +{ + ////////////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: New Shooting Mechanism, Bullet Deviation + // + // The new shooting system separates CTH into two parts - one where the shooter tries to perfect his aim + // using extra aiming and a scope, and relying heavily on skills and shooter's condition. This determines + // how far off the target the muzzle of the gun might point when the trigger is pulled. + // + // The second part, which is calculated here, is a second, marginal deviation caused by the gun itself. + // In other words, the gun's accuracy determines how far the bullet might fly off the point at which + // it was fired. + // + // This Bullet Deviation is largely static - it depends only on the type of gun we're using, its + // condition, and possibly the type of ammo or attachments we're using. For the most part, there's nothing + // the player can do to reduce bullet deviation, so it acts as a sort of uncontrollable extra element + // in shot randomness. In other words, unless you switch to a different gun, you're stuck with some random + // factor. + // + // Longer rifles have higher accuracy, and therefore will put the bullet closer to where it was aimed. + // Shorter pistols and SMGs will cause a relatively large deviation of the bullet, making it harder to + // properly hit the target at a distance, even when properly aiming the gun. + // + // Attachments or ammo that increase/decrease the gun's accuracy value will have a direct effect here. + // Guns with bad condition will also tend to send bullets in unwanted directions. Other than this, + // there's very little the player can do at all about it. + + // We start by reading the gun's Accuracy value. We'll use that as the basis for everything else. + + INT16 sAccuracy = GetGunAccuracy( pWeapon ); + + // This value can be anywhere between 0 and 100. Let's make sure. + sAccuracy = __max(0, sAccuracy); + sAccuracy = __min(100, sAccuracy); + + // Now we figure out a radius for our deviation circle. Similar to Muzzle Sway, shots will be + // able to go anywhere within the circle drawn by this radius. The maximum possible radius + // is defined by an INI setting. We then take the inverted accuracy value and use that as a + // percentage to increase or decrease the radius. A gun with accuracy 0 will produce a fully-sized + // deviation circle (100% radius), while a gun with accuracy 100 produces a minimal sized + // circle (actually, a dot with 0% radius). + FLOAT iBulletDev = (gGameCTHConstants.MAX_BULLET_DEV * (100-sAccuracy)) / 100; + + // If the radius is 0, this gun's bullets are flawless, and will never deviate from where + // they were fired. + if (iBulletDev == 0) + { + return; + } + + // So now, iBulletDev is a maximum deviation for any bullet coming out of this weapon. + // Next we randomly determine how far away this bullet will fly. + FLOAT RandomDev = (FLOAT)((FLOAT)(PreRandom( (UINT32)(iBulletDev * 100) )) / 100.0); + + // Now let's figure out where this puts the Muzzle Point, in relation to the Target Center. + // We do this by randomly selecting a left/right deviation, then using the remainder as + // up/down deviation. + FLOAT dDeltaX = (FLOAT)((FLOAT)(PreRandom( (UINT32)(RandomDev * 100)) ) / 100.0); + FLOAT dDeltaY = sqrt((RandomDev*RandomDev)-(dDeltaX*dDeltaX)); + + // Over increasing range, a bullet fired with the same deviation should actually end up + // further away from the target than if the target was closer. We use the constant + // "Normal Shooting Distance" to determine a "normal" range at which deviation is not multiplied + // or divided. At twice that range, bullets will end up twice further from the center of the target. + // At half this range, they'll end up half as far from the center of the target. + FLOAT iDistanceRatio = (FLOAT)((FLOAT)uiRange / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + dDeltaX *= iDistanceRatio; + dDeltaY *= iDistanceRatio; + + // Randomly determine whether the bullet goes up or down, and left or right. + INT8 bLeftRight = PreRandom(2)?(1):(-1); + INT8 bUpDown = PreRandom(2)?(1):(-1); + + // Finally, adjust the center point of our shot to correspond with the deviation. + *dShotOffsetX += dDeltaX * bLeftRight; + *dShotOffsetY += dDeltaY * bUpDown; + +} + +void LimitImpactPointToMaxAperture( FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, FLOAT dDistanceAperture ) +{ + //////////////////////////////////////////////////////////////////////////////////////////// + // + // HEADROCK HAM 4: New Shooting Mechanism, Angle Limits + // + // The new Shooting Mechanism works primarily by (virtually) never firing the bullet directly at the target's + // center. It does so by moving the "target point" for the bullet a certain distance from the target's + // center, as dictated by the functions preceding this one in the formula. However, this has the potential + // of making particularly-bad shots go off in very awkward directions, such as sideways or upwards, given + // that the center point can be adjusted considerably. + // + // To make sure this doesn't happen, this function limits all shots so that they never have neither a horizontal + // nor vertical angle greater than X (defined by the INI file). By default, this angle is 22.5 - the maximum + // possible angle to avoid a bullet flying outside the 45-degree cone in front of the shooter. + // + // If this INI-defined angle is decreased, it will proportionally make all shots more accurate, so take that + // under advisement. If that occurs, this formula will also make sure to keep shots within that smaller cone. + // + // Thankfully, by this point we already have the value called "Shot Aperture" calculated. This is the MAXIMUM + // possible deviation of any shot at Normal Distance. We just need to make sure that our current shot doesn't + // have a greater deviation than this. + + FLOAT dReductionRatio = 1.0; + + // Calculate how far from the target center will our shot impact. This is done by simple pythagorean formula. + FLOAT dTotalShotOffset = sqrt((*dShotOffsetX * *dShotOffsetX)+(*dShotOffsetY * *dShotOffsetY)); + + // If our shot deviates more than the aperture allows, at the target's distance... + if (dTotalShotOffset > dDistanceAperture ) + { + // Find out the ratio between the deviation and the limit. + dReductionRatio = dDistanceAperture / dTotalShotOffset; + + // Multiply both offsets by this ratio. This will effectively move them back into the aperture radius + // without altering the ratio between vertical and horizontal offsets. + *dShotOffsetX *= dReductionRatio; + *dShotOffsetY *= dReductionRatio; + } +} + +void CalcPreRecoilOffset( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, UINT32 uiRange ) +{ + ////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: New Shooting Mechanism, Pre-Recoil Calculation + // + // The new recoil system works on the premise that each gun has its own recoil force + // and direction. After X shots with enough recoil, the muzzle of the gun will be pointing + // a certain distance off the center of the target. After a few bullets have been fired, + // mercs get a chance to begin applying counter-force to act against recoil, and given + // enough bullets might even be able to push their gun back towards the target's center. + // However, by this point several bullets will have been wasted, and the muzzle may already + // be pointing very far from the target's center. + // + // To compensate for this, experienced characters can anticipate the recoil of their gun + // before it even starts firing. Instead of aiming the first shot at the center of the + // target, these characters will aim it at a location which would, once recoil kicks in, + // rake the gun over the target. This minimizes the distance by which the last shot will + // be offset from the target's center, making it easier to return the muzzle towards the + // center once the character gets the chance to start applying Counter-Force. + // + // To visualize this, imagine a gun like an AK-47, which pulls very strongly upwards. + // Experienced soldiers know that if they aim at a target's legs, the first bullets will + // then "rake" upwards, hitting the target in the legs, abdomen, torso, and possibly the + // head. By this point, if they continue autofiring, they'll be able to get control + // of the gun and keep it pointed at least close to the torso. If their volley had started + // while pointed at the torso, they'd be firing above the target by now... + + // Calculating Pre-Recoil Offset is fairly simple. We begin by determining the chance of + // this soldier to actually consider using pre-recoil offset at all. This depends entirely + // on wisdom and experience. + + INT8 traitLoop; + FLOAT iCombinedSkill = gGameCTHConstants.PRE_RECOIL_WIS * EffectiveWisdom(pShooter); + iCombinedSkill += gGameCTHConstants.PRE_RECOIL_EXP_LEVEL * EffectiveExpLevel(pShooter) * 10; + + // Average + FLOAT iDivisor = gGameCTHConstants.PRE_RECOIL_WIS + + gGameCTHConstants.PRE_RECOIL_EXP_LEVEL; + iCombinedSkill /= iDivisor; + + // AUTO-WEAPONS skill is used to bridge the gap between Combined Skill and 100%. Each level of the skill + // adds a fraction of the distance, as defined by the INI file. + if(gGameOptions.fNewTraitSystem) + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPONS_NT ); + else + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPS_OT ); + for (INT32 x = 0; x < traitLoop; x++) + { + INT8 bDifference = (INT8)(100-iCombinedSkill); + bDifference = (INT8)(bDifference / gGameCTHConstants.PRE_RECOIL_AUTO_WEAPONS_SKILL); + iCombinedSkill += bDifference; + } + + // Limit to a 0-100 scale, just in case. + UINT32 uiPreRecoilAbility = (UINT32)__min(100, __max(iCombinedSkill, 0)); + + // Randomly determine whether the soldier has compensated for recoil this time. + if (PreRandom(100) >= uiPreRecoilAbility) + { + // Soldier has forfeited his chance. Make no adjustments. + return; + } + + // Now that we've determined that this shooter will in fact compensate for recoil, we want to know + // how much to compensate by. We start by figuring out how many bullets will leave the gun before the + // shooter gets his chance to begin applying counter-force. He'll need to pre-compensate for this + // many bullets. + + FLOAT iCounterForceFrequency = gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AGI * EffectiveAgility(pShooter); + iCounterForceFrequency += gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_EXP_LEVEL * EffectiveExpLevel(pShooter) * 10; + + // Average + iDivisor = gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AGI + + gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_EXP_LEVEL; + iCounterForceFrequency /= iDivisor; + +//CHRISL: TODO: STOMP need to include AUTO_WEAPS_OT here as well. + // Bridge the gap to 100 with the help of the AUTO-WEAPONS skill + if(gGameOptions.fNewTraitSystem) + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPONS_NT ); + else + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPS_OT ); + for (INT32 x = 0; x < traitLoop; x++) + { + INT8 bDifference = (INT8)(100-iCounterForceFrequency); + bDifference = (INT8)(bDifference / gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AUTO_WEAPONS_DIVISOR); + iCounterForceFrequency += bDifference; + } + + // Percent Modifier from weapon and its attachments + iCounterForceFrequency += (iCounterForceFrequency * GetCounterForceFrequencyModifier( pWeapon, gAnimControl[ pShooter->usAnimState ].ubEndHeight )) / 100; + + // Limit to 0-100. + iCounterForceFrequency = __min(100, iCounterForceFrequency); + iCounterForceFrequency = __max(0, iCounterForceFrequency); + + // Invert value. Now 100 is bad, 0 is good. + iCounterForceFrequency = 100 - iCounterForceFrequency; + + // Calculate frequency + UINT32 uiBulletsPer5AP = GetAutofireShotsPerFiveAPs( pWeapon ); + UINT32 uiCounterForceFrequency = __max(1, (UINT32)(iCounterForceFrequency * uiBulletsPer5AP) / 100); + + // Also, it might be possible that we don't intend to fire that many bullets at all. So we want to figure out + // how many bullets are about to be fired, and adjust accordingly. + UINT32 uiIntendedBullets; + if ( pShooter->bDoAutofire > 0 ) + { + // Autofire. The number of bullets to be fired equals to the value of bDoAutofire + uiIntendedBullets = pShooter->bDoAutofire; + } + else + { + // Burst. Get the number of shots-per-burst from the weapon. + uiIntendedBullets = Weapon[ pWeapon->usItem ].ubShotsPerBurst + GetBurstSizeBonus(pWeapon); + } + + // Which one's smaller? + uiIntendedBullets = __min( uiIntendedBullets, uiCounterForceFrequency ); + + // Now, let's figure out how much recoil this gun will put out during those first X bullets. + INT8 bGunRecoilX; + INT8 bGunRecoilY; + INT32 iTotalGunRecoilX = 0; + INT32 iTotalGunRecoilY = 0; + + // For each bullet, add up its recoil. + for (UINT32 count=1; count <= uiIntendedBullets; count++) + { + GetRecoil( pWeapon, &bGunRecoilX, &bGunRecoilY, count ); + iTotalGunRecoilX += bGunRecoilX; + iTotalGunRecoilY += bGunRecoilY; + } + + if (iTotalGunRecoilX == 0 && iTotalGunRecoilY == 0) + { + // The weapon produces no recoil within these few shots. Either it has no recoil at all, or is designed + // to produce no recoil during the first shots. There's no need to compensate for pre-recoil. + return; + } + + // Next up, let's find out whether our shooter will correctly compensate for both X and Y recoil. + // Invert RecoilAbility value. 0=best, 100=worst. + uiPreRecoilAbility = (100-uiPreRecoilAbility); + + // Randomly decide how much compensation is performed + FLOAT dPreRecoilX = (FLOAT)(PreRandom(uiPreRecoilAbility)/100.0f) * iTotalGunRecoilX; + FLOAT dPreRecoilY = (FLOAT)(PreRandom(uiPreRecoilAbility)/100.0f) * iTotalGunRecoilY; + + // Decide over/under compensation randomly + INT8 bUpDown = PreRandom(2)?(1):(-1); + INT8 bLeftRight = PreRandom(2)?(1):(-1); + + // Apply random factor + dPreRecoilX = (iTotalGunRecoilX * -1) + (dPreRecoilX * bLeftRight); + dPreRecoilY = (iTotalGunRecoilY * -1) + (dPreRecoilY * bUpDown); + + // Apply distance ratio. The further away we are, the more compensation we need. + FLOAT dDistanceRatio = (FLOAT)(uiRange / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + dPreRecoilX *= dDistanceRatio; + dPreRecoilY *= dDistanceRatio; + + // Finally, adjust our muzzle direction. + *dMuzzleOffsetX += dPreRecoilX; + *dMuzzleOffsetY += dPreRecoilY; + +} + +// Calculate Recoil Offset +void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange ) +{ + ////////////////////////////////////////////////////////////////////////////////////// + // Recoil Calculation + // + // Where the old CTH system used recoil as a flat penalty to CTH after each bullet, the new system + // handles things completely differently. It actually gives each bullet an extra deviation in a specific + // direction away from the center of the target, which is based entirely on the parameters of the gun itself. + // Various guns can "pull" in different directions and with different force, all defined in the XML entries. + // Ammo and Attachments, such as bipods, can reduce this offset. + // + // In addition, the shooter's skills allow him or her to compensate for the recoil by pulling the gun back + // towards the target. This is done by applying a certain amount of counter-force. The shooter has to guesstimate + // the amount of force that will be required to put the muzzle back on the target, and is limited in how much + // counter force he/she can apply per bullet. Better shooters will be able to compensate correctly, while bad + // shooters might be overwhelmed and start firing towards the sky. + + // Get X/Y recoil parameters from the gun. + INT8 traitLoop; + INT8 bGunRecoilX; + INT8 bGunRecoilY; + + GetRecoil( pWeapon, &bGunRecoilX, &bGunRecoilY, pShooter->bDoBurst ); + + FLOAT iGunTotalRecoil = sqrt((FLOAT)(bGunRecoilX*bGunRecoilX) + (FLOAT)(bGunRecoilY*bGunRecoilY)); + + FLOAT iDistanceRatio = (FLOAT)((FLOAT)uiRange / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + + // These variables will hold the amount of X/Y force our shooter exerts to try to fight recoil. + FLOAT iAppliedCounterForceX; + FLOAT iAppliedCounterForceY; + + + ////////////////////////////////////////////////////////////////////////////////////// + // Counter-Force Frequency + // + // Counter force applied is recorded into the character's data. The same amount of force is applied to + // a few consecutive bullets, and then the shooter gets the chance to alter their counter force. + // Skilled shooters get this chance more often. + // Tracer fire also helps. Once a tracer bullet is fired, we get one free chance to alter our counter-force. + + FLOAT iCounterForceFrequency = gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AGI * EffectiveAgility(pShooter); + iCounterForceFrequency += gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_EXP_LEVEL * EffectiveExpLevel(pShooter) * 10; + + FLOAT iDivisor = gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AGI + + gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_EXP_LEVEL; + iCounterForceFrequency /= iDivisor; + +//CHRISL: TODO: STOMP need to include AUTO_WEAPS_OT here as well. + if(gGameOptions.fNewTraitSystem) + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPONS_NT ); + else + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPS_OT ); + for (INT32 x = 0; x < traitLoop; x++) + { + INT8 bDifference = (INT8)(100-iCounterForceFrequency); + bDifference = (INT8)(bDifference / gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_AUTO_WEAPONS_DIVISOR); + iCounterForceFrequency += bDifference; + } + + UINT32 uiBulletsPer5AP = GetAutofireShotsPerFiveAPs( pWeapon ); + UINT32 uiCounterForceFrequency = (UINT32)((iCounterForceFrequency * uiBulletsPer5AP) / 100); + + // Flat Modifier from weapon and its attachments + uiCounterForceFrequency = __max(1, uiCounterForceFrequency + ((uiCounterForceFrequency * GetCounterForceFrequencyModifier( pWeapon, gAnimControl[ pShooter->usAnimState ].ubEndHeight )) / 100)); + + BOOLEAN fAdjustmentAllowed = FALSE; + if ((pShooter->bDoBurst-1)%uiCounterForceFrequency == 0) + { + fAdjustmentAllowed = TRUE; + } + + BOOLEAN fTracer = WasPrevBulletATracer( pShooter, pWeapon ); + + if (!fAdjustmentAllowed && !fTracer) + { + // Not time for a force adjustment. Shooter will use the same amount of force he previously used. + iAppliedCounterForceX = pShooter->dPrevCounterForceX; + iAppliedCounterForceY = pShooter->dPrevCounterForceY; + } + else + { + /////////////////////////////////////////////////////////////////////////////////// + // STEP 2: + // + // Our shooter got the chance to change the amount of force he's using to counter recoil. + + // The "Next Offset" here signifies how far off the center of the target our next bullet will be, in X/Y terms. + // The optimal of course would be if both are equal to 0, meaning the shot will be directed towards the center. + // However, it's up to the shooter to make sure that happens, by applying counter-force. + // Our shooter wants to apply just as much counter-force as necessary to keep the next offset as close to 0 on both + // axes. + + // Add the two together to figure out where the next bullet is going to fly in relation to the target. + FLOAT dNextOffsetX = (FLOAT)(*dMuzzleOffsetX + ((bGunRecoilX * iDistanceRatio) * uiCounterForceFrequency) ); + FLOAT dNextOffsetY = (FLOAT)(*dMuzzleOffsetY + ((bGunRecoilY * iDistanceRatio) * uiCounterForceFrequency) ); + + //////////////////////////////////////////////////////////////////////////// + // Calculating recoil counter-force. + // + // The shooter needs to apply a specific amount of force in order to counter-act recoil, not just for this + // bullet, but for all others that came before. + // + // To do this, the shooter needs skills. One set of skills allows the shooter to exert more counter-force. A + // shooter with insufficient strength will be unable to counter-act the recoil from a powerful gun. A shooter + // with high strength can potentially hold the gun steady even while its firing. + // + // However, the shooter also needs a second set of skills to help him predict exactly how much force is required + // between every bullet, and the ability to actually exert the exact amount of force required. Exerting too little + // force leads to under-compensation: The shooter will need to exert even MORE force for the next bullet! Exerting + // too MUCH force is also a potential problem, as the gun may miss the target on the OTHER side. Of course, + // it's generally better to exert too much force than too little, assuming you don't repeatedly over-compensate, + // in which case you'll be shooting at the ground. + + // STEP 1: determining how much counter-force the shooter can apply if necessary. This is the absolute + // maximum counter-force that can be applied. By default, it is based primarily on the strength of the shooter, + // although agility is also helpful. + + FLOAT iCounterForceMax = gGameCTHConstants.RECOIL_MAX_COUNTER_STR * EffectiveStrength(pShooter); + iCounterForceMax += gGameCTHConstants.RECOIL_MAX_COUNTER_AGI * EffectiveAgility(pShooter); + iCounterForceMax += gGameCTHConstants.RECOIL_MAX_COUNTER_EXP_LEVEL * EffectiveExpLevel(pShooter) * 10; + + iDivisor = gGameCTHConstants.RECOIL_MAX_COUNTER_STR + + gGameCTHConstants.RECOIL_MAX_COUNTER_AGI + + gGameCTHConstants.RECOIL_MAX_COUNTER_EXP_LEVEL; + iCounterForceMax /= iDivisor; + + // Add the effects from the weapon and its attachments (foregrip, for instance). This is applied as a percentage. + INT32 iModifier = GetCounterForceMaxModifier( pWeapon, gAnimControl[ pShooter->usAnimState ].ubHeight ); + iCounterForceMax += (iCounterForceMax * iModifier) / 100; + + // Limit to 0-100. + iCounterForceMax = __max(__min(iCounterForceMax, 100), 0); + + // Use the result as a percentage of the maximum possible applicable force, as defined in the INI. + iCounterForceMax = (FLOAT)((iCounterForceMax * gGameCTHConstants.RECOIL_MAX_COUNTER_FORCE) / 100); + + // iCounterForceMax is now the absolute limit. + + // STEP 2: Now let's determine how much counter-force would be ideal. If the gun isn't kicking too powerfully, + // and/or not too much recoil has built up from previous bullets, the shooter should potentially be able to compensate + // for ALL of it. However, in some cases, the shooter simply can't exert enough force to counter ALL recoil. + + // Calculate Ideal X and limit to max force + FLOAT iIdealCounterForceX = 0.0; + iIdealCounterForceX = __min( iCounterForceMax, abs((dNextOffsetX / iDistanceRatio) / uiCounterForceFrequency )); + + // Calculate Ideal Y and limit to max force + FLOAT iIdealCounterForceY = 0.0; + iIdealCounterForceY = __min( iCounterForceMax, abs((dNextOffsetY / iDistanceRatio) / uiCounterForceFrequency )); + + // STEP 3: Now we need to determine how accurate the shooter is when applying counter-force. He won't always apply + // as much as necessary, and may sometimes apply too much. The ability to apply exactly (or close to exactly) the + // amount of force required is based on various skills, especially agility and dexterity. Wisdom and experience also + // help, and the AUTO_WEAPONS skill is invaluable. In addition, tracers (when actually fired) will boost the + // ability to compensate correctly by a certain amount. + + FLOAT iCounterForceAccuracy = gGameCTHConstants.RECOIL_COUNTER_ACCURACY_DEX * EffectiveDexterity(pShooter); + iCounterForceAccuracy += gGameCTHConstants.RECOIL_COUNTER_ACCURACY_WIS * EffectiveWisdom(pShooter); + iCounterForceAccuracy += gGameCTHConstants.RECOIL_COUNTER_ACCURACY_AGI * EffectiveAgility(pShooter); + iCounterForceAccuracy += gGameCTHConstants.RECOIL_COUNTER_ACCURACY_EXP_LEVEL * EffectiveExpLevel(pShooter) * 10; + + iDivisor = gGameCTHConstants.RECOIL_COUNTER_ACCURACY_DEX + + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_WIS + + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_AGI + + gGameCTHConstants.RECOIL_COUNTER_ACCURACY_EXP_LEVEL; + iCounterForceAccuracy /= iDivisor; + + // Add the effects from the weapon and its attachments. A foregrip or bipod are very useful for this. + // Attachment bonuses are applied as a percentage to the accuracy of the shooter. + iModifier = GetCounterForceAccuracyModifier( pWeapon, gAnimControl[ pShooter->usAnimState ].ubHeight ); + UINT32 uiCounterForceAccuracy = (UINT32)(iCounterForceAccuracy + ((iCounterForceAccuracy * iModifier) / 100)); + + // Now add the effect of the AutoWeapons skill. It "bridges" a portion of the gap between shooter's actual accuracy + // and 100% accuracy. For instance, if the divisor is set to 2 in the INI, the first skill level will close 50% of + // the gap, the second skill level closes another 25%. + if(gGameOptions.fNewTraitSystem) + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPONS_NT ); + else + traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPS_OT ); + for (INT32 x = 0; x < traitLoop; x++) + { + INT8 bDifference = 100-uiCounterForceAccuracy; + bDifference = (INT8)(bDifference / gGameCTHConstants.RECOIL_COUNTER_ACCURACY_AUTO_WEAPONS_DIVISOR); + uiCounterForceAccuracy += bDifference; + } + + //////////////////////////////////////////////////////////////////// + // Sight-range effects + // If we can't see the target, but buddies can see it, CF-Accuracy drops by 50% + // If we can't see the target and neither can buddies, CF-Accuracy drops by 75% + + UINT8 ubTargetID = WhoIsThere2( pShooter->sTargetGridNo, pShooter->bTargetLevel ); // Target ubID + INT32 iSightRange = -1; + if (ubTargetID != NOBODY) + { + iSightRange = SoldierToSoldierLineOfSightTest( pShooter, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pShooter->bAimShotLocation, false ); + if (pShooter->aiData.bOppList[ubTargetID] != SEEN_CURRENTLY && gbPublicOpplist[pShooter->bTeam][ubTargetID] == SEEN_CURRENTLY) + { + iSightRange /= 2; + } + else if(pShooter->aiData.bOppList[ubTargetID] != SEEN_CURRENTLY && gbPublicOpplist[pShooter->bTeam][ubTargetID] != SEEN_CURRENTLY) + { + iSightRange /= 4; + } + } + if (iSightRange == -1) // didn't do a bodypart-based test + { + iSightRange = SoldierTo3DLocationLineOfSightTest( pShooter, pShooter->sTargetGridNo, pShooter->bTargetLevel, pShooter->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT, false ); + iSightRange /= 4; + } + uiCounterForceAccuracy = (UINT32)(uiCounterForceAccuracy * (FLOAT)((FLOAT)iSightRange / uiRange)); + + // Was last bullet a tracer? + if (fTracer) + { + // Augment by a certain amount, mitigated by range + uiCounterForceAccuracy += (UINT32)gGameCTHConstants.RECOIL_COUNTER_ACCURACY_TRACER_BONUS; + } + + // Limit to 0 to 100. + uiCounterForceAccuracy = __max(__min(uiCounterForceAccuracy, 100), 0); + + // Invert. 0=good, 100-bad. + uiCounterForceAccuracy = 100-uiCounterForceAccuracy; + + // STEP 4: Find out whether the shooter is over-compensating or under-compensating, and by how much. Higher + // force-accuracy will decrease this deviation, generating a resulting counter-force that's closer to the ideal. + + ////////////////////////// + // CALCULATE FOR X + + // Randomize a deviation value. + INT32 uiCounterForceDeviationX = PreRandom(uiCounterForceAccuracy); + // Use as a percentage to the ideal counter force. + FLOAT iCounterForceDeviationX = (FLOAT)((uiCounterForceDeviationX * iIdealCounterForceX) / 100.0); + // Make sure there's always a little randomness - no one is THAT accurate unless the gun is producing really minimal + // amounts of recoil (or none). + iCounterForceDeviationX = __max(iCounterForceDeviationX, iGunTotalRecoil * gGameCTHConstants.RECOIL_COUNTER_ACCURACY_MIN_ERROR); + + // Determine whether we're under- or over-compensating. + INT8 bUpDownX = PreRandom(2)?(1):(-1); + iCounterForceDeviationX *= bUpDownX; + + // So now we have the ideal amount, and the randomal deviation from that amount. Let's add them up. + iAppliedCounterForceX = iIdealCounterForceX + iCounterForceDeviationX; + + // Limit to the maximum applied force. Our shooter cannot exert more force than his personal maximum. + iAppliedCounterForceX = __min(iAppliedCounterForceX, iCounterForceMax); + + ////////////////////////// + // CALCULATE FOR Y + + // Randomize a deviation value. + INT32 uiCounterForceDeviationY = PreRandom(uiCounterForceAccuracy); + // Use as a percentage to the ideal counter force. + FLOAT iCounterForceDeviationY = (FLOAT)((uiCounterForceDeviationY * iIdealCounterForceY) / 100.0); + // Make sure there's always a little randomness - no one is THAT accurate unless the gun is producing really minimal + // amounts of recoil (or none). + iCounterForceDeviationY = __max(iCounterForceDeviationY, __min(1, iGunTotalRecoil)); + + // Determine whether we're under- or over-compensating. + INT8 bUpDownY = PreRandom(2)?(1):(-1); + iCounterForceDeviationY *= bUpDownY; + + // So now we have the ideal amount, and the randomal deviation from that amount. Let's add them up. + iAppliedCounterForceY = iIdealCounterForceY + iCounterForceDeviationY; + + // Limit to the maximum applied force. Our shooter cannot exert more force than his personal maximum. + iAppliedCounterForceY = __min(iAppliedCounterForceY, iCounterForceMax); + + ///////////////////////////// + // Transfer unused force from one axis to the other. + if (iAppliedCounterForceX < iCounterForceMax && + iAppliedCounterForceX > iIdealCounterForceX && + iAppliedCounterForceY < iIdealCounterForceY ) + { + // X is using more counter force than it actually needs. Y is not using as much force as it needs. + // Find out how much remainder force we can transfer to Y, and do so. + FLOAT iRemainder = iAppliedCounterForceX - iIdealCounterForceX; + iAppliedCounterForceX -= iRemainder; + iAppliedCounterForceY = __min(iCounterForceMax, __min(iIdealCounterForceY, iAppliedCounterForceY + iRemainder)); + } + else if (iAppliedCounterForceY < iCounterForceMax && + iAppliedCounterForceY > iIdealCounterForceY && + iAppliedCounterForceX < iIdealCounterForceX ) + { + // Y is using more counter force than it actually needs. X is not using as much force as it needs. + // Find out how much remainder force we can transfer to X, and do so. + FLOAT iRemainder = iAppliedCounterForceY - iIdealCounterForceY; + iIdealCounterForceY -= iRemainder; + iAppliedCounterForceX = __min(iCounterForceMax, __min(iIdealCounterForceX, iAppliedCounterForceX + iRemainder)); + } + + ///////////////////////////// + // Use pythagorean to scale this to the max force allowed. + FLOAT iTotalAppliedCounterForce = sqrt((iAppliedCounterForceX*iAppliedCounterForceX) + (iAppliedCounterForceY*iAppliedCounterForceY)); + if (iTotalAppliedCounterForce > iCounterForceMax) + { + FLOAT iRatio = iTotalAppliedCounterForce / iCounterForceMax; + if (iRatio != 0) + { + iAppliedCounterForceX /= iRatio; + iAppliedCounterForceY /= iRatio; + } + } + + // Make sure it's the correct direction compared to where the gun is pulling. + if (dNextOffsetX > 0) + { + iAppliedCounterForceX *= (-1); + } + if (dNextOffsetY > 0) + { + iAppliedCounterForceY *= (-1); + } + + // Record how much counter force was applied this time. It will be used for the next few shots until the + // shooter can recalculate. + pShooter->dPrevCounterForceX = iAppliedCounterForceX; + pShooter->dPrevCounterForceY = iAppliedCounterForceY; + } + + iAppliedCounterForceX += bGunRecoilX; + iAppliedCounterForceY += bGunRecoilY; + + // Add a distance ratio + iAppliedCounterForceX *= iDistanceRatio; + iAppliedCounterForceY *= iDistanceRatio; + + // Offset the bullet. + *dMuzzleOffsetX += iAppliedCounterForceX; + *dMuzzleOffsetY += iAppliedCounterForceY; + + +} #if 0 { diff --git a/Tactical/LOS.h b/Tactical/LOS.h index 954ef29e..1393f262 100644 --- a/Tactical/LOS.h +++ b/Tactical/LOS.h @@ -65,12 +65,14 @@ INT32 CheckForCollision( FLOAT dX, FLOAT dY, FLOAT dZ, FLOAT dDeltaX, FLOAT dDel INT8 ChanceToGetThrough( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ ); INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sHitBy, BOOLEAN fBuckshot, BOOLEAN fFake ); +// HEADROCK HAM 4: Changed the name of one argument to avoid confusion with the new CTH system. +INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, UINT16 usHandItem, INT16 sApertureRatio, BOOLEAN fBuckshot, BOOLEAN fFake ); #define CALC_FROM_ALL_DIRS -1 #define CALC_FROM_WANTED_DIR -2 #define NO_DISTANCE_LIMIT -3 -INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS, UINT8 ubAimLocation = LOS_POS, bool adjustForSight = true ); +INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS, UINT8 ubAimLocation = LOS_POS, bool adjustForSight = true, bool cthCalc = false ); INT32 SoldierTo3DLocationLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT32 sGridNo, INT8 bLevel, INT8 bCubeLevel, INT8 bAware, int ubSightLimit = CALC_FROM_ALL_DIRS, bool adjustForSight = true ); INT32 SoldierToVirtualSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, INT32 sGridNo, INT8 bLevel, INT8 bStance, INT8 bAware, int iTileSightLimit = CALC_FROM_ALL_DIRS ); UINT8 SoldierToSoldierChanceToGetThrough( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE * pEndSoldier ); @@ -170,16 +172,14 @@ extern LOSResults gLOSTestResults; void MoveBullet( INT32 iBullet ); //BOOLEAN FireBullet2( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOAT dEndZ, INT16 sHitBy ); -// TODO: public but at the wrong place, the original function deletes the important parts, not sure what it could brake -// to be used in conjunction with the camo thing and the "F" key -INT8 GetTerrainTypeForGrid( const INT32& uGridNo ); +INT8 GetTerrainTypeForGrid( const INT32& uGridNo, const INT16& bLevel ); // check the flat distance adjustment based on your stance // use this to test your view on your surroundings based on your stance INT8 GetSightAdjustmentThroughStance( const UINT8& ubStance ); // quick way to get all. should be used for all sight line tests with target soldier known -INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo = -1, INT8 bStance = -1 ); +INT16 GetSightAdjustment( SOLDIERTYPE* pSoldier, INT32 sGridNo = -1, INT16 bLevel = -1, INT8 bStance = -1 ); //zilpin: pellet spread patterns externalized in XML #define SPREADPATTERN_NAME_SIZE 32 @@ -210,4 +210,26 @@ extern t_SpreadPattern *gpSpreadPattern; extern INT32 giSpreadPatternCount; extern INT32 GetSpreadPattern( OBJECTTYPE * pObj ); +///////////////////////////////////////////////////////////////////////////////////////// +// HEADROCK HAM 4: The following functions are all part of the NCTH project, +// which completely redesigns the way we calculate and handle CTH for the purposes of firing weapons. +void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT *dEndX, FLOAT *dEndY, FLOAT *dEndZ, OBJECTTYPE *pWeapon, UINT32 uiMuzzleSway, INT16 *sApertureRatio ); +FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, UINT8 ubAimTime ); +FLOAT CalcBasicAperture(); +void CalcTargetMovementOffset( SOLDIERTYPE *pShooter, SOLDIERTYPE *pTarget, OBJECTTYPE *pWeapon, FLOAT *dMuzzleOffsetX, DOUBLE ddShootingAngle, INT32 iAperture ); +void CalcRangeCompensationOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetY, INT32 iRangeToTarget, OBJECTTYPE *pWeapon ); +void CalcMuzzleSway( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, FLOAT iAperture ); +void CalcBulletDeviation( SOLDIERTYPE *pShooter, FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange ); +void LimitImpactPointToMaxAperture( FLOAT *dShotOffsetX, FLOAT *dShotOffsetY, FLOAT dDistanceAperture ); +void CalcPreRecoilOffset( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, UINT32 uiRange ); +void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange ); + +// HEADROCK HAM 4: Required for shooting mechanic +extern INT8 EffectiveMarksmanship( SOLDIERTYPE * pSoldier ); +extern INT8 EffectiveWisdom( SOLDIERTYPE * pSoldier ); +extern INT8 EffectiveExpLevel( SOLDIERTYPE * pSoldier ); +extern INT8 EffectiveDexterity( SOLDIERTYPE * pSoldier ); +extern INT8 EffectiveStrength( SOLDIERTYPE * pSoldier ); +extern INT8 EffectiveAgility( SOLDIERTYPE * pSoldier ); + #endif \ No newline at end of file diff --git a/Tactical/Merc Hiring.cpp b/Tactical/Merc Hiring.cpp index 2bbbc62b..7f7e6133 100644 --- a/Tactical/Merc Hiring.cpp +++ b/Tactical/Merc Hiring.cpp @@ -105,7 +105,7 @@ INT8 HireMerc( MERC_HIRE_STRUCT *pHireMerc) //hayden, 7 member team limit setable in ini - if( NumberOfMercsOnPlayerTeam() >= gGameExternalOptions.ubGameMaximumNumberOfPlayerMercs || (is_client && NumberOfMercsOnPlayerTeam() >= MAX_MERCS) ) + if( NumberOfMercsOnPlayerTeam() >= gGameExternalOptions.ubGameMaximumNumberOfPlayerMercs || (is_client && NumberOfMercsOnPlayerTeam() >= cMaxMercs) ) return( MERC_HIRE_OVER_PLAYER_LIMIT ); // ATE: if we are to use landing zone, update to latest value @@ -127,7 +127,7 @@ INT8 HireMerc( MERC_HIRE_STRUCT *pHireMerc) MercCreateStruct.bTeam = SOLDIER_CREATE_AUTO_TEAM; MercCreateStruct.fCopyProfileItemsOver= pHireMerc->fCopyProfileItemsOver; - if(!ALLOW_EQUIP && is_networked) + if(!cAllowMercEquipment && is_networked) MercCreateStruct.fCopyProfileItemsOver=0;//hayden : server overide if ( !TacticalCreateSoldier( &MercCreateStruct, &iNewIndex ) ) @@ -246,7 +246,8 @@ INT8 HireMerc( MERC_HIRE_STRUCT *pHireMerc) //if the merc is an AIM merc - if( ubCurrentSoldier < 40 ) + //if( ubCurrentSoldier < 40 ) + if ( gProfilesAIM[ ubCurrentSoldier ].ProfilId == ubCurrentSoldier ) //new profiles by Jazz { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__AIM_MERC; @@ -275,7 +276,8 @@ INT8 HireMerc( MERC_HIRE_STRUCT *pHireMerc) pSoldier->usMedicalDeposit = gMercProfiles[ pSoldier->ubProfile ].sMedicalDepositAmount; } //if the merc is from M.E.R.C. - else if( ( ubCurrentSoldier >= BIFF && ubCurrentSoldier <= BUBBA ) || ubCurrentSoldier >= GASTON ) + //else if( ( ubCurrentSoldier >= BIFF && ubCurrentSoldier <= BUBBA ) || ubCurrentSoldier >= GASTON ) + else if ( gProfilesMERC[ ubCurrentSoldier ].ProfilId == ubCurrentSoldier ) //new profiles by Jazz { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__MERC; //pSoldier->iTotalContractCharge = -1; @@ -288,7 +290,8 @@ INT8 HireMerc( MERC_HIRE_STRUCT *pHireMerc) if(!is_client)AddHistoryToPlayersLog(HISTORY_HIRED_MERC_FROM_MERC, ubCurrentSoldier, GetWorldTotalMin(), -1, -1 ); } //If the merc is from IMP, (ie a player character) - else if( ( ubCurrentSoldier >= 51 ) && ( ubCurrentSoldier < 57 ) ) + //else if( ( ubCurrentSoldier >= 51 ) && ( ubCurrentSoldier < 57 ) ) + else if ( gProfilesIMP[ ubCurrentSoldier ].ProfilId == ubCurrentSoldier ) //new profiles by Jazz { pSoldier->ubWhatKindOfMercAmI = MERC_TYPE__PLAYER_CHARACTER; //pSoldier->iTotalContractCharge = -1; diff --git a/Tactical/Merc Hiring.h b/Tactical/Merc Hiring.h index 90f784e6..e9215d92 100644 --- a/Tactical/Merc Hiring.h +++ b/Tactical/Merc Hiring.h @@ -53,5 +53,6 @@ void UpdateAnyInTransitMercsWithGlobalArrivalSector( ); UINT32 GetMercArrivalTimeOfDay( ); +extern INT16 StrategicPythSpacesAway(INT16 sOrigin, INT16 sDest); #endif \ No newline at end of file diff --git a/Tactical/Morale.cpp b/Tactical/Morale.cpp index d691fcdb..ca29fd50 100644 --- a/Tactical/Morale.cpp +++ b/Tactical/Morale.cpp @@ -23,6 +23,9 @@ #include "Event Pump.h" // HEADROCK HAM 3.5: Added for facility effect on morale #include "Facilities.h" + // addedd by SANDRO + #include "GameSettings.h" + #include "Isometric Utils.h" #endif #include "connect.h" @@ -80,10 +83,16 @@ MoraleEvent gbMoraleEvent[NUM_MORALE_EVENTS] = { STRATEGIC_MORALE_EVENT, -5}, // MORALE_MERC_MARRIED, { STRATEGIC_MORALE_EVENT, +8}, // MORALE_QUEEN_BATTLE_WON, { STRATEGIC_MORALE_EVENT, +5}, // MORALE_SEX, + // added by SANDRO + { STRATEGIC_MORALE_EVENT, -1}, // MORALE_HEAT_INTOLERANT_IN_DESERT, + { TACTICAL_MORALE_EVENT, -1}, // MORALE_PSYCHO_UNABLE_TO_PSYCHO, + { STRATEGIC_MORALE_EVENT, +1}, // MORALE_PACIFIST_GAIN_NONCOMBAT, + { TACTICAL_MORALE_EVENT, +1}, // MORALE_MALICIOUS_HIT, }; BOOLEAN gfSomeoneSaidMoraleQuote = FALSE; +BOOLEAN IsShowOffNearBy( SOLDIERTYPE * pSoldier ); // Added by SANDRO INT8 GetMoraleModifier( SOLDIERTYPE * pSoldier ) { @@ -176,7 +185,7 @@ void DecayTacticalMoraleModifiers( void ) continue; } - switch( gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait ) + switch( gMercProfiles[ pSoldier->ubProfile ].bDisability ) { case CLAUSTROPHOBIC: if ( pSoldier->bSectorZ > 0 ) @@ -313,7 +322,7 @@ void RefreshSoldierMorale( SOLDIERTYPE * pSoldier ) GetSoldierFacilityAssignmentIndex( pSoldier ) != -1) { UINT8 ubFacilityType = (UINT8)cnt; - UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier ); + UINT8 ubAssignmentType = (UINT8)GetSoldierFacilityAssignmentIndex( pSoldier ); // Check this facility both for an assignment-specific AND ambient value. Use it if it's the lowest // encountered yet. ubMaxMorale = __min(ubMaxMorale, (UINT8)GetFacilityModifier(FACILITY_MAX_MORALE, ubFacilityType, ubAssignmentType )); @@ -338,11 +347,13 @@ void RefreshSoldierMorale( SOLDIERTYPE * pSoldier ) fCharacterInfoPanelDirty = TRUE; } - -void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, UINT8 ubType, INT8 bMoraleMod ) +// SANDRO - changed this a bit +void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) { MERCPROFILESTRUCT * pProfile; INT32 iMoraleModTotal; + UINT8 ubType; + INT8 bMoraleMod = 0; if ( !pSoldier->bActive || ( pSoldier->stats.bLife < CONSCIOUSNESS ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) || AM_AN_EPC( pSoldier ) ) @@ -363,27 +374,96 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, UINT8 ubType, INT8 bMoraleMod return; } - if(DISABLE_MORALE && is_networked) + if(cDisableMorale && is_networked) { return; }//hayden + ubType = gbMoraleEvent[bMoraleEvent].ubType; + bMoraleMod = gbMoraleEvent[bMoraleEvent].bChange; + pProfile = &(gMercProfiles[ pSoldier->ubProfile ]); if (bMoraleMod > 0) { - switch( pProfile->bAttitude ) + if ( gGameOptions.fNewTraitSystem ) { - case ATT_OPTIMIST: - case ATT_AGGRESSIVE: - bMoraleMod += 1; + // SANDRO - STOMP traits + // Squadleader's bonus to morale + if ( IS_MERC_BODY_TYPE( pSoldier ) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) ) + { + bMoraleMod += (gSkillTraitValues.ubSLMoraleGainBonus * GetSquadleadersCountInVicinity( pSoldier, FALSE, FALSE )); + } + // Check for character traits + INT8 bNumMercs = 0; + switch( pProfile->bCharacterTrait ) + { + case CHAR_TRAIT_SOCIABLE: + bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs == 0 ) + bMoraleMod -= 5; + else if ( bNumMercs == 1 ) + bMoraleMod -= 2; break; - case ATT_PESSIMIST: - bMoraleMod -= 1; - break; - default: + case CHAR_TRAIT_LONER: + bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs > 1 ) + bMoraleMod -= 5; + else if ( bNumMercs == 1 ) + bMoraleMod -= 2; break; + case CHAR_TRAIT_OPTIMIST: + bMoraleMod += 1; + break; + case CHAR_TRAIT_AGGRESSIVE: + switch ( bMoraleEvent ) + { + case MORALE_KILLED_ENEMY: + case MORALE_DID_LOTS_OF_DAMAGE: + case MORALE_MONSTER_QUEEN_KILLED: + case MORALE_DEIDRANNA_KILLED: + bMoraleMod += 1; + break; + } + break; + case CHAR_TRAIT_PACIFIST: + switch ( bMoraleEvent ) + { + case MORALE_KILLED_ENEMY: + case MORALE_DID_LOTS_OF_DAMAGE: + case MORALE_BATTLE_WON: + case MORALE_HEARD_BATTLE_WON: + case MORALE_HATED_DIED: + case MORALE_MONSTER_QUEEN_KILLED: + case MORALE_DEIDRANNA_KILLED: + case MORALE_QUEEN_BATTLE_WON: + bMoraleMod -= 5; + break; + } + break; + } + if ( IsShowOffNearBy( pSoldier ) ) + { + bMoraleMod -= 2; + } + } + else if ( bMoraleMod != MORALE_PSYCHO_UNABLE_TO_PSYCHO && bMoraleMod != MORALE_MALICIOUS_HIT) + { + switch( pProfile->bAttitude ) + { + case ATT_OPTIMIST: + case ATT_AGGRESSIVE: + bMoraleMod += 1; + break; + case ATT_PESSIMIST: + bMoraleMod -= 1; + break; + default: + break; + } + } + if (bMoraleMod < 0) { // can't change a positive event into a negative one! @@ -392,19 +472,62 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, UINT8 ubType, INT8 bMoraleMod } else { - switch( pProfile->bAttitude ) + if ( gGameOptions.fNewTraitSystem ) { - case ATT_OPTIMIST: + // SANDRO - STOMP traits - squadleader's bonus to morale + if ( IS_MERC_BODY_TYPE( pSoldier ) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) ) + { + switch ( bMoraleEvent ) // certain thing are not supported by our squadleader + { + case MORALE_HATED_DIED: + case MORALE_MERC_MARRIED: + case MORALE_SEX: + case MORALE_PSYCHO_UNABLE_TO_PSYCHO: + case MORALE_MALICIOUS_HIT: + break; + default: + bMoraleMod += (gSkillTraitValues.ubSLMoraleLossReduction * GetSquadleadersCountInVicinity( pSoldier, FALSE, FALSE )); + break; + } + } + // Check for character traits + if ( pProfile->bCharacterTrait == CHAR_TRAIT_OPTIMIST ) + { bMoraleMod += 1; - break; - case ATT_PESSIMIST: - bMoraleMod -= 1; - break; - case ATT_COWARD: - bMoraleMod -= 2; - default: - break; + } + // Fearless character does not suffer morale loss for these so much + else if( pProfile->bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + { + switch ( bMoraleEvent ) + { + case MORALE_SQUADMATE_DIED: + case MORALE_SUPPRESSED: + case MORALE_TOOK_LOTS_OF_DAMAGE: + bMoraleMod += 3; + break; + case MORALE_TEAMMATE_DIED: + bMoraleMod += 2; + break; + } + } } + else if ( bMoraleMod != MORALE_PSYCHO_UNABLE_TO_PSYCHO) + { + switch( pProfile->bAttitude ) + { + case ATT_OPTIMIST: + bMoraleMod += 1; + break; + case ATT_PESSIMIST: + bMoraleMod -= 1; + break; + case ATT_COWARD: + bMoraleMod -= 2; + default: + break; + } + } + if (pSoldier->pathing.bLevel == 1) { bMoraleMod--; @@ -413,6 +536,7 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, UINT8 ubType, INT8 bMoraleMod { bMoraleMod++; } + if (bMoraleMod > 0) { // can't change a negative event into a positive one! @@ -475,7 +599,8 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, UINT8 ubType, INT8 bMoraleMod void HandleMoraleEventForSoldier( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent ) { - UpdateSoldierMorale( pSoldier, gbMoraleEvent[bMoraleEvent].ubType, gbMoraleEvent[bMoraleEvent].bChange ); + // SANDRO - changed this to send the event forward + UpdateSoldierMorale( pSoldier, bMoraleEvent ); //, gbMoraleEvent[bMoraleEvent].ubType, gbMoraleEvent[bMoraleEvent].bChange ); } @@ -518,10 +643,12 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I case MORALE_CLAUSTROPHOBE_UNDERGROUND: case MORALE_INSECT_PHOBIC_SEES_CREATURE: case MORALE_NERVOUS_ALONE: + case MORALE_HEAT_INTOLERANT_IN_DESERT: // SANDRO added this one // needs specific soldier! Assert( pSoldier ); // affects the soldier only, should be ignored if tactical morale mod is -20 or less - if ( pSoldier->aiData.bTacticalMoraleMod > PHOBIC_LIMIT ) + // SANDRO - really?? I think it also shouldn't go lower if strategic morale mod is less than -20 + if ( pSoldier->aiData.bTacticalMoraleMod > PHOBIC_LIMIT && pSoldier->aiData.bStrategicMoraleMod > PHOBIC_LIMIT ) { HandleMoraleEventForSoldier( pSoldier, bMoraleEvent ); } @@ -538,7 +665,8 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I { HandleMoraleEventForSoldier( pTeamSoldier, MORALE_BATTLE_WON ); } - else + // SANDRO - Assertive people don't care about actions of others + else if ( !gGameOptions.fNewTraitSystem || gMercProfiles[pTeamSoldier->ubProfile].bCharacterTrait != CHAR_TRAIT_ASSERTIVE ) { HandleMoraleEventForSoldier( pTeamSoldier, MORALE_HEARD_BATTLE_WON ); } @@ -557,22 +685,35 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I if ( SOLDIER_IN_SECTOR( pTeamSoldier, sMapX, sMapY, bMapZ ) || ( pTeamSoldier->flags.fBetweenSectors && ((pTeamSoldier->ubPrevSectorID % 16) + 1) == sMapX && ((pTeamSoldier->ubPrevSectorID / 16) + 1) == sMapY && ( pTeamSoldier->bSectorZ == bMapZ ) ) ) { - switch ( gMercProfiles[ pTeamSoldier->ubProfile ].bAttitude ) + if ( gGameOptions.fNewTraitSystem ) { - case ATT_AGGRESSIVE: - // double the penalty - these guys REALLY hate running away + // SANDRO - no penalty for pacifists to run away + if ( gMercProfiles[pTeamSoldier->ubProfile].bCharacterTrait != CHAR_TRAIT_PACIFIST ) HandleMoraleEventForSoldier( pTeamSoldier, MORALE_RAN_AWAY ); + // Double morale drop for aggressive people + if ( gMercProfiles[pTeamSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) HandleMoraleEventForSoldier( pTeamSoldier, MORALE_RAN_AWAY ); - break; - case ATT_COWARD: - // no penalty - cowards are perfectly happy to avoid fights! - break; - default: - HandleMoraleEventForSoldier( pTeamSoldier, MORALE_RAN_AWAY ); - break; + } + else + { + switch ( gMercProfiles[ pTeamSoldier->ubProfile ].bAttitude ) + { + case ATT_AGGRESSIVE: + // double the penalty - these guys REALLY hate running away + HandleMoraleEventForSoldier( pTeamSoldier, MORALE_RAN_AWAY ); + HandleMoraleEventForSoldier( pTeamSoldier, MORALE_RAN_AWAY ); + break; + case ATT_COWARD: + // no penalty - cowards are perfectly happy to avoid fights! + break; + default: + HandleMoraleEventForSoldier( pTeamSoldier, MORALE_RAN_AWAY ); + break; + } } } - else + // SANDRO - Assertive people don't care about actions of others + else if ( !gGameOptions.fNewTraitSystem || gMercProfiles[pTeamSoldier->ubProfile].bCharacterTrait != CHAR_TRAIT_ASSERTIVE ) { HandleMoraleEventForSoldier( pTeamSoldier, MORALE_HEARD_BATTLE_LOST ); } @@ -598,7 +739,22 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I { if ( pTeamSoldier->bActive ) { - HandleMoraleEventForSoldier( pTeamSoldier, bMoraleEvent ); + if ( gGameOptions.fNewTraitSystem && bMoraleEvent != MORALE_DEIDRANNA_KILLED) + { + if ( !SOLDIER_IN_SECTOR( pTeamSoldier, sMapX, sMapY, bMapZ ) && ( gbMoraleEvent[bMoraleEvent].bChange > 0 ) && + gMercProfiles[pTeamSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_ASSERTIVE ) + { + // No morale gain for assertive people from actions of others + } + else + { + HandleMoraleEventForSoldier( pTeamSoldier, bMoraleEvent ); + } + } + else + { + HandleMoraleEventForSoldier( pTeamSoldier, bMoraleEvent ); + } } } break; @@ -654,11 +810,29 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I { // mate died in my sector! tactical morale mod HandleMoraleEventForSoldier( pTeamSoldier, MORALE_SQUADMATE_DIED ); + + // SANDRO - Squadleaders death cost a lot of morale + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SQUADLEADER_NT )) + { + for ( UINT8 i = 0; i < (gSkillTraitValues.ubSLDeathMoralelossMultiplier * NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT )); i++ ) + { + HandleMoraleEventForSoldier( pTeamSoldier, MORALE_SQUADMATE_DIED ); + } + } } // this is handled for everyone even if in sector, as it's a strategic morale mod HandleMoraleEventForSoldier( pTeamSoldier, MORALE_TEAMMATE_DIED ); + // SANDRO - Squadleaders death cost a lot of morale + if( gGameOptions.fNewTraitSystem && (NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT ) > 1)) + { + for ( UINT8 i = 0; i < gSkillTraitValues.ubSLDeathMoralelossMultiplier; i++ ) + { + HandleMoraleEventForSoldier( pTeamSoldier, MORALE_SQUADMATE_DIED ); + } + } + if (BUDDY_MERC( pProfile, pSoldier->ubProfile )) { // oh no! buddy died! @@ -715,6 +889,13 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I } } break; + // added by SANDRO + case MORALE_PSYCHO_UNABLE_TO_PSYCHO: + case MORALE_PACIFIST_GAIN_NONCOMBAT: // added by SANDRO + case MORALE_MALICIOUS_HIT: // added by SANDRO + Assert( pSoldier ); + HandleMoraleEventForSoldier( pSoldier, bMoraleEvent ); + break; default: // debug message @@ -954,6 +1135,11 @@ void HourlyMoraleUpdate( void ) { bTeamMoraleModChange = 0; } + // SANDRO - morale is going down faster if not fighting for malicious characters + if ( gGameOptions.fNewTraitSystem && pProfile->bCharacterTrait == CHAR_TRAIT_MALICIOUS ) + { + bTeamMoraleModChange -= 1; + } pSoldier->aiData.bTeamMoraleMod += bTeamMoraleModChange; pSoldier->aiData.bTeamMoraleMod = __min( pSoldier->aiData.bTeamMoraleMod, MORALE_MOD_MAX ); pSoldier->aiData.bTeamMoraleMod = __max( pSoldier->aiData.bTeamMoraleMod, -MORALE_MOD_MAX ); @@ -1024,3 +1210,60 @@ void DailyMoraleUpdate(SOLDIERTYPE *pSoldier) } } + +// Added by SANDRO +BOOLEAN IsShowOffNearBy( SOLDIERTYPE * pSoldier ) +{ + UINT32 uiLoop; + SOLDIERTYPE * pTeammate; + BOOLEAN fOneException = FALSE; + BOOLEAN fYesHeIs = FALSE; + + if (!pSoldier) + { + return( FALSE ); + } + if( !(pSoldier->bActive) || !(pSoldier->bInSector) ) + { + return( FALSE ); + } + + for ( uiLoop = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID; uiLoop < gTacticalStatus.Team[ pSoldier->bTeam ].bLastID; uiLoop++) + { + pTeammate = MercPtrs[ uiLoop ]; + if ( pTeammate == NULL ) + { + continue; + } + if ( pTeammate == pSoldier ) + { + continue; + } + // Are we actually here? + if ( !(pTeammate->bActive) || !(pTeammate->bInSector) || ( pTeammate->flags.uiStatusFlags & SOLDIER_VEHICLE ) || (pTeammate->bAssignment == VEHICLE ) ) + { + // is nowhere around! + continue; + } + // Are we from our team an dalive? + if ( pTeammate->bTeam == pSoldier->bTeam && pTeammate->stats.bLife >= OKLIFE && + gMercProfiles[ pTeammate->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF && PythSpacesAway( pSoldier->sGridNo, pTeammate->sGridNo ) <= 15) + { + if ( (pSoldier->ubBodyType <= STOCKYMALE && pTeammate->ubBodyType <= STOCKYMALE) || + (pSoldier->ubBodyType == REGFEMALE && pTeammate->ubBodyType == REGFEMALE) ) + { + // phlegmatic character can ignore one + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC && !fOneException) + { + fOneException = TRUE; + } + else + { + fYesHeIs = TRUE; + } + } + } + } + + return( fYesHeIs ); +} \ No newline at end of file diff --git a/Tactical/Morale.h b/Tactical/Morale.h index 30e20896..4e341d16 100644 --- a/Tactical/Morale.h +++ b/Tactical/Morale.h @@ -44,6 +44,11 @@ typedef enum MORALE_MERC_MARRIED, MORALE_QUEEN_BATTLE_WON, MORALE_SEX, + // added by SANDRO + MORALE_HEAT_INTOLERANT_IN_DESERT, + MORALE_PSYCHO_UNABLE_TO_PSYCHO, + MORALE_PACIFIST_GAIN_NONCOMBAT, + MORALE_MALICIOUS_HIT, NUM_MORALE_EVENTS } MoraleEventNames; diff --git a/Tactical/Overhead Types.h b/Tactical/Overhead Types.h index de8b1c25..baf80fa0 100644 --- a/Tactical/Overhead Types.h +++ b/Tactical/Overhead Types.h @@ -356,7 +356,246 @@ enum UNNAMED_CIV_GROUP_17, UNNAMED_CIV_GROUP_18, UNNAMED_CIV_GROUP_19, - + UNNAMED_CIV_GROUP_20, + UNNAMED_CIV_GROUP_21, + UNNAMED_CIV_GROUP_22, + UNNAMED_CIV_GROUP_23, + UNNAMED_CIV_GROUP_24, + UNNAMED_CIV_GROUP_25, + UNNAMED_CIV_GROUP_26, + UNNAMED_CIV_GROUP_27, + UNNAMED_CIV_GROUP_28, + UNNAMED_CIV_GROUP_29, + UNNAMED_CIV_GROUP_30, + UNNAMED_CIV_GROUP_31, + UNNAMED_CIV_GROUP_32, + UNNAMED_CIV_GROUP_33, + UNNAMED_CIV_GROUP_34, + UNNAMED_CIV_GROUP_35, + UNNAMED_CIV_GROUP_36, + UNNAMED_CIV_GROUP_37, + UNNAMED_CIV_GROUP_38, + UNNAMED_CIV_GROUP_39, + UNNAMED_CIV_GROUP_40, + UNNAMED_CIV_GROUP_41, + UNNAMED_CIV_GROUP_42, + UNNAMED_CIV_GROUP_43, + UNNAMED_CIV_GROUP_44, + UNNAMED_CIV_GROUP_45, + UNNAMED_CIV_GROUP_46, + UNNAMED_CIV_GROUP_47, + UNNAMED_CIV_GROUP_48, + UNNAMED_CIV_GROUP_49, + UNNAMED_CIV_GROUP_50, + UNNAMED_CIV_GROUP_51, + UNNAMED_CIV_GROUP_52, + UNNAMED_CIV_GROUP_53, + UNNAMED_CIV_GROUP_54, + UNNAMED_CIV_GROUP_55, + UNNAMED_CIV_GROUP_56, + UNNAMED_CIV_GROUP_57, + UNNAMED_CIV_GROUP_58, + UNNAMED_CIV_GROUP_59, + UNNAMED_CIV_GROUP_60, + UNNAMED_CIV_GROUP_61, + UNNAMED_CIV_GROUP_62, + UNNAMED_CIV_GROUP_63, + UNNAMED_CIV_GROUP_64, + UNNAMED_CIV_GROUP_65, + UNNAMED_CIV_GROUP_66, + UNNAMED_CIV_GROUP_67, + UNNAMED_CIV_GROUP_68, + UNNAMED_CIV_GROUP_69, + UNNAMED_CIV_GROUP_70, + UNNAMED_CIV_GROUP_71, + UNNAMED_CIV_GROUP_72, + UNNAMED_CIV_GROUP_73, + UNNAMED_CIV_GROUP_74, + UNNAMED_CIV_GROUP_75, + UNNAMED_CIV_GROUP_76, + UNNAMED_CIV_GROUP_77, + UNNAMED_CIV_GROUP_78, + UNNAMED_CIV_GROUP_79, + UNNAMED_CIV_GROUP_80, + UNNAMED_CIV_GROUP_81, + UNNAMED_CIV_GROUP_82, + UNNAMED_CIV_GROUP_83, + UNNAMED_CIV_GROUP_84, + UNNAMED_CIV_GROUP_85, + UNNAMED_CIV_GROUP_86, + UNNAMED_CIV_GROUP_87, + UNNAMED_CIV_GROUP_88, + UNNAMED_CIV_GROUP_89, + UNNAMED_CIV_GROUP_90, + UNNAMED_CIV_GROUP_91, + UNNAMED_CIV_GROUP_92, + UNNAMED_CIV_GROUP_93, + UNNAMED_CIV_GROUP_94, + UNNAMED_CIV_GROUP_95, + UNNAMED_CIV_GROUP_96, + UNNAMED_CIV_GROUP_97, + UNNAMED_CIV_GROUP_98, + UNNAMED_CIV_GROUP_99, + UNNAMED_CIV_GROUP_100, + UNNAMED_CIV_GROUP_101, + UNNAMED_CIV_GROUP_102, + UNNAMED_CIV_GROUP_103, + UNNAMED_CIV_GROUP_104, + UNNAMED_CIV_GROUP_105, + UNNAMED_CIV_GROUP_106, + UNNAMED_CIV_GROUP_107, + UNNAMED_CIV_GROUP_108, + UNNAMED_CIV_GROUP_109, + UNNAMED_CIV_GROUP_110, + UNNAMED_CIV_GROUP_111, + UNNAMED_CIV_GROUP_112, + UNNAMED_CIV_GROUP_113, + UNNAMED_CIV_GROUP_114, + UNNAMED_CIV_GROUP_115, + UNNAMED_CIV_GROUP_116, + UNNAMED_CIV_GROUP_117, + UNNAMED_CIV_GROUP_118, + UNNAMED_CIV_GROUP_119, + UNNAMED_CIV_GROUP_120, + UNNAMED_CIV_GROUP_121, + UNNAMED_CIV_GROUP_122, + UNNAMED_CIV_GROUP_123, + UNNAMED_CIV_GROUP_124, + UNNAMED_CIV_GROUP_125, + UNNAMED_CIV_GROUP_126, + UNNAMED_CIV_GROUP_127, + UNNAMED_CIV_GROUP_128, + UNNAMED_CIV_GROUP_129, + UNNAMED_CIV_GROUP_130, + UNNAMED_CIV_GROUP_131, + UNNAMED_CIV_GROUP_132, + UNNAMED_CIV_GROUP_133, + UNNAMED_CIV_GROUP_134, + UNNAMED_CIV_GROUP_135, + UNNAMED_CIV_GROUP_136, + UNNAMED_CIV_GROUP_137, + UNNAMED_CIV_GROUP_138, + UNNAMED_CIV_GROUP_139, + UNNAMED_CIV_GROUP_140, + + UNNAMED_CIV_GROUP_141, + UNNAMED_CIV_GROUP_142, + UNNAMED_CIV_GROUP_143, + UNNAMED_CIV_GROUP_144, + UNNAMED_CIV_GROUP_145, + UNNAMED_CIV_GROUP_146, + UNNAMED_CIV_GROUP_147, + UNNAMED_CIV_GROUP_148, + UNNAMED_CIV_GROUP_149, + UNNAMED_CIV_GROUP_150, + UNNAMED_CIV_GROUP_151, + UNNAMED_CIV_GROUP_152, + UNNAMED_CIV_GROUP_153, + UNNAMED_CIV_GROUP_154, + UNNAMED_CIV_GROUP_155, + UNNAMED_CIV_GROUP_156, + UNNAMED_CIV_GROUP_157, + UNNAMED_CIV_GROUP_158, + UNNAMED_CIV_GROUP_159, + UNNAMED_CIV_GROUP_160, + UNNAMED_CIV_GROUP_161, + UNNAMED_CIV_GROUP_162, + UNNAMED_CIV_GROUP_163, + UNNAMED_CIV_GROUP_164, + UNNAMED_CIV_GROUP_165, + UNNAMED_CIV_GROUP_166, + UNNAMED_CIV_GROUP_167, + UNNAMED_CIV_GROUP_168, + UNNAMED_CIV_GROUP_169, + UNNAMED_CIV_GROUP_170, + + UNNAMED_CIV_GROUP_171, + UNNAMED_CIV_GROUP_172, + UNNAMED_CIV_GROUP_173, + UNNAMED_CIV_GROUP_174, + UNNAMED_CIV_GROUP_175, + UNNAMED_CIV_GROUP_176, + UNNAMED_CIV_GROUP_177, + UNNAMED_CIV_GROUP_178, + UNNAMED_CIV_GROUP_179, + UNNAMED_CIV_GROUP_180, + UNNAMED_CIV_GROUP_181, + UNNAMED_CIV_GROUP_182, + UNNAMED_CIV_GROUP_183, + UNNAMED_CIV_GROUP_184, + UNNAMED_CIV_GROUP_185, + UNNAMED_CIV_GROUP_186, + UNNAMED_CIV_GROUP_187, + UNNAMED_CIV_GROUP_188, + UNNAMED_CIV_GROUP_189, + UNNAMED_CIV_GROUP_190, + UNNAMED_CIV_GROUP_191, + UNNAMED_CIV_GROUP_192, + UNNAMED_CIV_GROUP_193, + UNNAMED_CIV_GROUP_194, + UNNAMED_CIV_GROUP_195, + UNNAMED_CIV_GROUP_196, + UNNAMED_CIV_GROUP_197, + UNNAMED_CIV_GROUP_198, + UNNAMED_CIV_GROUP_199, + UNNAMED_CIV_GROUP_200, + + UNNAMED_CIV_GROUP_201, + UNNAMED_CIV_GROUP_202, + UNNAMED_CIV_GROUP_203, + UNNAMED_CIV_GROUP_204, + UNNAMED_CIV_GROUP_205, + UNNAMED_CIV_GROUP_206, + UNNAMED_CIV_GROUP_207, + UNNAMED_CIV_GROUP_208, + UNNAMED_CIV_GROUP_209, + UNNAMED_CIV_GROUP_210, + UNNAMED_CIV_GROUP_211, + UNNAMED_CIV_GROUP_212, + UNNAMED_CIV_GROUP_213, + UNNAMED_CIV_GROUP_214, + UNNAMED_CIV_GROUP_215, + UNNAMED_CIV_GROUP_216, + UNNAMED_CIV_GROUP_217, + UNNAMED_CIV_GROUP_218, + UNNAMED_CIV_GROUP_219, + UNNAMED_CIV_GROUP_220, + UNNAMED_CIV_GROUP_221, + UNNAMED_CIV_GROUP_222, + UNNAMED_CIV_GROUP_223, + UNNAMED_CIV_GROUP_224, + UNNAMED_CIV_GROUP_225, + UNNAMED_CIV_GROUP_226, + UNNAMED_CIV_GROUP_227, + UNNAMED_CIV_GROUP_228, + UNNAMED_CIV_GROUP_229, + UNNAMED_CIV_GROUP_230, + + UNNAMED_CIV_GROUP_231, + UNNAMED_CIV_GROUP_232, + UNNAMED_CIV_GROUP_233, + UNNAMED_CIV_GROUP_234, + UNNAMED_CIV_GROUP_235, + UNNAMED_CIV_GROUP_236, + UNNAMED_CIV_GROUP_237, + UNNAMED_CIV_GROUP_238, + UNNAMED_CIV_GROUP_239, + UNNAMED_CIV_GROUP_240, + UNNAMED_CIV_GROUP_241, + UNNAMED_CIV_GROUP_242, + UNNAMED_CIV_GROUP_243, + UNNAMED_CIV_GROUP_244, + UNNAMED_CIV_GROUP_245, + UNNAMED_CIV_GROUP_246, + UNNAMED_CIV_GROUP_247, + UNNAMED_CIV_GROUP_248, + UNNAMED_CIV_GROUP_249, + UNNAMED_CIV_GROUP_250, + + UNNAMED_CIV_GROUP_251, + UNNAMED_CIV_GROUP_252, + UNNAMED_CIV_GROUP_253, + UNNAMED_CIV_GROUP_254, NUM_CIV_GROUPS }; @@ -382,7 +621,7 @@ enum BoxingStates // add new groups. Try to abbreviate the team name as much as possible. The text is in // EditorMercs.c #ifdef JA2EDITOR - extern CHAR16 gszCivGroupNames[ NUM_CIV_GROUPS ][ 20 ]; + extern CHAR16 gszCivGroupNames[ NUM_CIV_GROUPS ][ 128 ]; #endif // //----------------------------------------------- diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index ed7180fc..2f71cbb7 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -114,9 +114,12 @@ #include "Lua Interpreter.h" #include "bullets.h" #endif -#include "test_space.h" #include "connect.h" +#include "Luaglobal.h" +#include "LuaInitNPCs.h" +#include "Interface.h" + // OJW - 20090419 UINT8 giMAXIMUM_NUMBER_OF_PLAYER_MERCS = CODE_MAXIMUM_NUMBER_OF_PLAYER_MERCS; UINT8 giMAXIMUM_NUMBER_OF_PLAYER_VEHICLES = CODE_MAXIMUM_NUMBER_OF_PLAYER_VEHICLES; @@ -779,6 +782,7 @@ BOOLEAN InitOverhead( ) gTacticalStatus.fDidGameJustStart = TRUE; gTacticalStatus.ubLastRequesterTargetID = NO_PROFILE; + gTacticalStatus.ubLastRequesterSurgeryTargetID = NOBODY; // SANDRO - reset surgery requester too for ( cnt = 0; cnt < NUM_PANIC_TRIGGERS; cnt++ ) { @@ -1426,7 +1430,7 @@ BOOLEAN ExecuteOverhead( ) } else { - CalcInteractiveObjectAPs( sGridNo, pStructure, &sAPCost, &sBPCost ); + CalcInteractiveObjectAPs( pSoldier, sGridNo, pStructure, &sAPCost, &sBPCost ); // SANDRO - added argument if ( EnoughPoints( pSoldier, sAPCost, sBPCost , TRUE ) ) { @@ -1702,19 +1706,6 @@ BOOLEAN ExecuteOverhead( ) } } } - //if(is_client)//hayden - //{ - // if(pSoldier->flags.fIsSoldierDelayed==TRUE) - // { - // continue;//in position but waiting on other clients - // } - // else - // { - // //ovh_advance=false; - // pSoldier->flags.fIsSoldierDelayed=TRUE; - // request_ovh(pSoldier->ubID); - // } - //} } if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_PAUSEANIMOVE ) ) @@ -1969,7 +1960,8 @@ void HandleLocateToGuyAsHeWalks( SOLDIERTYPE *pSoldier ) } } - +#pragma optimize("gpt",on) +__forceinline BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLEAN fInitialMove, UINT16 usAnimState ) { INT16 sAPCost; @@ -2028,15 +2020,16 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE // Do we have APs? // CHRISL: Added penalty for jumping a fence while wearing a backpack // Do we have APs? + // SANDRO - changed the static values to precise calculation here if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true) { - sAPCost = APBPConstants[AP_JUMPFENCEBPACK]; - sBPCost = APBPConstants[BP_JUMPFENCEBPACK]; + sAPCost = GetAPsToJumpFence( pSoldier, TRUE ); + sBPCost = GetBPsToJumpFence( pSoldier, TRUE ); } else { - sAPCost = APBPConstants[AP_JUMPFENCE]; - sBPCost = APBPConstants[BP_JUMPFENCE]; + sAPCost = GetAPsToJumpFence( pSoldier, FALSE ); + sBPCost = GetBPsToJumpFence( pSoldier, FALSE ); } @@ -2199,8 +2192,14 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE // we reuse the boobytrap gridno variable here gsBoobyTrapGridNo = sMineGridNo; gpBoobyTrapSoldier = pSoldier; - SetStopTimeQuoteCallback( MineSpottedDialogueCallBack ); - TacticalCharacterDialogue( pSoldier, QUOTE_SUSPICIOUS_GROUND ); + // silversurfer: if TRUE the merc won't comment that he found a mine, otherwise old behaviour + if (gGameExternalOptions.fMineSpottedNoTalk ) + MineSpottedDialogueCallBack (); + else + { + SetStopTimeQuoteCallback( MineSpottedDialogueCallBack ); + TacticalCharacterDialogue( pSoldier, QUOTE_SUSPICIOUS_GROUND ); + } } } else @@ -2418,7 +2417,7 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE else // ATE; First check for profile // Forgetful guy might forget his path - if ( (pSoldier->bTeam == gbPlayerNum) && ( pSoldier->ubProfile != NO_PROFILE ) && gMercProfiles[pSoldier->ubProfile].bPersonalityTrait == FORGETFUL ) + if ( (pSoldier->bTeam == gbPlayerNum) && ( pSoldier->ubProfile != NO_PROFILE ) && gMercProfiles[pSoldier->ubProfile].bDisability == FORGETFUL ) { if ( pSoldier->ubNumTilesMovesSinceLastForget < 255 ) { @@ -2616,7 +2615,16 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving ) INT32 sMineGridNo; UINT8 ubVolume; - + //uses Lua + PROFILLUA_sSectorX = pSoldier->sSectorX; + PROFILLUA_sSectorY = pSoldier->sSectorY; + PROFILLUA_bSectorZ = pSoldier->bSectorZ; + PROFILLUA_Level = pSoldier->pathing.bLevel; + PROFILLUA_ubID = pSoldier->ubID; + PROFILLUA_sGridNo = pSoldier->sGridNo; + PROFILLUA_ubDirectiono = pSoldier->ubDirection; + PROFILLUA_bTeam = pSoldier->bTeam; + // ATE; Handle bad guys, as they fade, to cancel it if // too long... // ONLY if fading IN! @@ -2810,8 +2818,14 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving ) // we reuse the boobytrap gridno variable here gsBoobyTrapGridNo = sMineGridNo; gpBoobyTrapSoldier = pSoldier; - SetStopTimeQuoteCallback( MineSpottedDialogueCallBack ); - TacticalCharacterDialogue( pSoldier, QUOTE_SUSPICIOUS_GROUND ); + // silversurfer: if TRUE the merc won't comment that he found a mine, otherwise old behaviour + if (gGameExternalOptions.fMineSpottedNoTalk ) + MineSpottedDialogueCallBack (); + else + { + SetStopTimeQuoteCallback( MineSpottedDialogueCallBack ); + TacticalCharacterDialogue( pSoldier, QUOTE_SUSPICIOUS_GROUND ); + } } } else @@ -2833,6 +2847,13 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving ) HandleSystemNewAISituation( pSoldier, FALSE ); + +#ifdef LUA_OVERHEAD + LetLuaMyCustomHandleAtNewGridNo(NULL,pSoldier->ubProfile, 0); +#else + //----------------Lua------------------------ + + if ( pSoldier->bTeam == gbPlayerNum ) { if ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__EPC) @@ -2927,6 +2948,9 @@ BOOLEAN HandleAtNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving ) break; } } + +#endif + return( TRUE ); } @@ -3095,7 +3119,7 @@ void InternalSelectSoldier( UINT16 usSoldierID, BOOLEAN fAcknowledge, BOOLEAN fF // possibly say personality quote if ( (pSoldier->bTeam == gbPlayerNum) && (pSoldier->ubProfile != NO_PROFILE && pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER) && !( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_PERSONALITY) ) { - switch ( gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait ) + switch ( gMercProfiles[ pSoldier->ubProfile ].bDisability ) { case PSYCHO: if ( Random( 50 ) == 0 ) @@ -3540,7 +3564,22 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld ) // check to see if dynamo quest is on if ( gubQuest[ QUEST_FREE_DYNAMO ] == QUESTINPROGRESS) { - EndQuest( QUEST_FREE_DYNAMO, pSoldierOld->sSectorX, pSoldierOld->sSectorY ); + // SANDRO - quest failed if Dynamo is killed + InternalEndQuest( QUEST_FREE_DYNAMO, pSoldierOld->sSectorX, pSoldierOld->sSectorY, FALSE ); + } + break; + // SANDRO - if we kill Carmen with Slay in our team, end the terrorists quest + case CARMEN : + // Carmen must have seen Slay, to finish the quest properly, he must know we betrayd him + if ( pSoldierOld->aiData.bAttitude == ATTACKSLAYONLY ) + { + pOther = FindSoldierByProfileID( SLAY, FALSE ); + if (pOther && pOther->stats.bLife && pOther->bTeam == gbPlayerNum && + pSoldierOld->sSectorX == pOther->sSectorX && pSoldierOld->sSectorY == pOther->sSectorY) + { + // Slay is in sector and alive, Carmen dead, end quest, award some exp + EndQuest( QUEST_KILL_TERRORISTS, pSoldierOld->sSectorX, pSoldierOld->sSectorY ); + } } break; case KINGPIN: @@ -3569,6 +3608,11 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld ) HandleNPCDoAction( DOREEN, NPC_ACTION_FREE_KIDS, 0 ); } break; + // SANDRO - Check if queen bitch is dead + case QUEEN: + // Muhahahahaaa, QUEST COMPLETED! Give us everything!! Exp, glory, fame! + EndQuest( QUEST_KILL_DEIDRANNA, pSoldierOld->sSectorX, pSoldierOld->sSectorY ); + break; } // Are we looking at the queen? @@ -3608,7 +3652,8 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld ) } // If the militia's killer is known - if ( pSoldierOld->ubAttackerID != NOBODY ) + // silversurfer: did the player team kill the militia? If not, militia shouldn't become hostile towards the player. + if ( pSoldierOld->ubAttackerID != NOBODY && MercPtrs[ pSoldierOld->ubAttackerID ]->bTeam == OUR_TEAM ) { // also treat this as murder - but player will never be blamed for militia death he didn't cause // HEADROCK HAM 3.6: Actually this function never runs for militia (see function for details) @@ -3679,21 +3724,49 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld ) // killing crows/cows is not worth any experience! - if ( ( pSoldierOld->ubBodyType != CROW ) && ( pSoldierOld->ubBodyType != COW ) && pSoldierOld->ubLastDamageReason != TAKE_DAMAGE_BLOODLOSS ) + if ( ( pSoldierOld->ubBodyType != CROW ) && ( pSoldierOld->ubBodyType != COW ) ) //&& pSoldierOld->ubLastDamageReason != TAKE_DAMAGE_BLOODLOSS ) // SANDRO - why not give exp for bleeding out? { - UINT8 ubAssister; + UINT8 ubAssister = NOBODY; // if it was a kill by a player's merc if (pSoldierOld->ubAttackerID != NOBODY && MercPtrs[ pSoldierOld->ubAttackerID ]->bTeam == gbPlayerNum ) { + // SANDRO - for special NPCs, you gain more experiences + UINT16 usNumExpChances = ( 10 * pSoldierOld->stats.bExpLevel ); // basic value + switch( pSoldierOld->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + usNumExpChances *= 2; // make it double for special guys + if( gGameExternalOptions.usSpecialNPCStronger > 0 ) // if set stronger, adjust the value + { + usNumExpChances += (usNumExpChances * gGameExternalOptions.usSpecialNPCStronger / 100); + } + break; + } // EXPERIENCE CLASS GAIN: Earned a kill - StatChange( MercPtrs[ pSoldierOld->ubAttackerID ], EXPERAMT, (UINT16)( 10 * pSoldierOld->stats.bExpLevel ), FALSE ); + StatChange( MercPtrs[ pSoldierOld->ubAttackerID ], EXPERAMT, usNumExpChances, FALSE ); } // JA2 Gold: if previous and current attackers are the same, the next-to-previous attacker gets the assist if (pSoldierOld->ubPreviousAttackerID == pSoldierOld->ubAttackerID) { - ubAssister = pSoldierOld->ubNextToPreviousAttackerID; + if (pSoldierOld->ubNextToPreviousAttackerID != pSoldierOld->ubAttackerID ) // SANDRO - carefully with this, if we are still one person don't do this + ubAssister = pSoldierOld->ubNextToPreviousAttackerID; } else { @@ -3744,6 +3817,7 @@ UINT8 LastActiveTeamMember( UINT8 ubTeam ) void CheckForPotentialAddToBattleIncrement( SOLDIERTYPE *pSoldier ) { +UINT16 iCounter2; // Check if we are a threat! if ( !pSoldier->aiData.bNeutral && (pSoldier->bSide != gbPlayerNum ) ) { @@ -3751,7 +3825,7 @@ void CheckForPotentialAddToBattleIncrement( SOLDIERTYPE *pSoldier ) // We need to exclude cases where a kid is not neutral anymore, but is defenceless! if ( pSoldier->bTeam == CIV_TEAM ) { - // maybe increment num enemy attacked + /* // maybe increment num enemy attacked switch ( pSoldier->ubCivilianGroup ) { case REBEL_CIV_GROUP: @@ -3766,6 +3840,33 @@ void CheckForPotentialAddToBattleIncrement( SOLDIERTYPE *pSoldier ) // nope! break; } + + //New Group by Jazz + for( iCounter2 = UNNAMED_CIV_GROUP_15; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if (pSoldier->ubCivilianGroup == iCounter2) + { + if ( FindObjClass( pSoldier, IC_WEAPON ) != NO_SLOT ) + { + gTacticalStatus.bNumFoughtInBattle[ pSoldier->bTeam ]++; + } + + } + } + */ + + //New Group by Jazz + for( iCounter2 = REBEL_CIV_GROUP; iCounter2 < NUM_CIV_GROUPS; iCounter2++ ) + { + if ( pSoldier->ubCivilianGroup == iCounter2 && zCivGroupName[iCounter2].AddToBattle == TRUE ) + { + if ( FindObjClass( pSoldier, IC_WEAPON ) != NO_SLOT ) + { + gTacticalStatus.bNumFoughtInBattle[ pSoldier->bTeam ]++; + } + } + } + } else { @@ -5437,14 +5538,17 @@ void HandleTeamServices( UINT8 ubTeamNum ) if ( pTargetSoldier->ubServiceCount ) { + BOOLEAN fThrowMessage = (pTargetSoldier->bBleeding ? TRUE : FALSE); // added by SANDRO + usKitPts = TotalPoints( &(pTeamSoldier->inv[ HANDPOS ] ) ); uiPointsUsed = pTeamSoldier->SoldierDressWound( pTargetSoldier, usKitPts, usKitPts ); // Determine if they are all banagded - if ( !pTargetSoldier->bBleeding && pTargetSoldier->stats.bLife >= OKLIFE ) + if ( !pTargetSoldier->bBleeding && pTargetSoldier->stats.bLife >= OKLIFE && !(pTargetSoldier->iHealableInjury >= 100 && pTeamSoldier->fDoingSurgery)) // check for surgery added by SANDRO { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ MERC_IS_ALL_BANDAGED_STR ], pTargetSoldier->name ); + if ( fThrowMessage ) // throw message "all bandaged" only if there was something to bandage - SANDRO + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ MERC_IS_ALL_BANDAGED_STR ], pTargetSoldier->name ); // Cancel all services for this guy! pTargetSoldier->ReceivingSoldierCancelServices( ); @@ -5523,14 +5627,17 @@ void HandlePlayerServices( SOLDIERTYPE *pTeamSoldier ) if ( pTargetSoldier->ubServiceCount ) { + BOOLEAN fThrowMessage = (pTargetSoldier->bBleeding ? TRUE : FALSE); // added by SANDRO + usKitPts = TotalPoints( &(pTeamSoldier->inv[ HANDPOS ] ) ); uiPointsUsed = pTeamSoldier->SoldierDressWound( pTargetSoldier, usKitPts, usKitPts ); // Determine if they are all banagded - if ( !pTargetSoldier->bBleeding && pTargetSoldier->stats.bLife >= OKLIFE ) + if ( !pTargetSoldier->bBleeding && pTargetSoldier->stats.bLife >= OKLIFE && !(pTargetSoldier->iHealableInjury >= 100 && pTeamSoldier->fDoingSurgery)) // check for surgery added by SANDRO { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ MERC_IS_ALL_BANDAGED_STR ], pTargetSoldier->name ); + if ( fThrowMessage ) // throw message "all bandaged" only if there was something to bandage - SANDRO + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[ MERC_IS_ALL_BANDAGED_STR ], pTargetSoldier->name ); // Cancel all services for this guy! pTargetSoldier->ReceivingSoldierCancelServices( ); @@ -5552,16 +5659,24 @@ void HandlePlayerServices( SOLDIERTYPE *pTeamSoldier ) } else { - bSlot = FindFirstAidKit ( pTeamSoldier); - if ( bSlot == NO_SLOT ) + // SANDRO - on surgery, only search for medic bags + if (pTeamSoldier->fDoingSurgery) { bSlot = FindMedKit ( pTeamSoldier ); } + else + { + bSlot = FindFirstAidKit ( pTeamSoldier); + if ( bSlot == NO_SLOT ) + { + bSlot = FindMedKit ( pTeamSoldier ); + } + } } if ( bSlot != NO_SLOT ) { - SwapObjs( pTeamSoldier, HANDPOS, bSlot, TRUE ); + SwapObjs( pTeamSoldier, HANDPOS, bSlot, FALSE ); // SANDRO - changed to FALSE, so we can continue in the service (???) } else { @@ -5591,7 +5706,8 @@ void CommonEnterCombatModeCode( ) //gTacticalStatus.ubAttackBusyCount = 0; // Reset num enemies fought flag... - memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); + // SANDRO - removed from here + //memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); gTacticalStatus.ubLastBattleSectorX = (UINT8) gWorldSectorX; gTacticalStatus.ubLastBattleSectorY = (UINT8) gWorldSectorY; gTacticalStatus.fLastBattleWon = FALSE; @@ -5626,7 +5742,8 @@ void CommonEnterCombatModeCode( ) pSoldier->flags.uiStatusFlags &= ~SOLDIER_UNDERAICONTROL; // Check if this guy is an enemy.... - CheckForPotentialAddToBattleIncrement( pSoldier ); + // SANDRO - don't check this here, we've already checked that once + //CheckForPotentialAddToBattleIncrement( pSoldier ); // If guy is sleeping, wake him up! if ( pSoldier->flags.fMercAsleep == TRUE ) @@ -5835,7 +5952,8 @@ void ExitCombatMode( ) } // Change music modes - gfForceMusicToTense = TRUE; + // unused + //gfForceMusicToTense = TRUE; SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT ); @@ -6205,7 +6323,9 @@ BOOLEAN CheckForEndOfCombatMode( BOOLEAN fIncrementTurnsNotSeen ) // Double check by seeing if we have any active enemies in sector! if ( NumEnemyInSectorNotDeadOrDying( ) > 0 ) { - SayQuoteFromAnyBodyInSector( QUOTE_WARNING_OUTSTANDING_ENEMY_AFTER_RT ); + //comm by ddd SayQuoteFromAnyBodyInSector( QUOTE_WARNING_OUTSTANDING_ENEMY_AFTER_RT ); + if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) + SayQuoteFromAnyBodyInSector( QUOTE_WARNING_OUTSTANDING_ENEMY_AFTER_RT ); } } } @@ -6218,7 +6338,8 @@ BOOLEAN CheckForEndOfCombatMode( BOOLEAN fIncrementTurnsNotSeen ) */ // Begin tense music.... - gfForceMusicToTense = TRUE; + // unused + //gfForceMusicToTense = TRUE; SetMusicMode( MUSIC_TACTICAL_ENEMYPRESENT ); return( TRUE ); @@ -6238,7 +6359,7 @@ void DeathNoMessageTimerCallback( void ) if (!isOwnTeamWipedOut) { ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[40] ); - if(!DISABLE_SPEC_MODE) + if(!cDisableSpectatorMode) { gTacticalStatus.uiFlags |= SHOW_ALL_MERCS;//hayden ScreenMsg( FONT_YELLOW, MSG_CHAT, MPClientMessage[41] ); @@ -6367,6 +6488,8 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) // Set enemy presence to false // This is safe 'cause we're about to unload the friggen sector anyway.... gTacticalStatus.fEnemyInSector = FALSE; + // SANDRO - reset number of enemies here + memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); // If here, the battle has been lost! UnSetUIBusy( (UINT8)gusSelectedSoldier ); @@ -6380,6 +6503,13 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) HandleMoraleEvent( NULL, MORALE_HEARD_BATTLE_LOST, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_BATTLE_LOST, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + // SANDRO - end quest if cleared the sector after interrogation (sector N7 by Meduna) + if ( gWorldSectorX == 7 && gWorldSectorY == 14 && gbWorldSectorZ == 0 && gubQuest[ QUEST_INTERROGATION ] == QUESTINPROGRESS ) + { + // Quest failed + InternalEndQuest( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY, FALSE ); + } + // Play death music SetMusicMode( MUSIC_TACTICAL_DEATH ); @@ -6475,7 +6605,13 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) { if( pTeamSoldier->bTeam == gbPlayerNum ) { - gMercProfiles[pTeamSoldier->ubProfile].usBattlesFought++; + // SANDRO - records - num tactical battles + gMercProfiles[pTeamSoldier->ubProfile].records.usBattlesTactical++; + // largest battle experienced + if (gMercProfiles[pTeamSoldier->ubProfile].records.usLargestBattleFought < ( gTacticalStatus.bNumFoughtInBattle[ ENEMY_TEAM ] + gTacticalStatus.bNumFoughtInBattle[ CREATURE_TEAM ] + gTacticalStatus.bNumFoughtInBattle[ CIV_TEAM ] )) + { + gMercProfiles[pTeamSoldier->ubProfile].records.usLargestBattleFought = ( gTacticalStatus.bNumFoughtInBattle[ ENEMY_TEAM ] + gTacticalStatus.bNumFoughtInBattle[ CREATURE_TEAM ] + gTacticalStatus.bNumFoughtInBattle[ CIV_TEAM ] ); + } // If this guy is OKLIFE & not standing, make stand.... if ( pTeamSoldier->stats.bLife >= OKLIFE && !pTeamSoldier->bCollapsed ) @@ -6491,19 +6627,21 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) gfUIStanceDifferent = TRUE; pTeamSoldier->bStealthMode = FALSE; fInterfacePanelDirty = DIRTYLEVEL2; - - if ( gAnimControl[ pTeamSoldier->usAnimState ].ubHeight != ANIM_STAND ) - { - pTeamSoldier->ChangeSoldierStance( ANIM_STAND ); - } - else - { - // If they are aiming, end aim! - usAnimState = PickSoldierReadyAnimation( pTeamSoldier, TRUE ); - - if ( usAnimState != INVALID_ANIMATION ) + //DBrot: Stance change + if (gGameExternalOptions.fStandUpAfterBattle){ + if ( gAnimControl[ pTeamSoldier->usAnimState ].ubHeight != ANIM_STAND ) { - pTeamSoldier->EVENT_InitNewSoldierAnim( usAnimState, 0, FALSE ); + pTeamSoldier->ChangeSoldierStance( ANIM_STAND ); + } + else + { + // If they are aiming, end aim! + usAnimState = PickSoldierReadyAnimation( pTeamSoldier, TRUE ); + + if ( usAnimState != INVALID_ANIMATION ) + { + pTeamSoldier->EVENT_InitNewSoldierAnim( usAnimState, 0, FALSE ); + } } } } @@ -6531,6 +6669,12 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) if (!is_networked) ShouldBeginAutoBandage( ); } + // SANDRO - end quest if cleared the sector after interrogation (sector N7 by Meduna) + if ( gWorldSectorX == 7 && gWorldSectorY == 14 && gbWorldSectorZ == 0 && gubQuest[ QUEST_INTERROGATION ] == QUESTINPROGRESS ) + { + // Complete quest + EndQuest( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY ); + } // Say battle end quote.... @@ -6556,6 +6700,8 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) } } + // SANDRO - reset number of enemies here + memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); } else { @@ -6583,7 +6729,14 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) pTeamSoldier->aiData.bNewSituation = FALSE; pTeamSoldier->aiData.bOrders = STATIONARY; if ( pTeamSoldier->stats.bLife < OKLIFE ) + { + // SANDRO - the insta-healable value for doctor trait check + pTeamSoldier->iHealableInjury -= ((OKLIFE - pTeamSoldier->stats.bLife) * 100); + if (pTeamSoldier->iHealableInjury < 0) + pTeamSoldier->iHealableInjury = 0; + pTeamSoldier->stats.bLife = OKLIFE; + } pTeamSoldier->bBleeding = 0; // let's think, the autobandage was done for the militia too } @@ -7183,7 +7336,16 @@ BOOLEAN KillIncompacitatedEnemyInSector( ) if ( !pTeamSoldier->aiData.bNeutral && (pTeamSoldier->bSide != gbPlayerNum ) ) { // KIll...... - pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE ); + // SANDRO - if the soldier is bleeding out, consider this damage as done by the last attacker + if ( pTeamSoldier->ubAttackerID != NOBODY ) + pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubAttackerID, NOWHERE, 0, TRUE ); + else if ( pTeamSoldier->ubPreviousAttackerID != NOBODY ) + pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubPreviousAttackerID, NOWHERE, 0, TRUE ); + else if ( pTeamSoldier->ubNextToPreviousAttackerID != NOBODY ) + pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubNextToPreviousAttackerID, NOWHERE, 0, TRUE ); + else + pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE ); + fReturnVal = TRUE; } } @@ -7237,17 +7399,28 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier ) if ( pSoldier->ubProfile != NO_PROFILE ) { - // change tolerance based on attitude - switch ( gMercProfiles[ pSoldier->ubProfile ].bAttitude ) + // SANDRO - check for character traits + if ( gGameOptions.fNewTraitSystem ) { - case ATT_AGGRESSIVE: - bTolerance += 2; - break; - case ATT_COWARD: - bTolerance += -2; - break; - default: - break; + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_INTELLECTUAL ) + bTolerance += -2; + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + bTolerance += 2; + } + else + { + // change tolerance based on attitude + switch ( gMercProfiles[ pSoldier->ubProfile ].bAttitude ) + { + case ATT_AGGRESSIVE: + bTolerance += 2; + break; + case ATT_COWARD: + bTolerance += -2; + break; + default: + break; + } } } else @@ -7290,6 +7463,19 @@ INT8 CalcSuppressionTolerance( SOLDIERTYPE * pSoldier ) } } + // SANDRO - STOMP traits - squadleader's bonus to suppression tolerance + if ( gGameOptions.fNewTraitSystem && IS_MERC_BODY_TYPE(pSoldier) && + (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) ) + { + UINT8 ubNumberOfSL = GetSquadleadersCountInVicinity( pSoldier, FALSE, FALSE ); + // Also take ourselves into account + if ((ubNumberOfSL < gSkillTraitValues.ubSLMaxBonuses) && HAS_SKILL_TRAIT( pSoldier, SQUADLEADER_NT )) + { + ubNumberOfSL = max( gSkillTraitValues.ubSLMaxBonuses, (ubNumberOfSL + NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT )) ); + } + bTolerance += (bTolerance * gSkillTraitValues.ubSLOverallSuppresionBonusPercent * ubNumberOfSL / 100); + } + bTolerance = __max(bTolerance, gGameExternalOptions.ubSuppressionToleranceMin); bTolerance = __min(bTolerance, gGameExternalOptions.ubSuppressionToleranceMax); @@ -7398,6 +7584,8 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) bShockLimit = MAXIMUM_SUPPRESSION_SHOCK; // The amount of shock received depends on how many APs we've lost - Every AP lost will cause one // point of shock. This is then divided by 4 if using the 100AP system. + if (uiShockPerAPLossDivisor == 0) // SANDRO - check if we are not going to divide by zero + uiShockPerAPLossDivisor = 4; // set to default value in this case bShockValue = ubPointsLost / uiShockPerAPLossDivisor; bShockValue = __max(0,bShockValue); @@ -7432,7 +7620,26 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) fCower = false; if ( gGameExternalOptions.usSuppressionShockEffect > 0 ) { - if (pSoldier->aiData.bShock >= bTolerance) + // SANDRO - STOMP traits + INT8 bShockForCower = pSoldier->aiData.bShock; + if ( gGameOptions.fNewTraitSystem ) + { + // Squadleader's resistance to cowering + if ( HAS_SKILL_TRAIT( pSoldier, SQUADLEADER_NT )) + { + bShockForCower = (INT8)((bShockForCower * (100 - gSkillTraitValues.ubSLFearResistance * NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT )) /100) + 0.5); + } + // Check for character traits + if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_INTELLECTUAL ) + { + bShockForCower = (INT8)((bShockForCower * 23 / 20 ) + 0.5); // +15% as shock + } + else if ( gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + { + bShockForCower = (INT8)((bShockForCower * 17 / 20 ) + 0.5); // -15% as shock + } + } + if (bShockForCower >= bTolerance) { fCower = true; @@ -7467,13 +7674,13 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) // can't change stance below prone! break; case ANIM_CROUCH: - if (ubPointsLost >= APBPConstants[AP_PRONE] && IsValidStance( pSoldier, ANIM_PRONE ) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) + if (ubPointsLost >= GetAPsProne(pSoldier, TRUE) && IsValidStance( pSoldier, ANIM_PRONE ) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) // SANDRO - changed to GetAPsProne { sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL ); // HEADROCK: Added cowering. if (TileIsOutOfBounds(sClosestOpponent) || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower) { - ubPointsLost -= APBPConstants[AP_PRONE]; + ubPointsLost -= GetAPsProne(pSoldier, TRUE); ubNewStance = ANIM_PRONE; } } @@ -7484,7 +7691,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) // can't change stance here! break; } - else if (ubPointsLost >= (APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) ) + else if (ubPointsLost >= (GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE)) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) ) // SANDRO - changed to GetAPsCrouch/Prone { sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL ); // HEADROCK: Added cowering. @@ -7507,7 +7714,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) ubNewStance = ANIM_CROUCH; } } - else if ( ubPointsLost >= APBPConstants[AP_CROUCH] && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) ) + else if ( ubPointsLost >= GetAPsCrouch(pSoldier, TRUE) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) ) // SANDRO - changed to GetAPsCrouch { // crouch! ubNewStance = ANIM_CROUCH; @@ -7668,11 +7875,16 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp } } - if ( (pTarget->bTeam == MILITIA_TEAM) && (pTarget->bSide == gbPlayerNum) ) + // silversurfer: if militia was attacked and not already hostile make them hostile towards the player + // but only IF the player was the attacker! + if ( (pTarget->bTeam == MILITIA_TEAM) && (pSoldier->bTeam == OUR_TEAM) ) { // HEADROCK HAM 3.6: INI setting controls their response { - if (gGameExternalOptions.ubCanMilitiaBecomeHostile == 2) + if (pTarget->flags.fIntendedTarget // Must be intentional + && gGameExternalOptions.ubCanMilitiaBecomeHostile == 2 // INI setting + && pTarget->bSide == gbPlayerNum // Must not be hostile by now + ) { // rebel militia attacked by the player! MilitiaChangesSides(); @@ -8161,7 +8373,9 @@ SOLDIERTYPE *InternalReduceAttackBusyCount( ) // Display quote! if ( !AM_AN_EPC( MercPtrs[ gTacticalStatus.ubItemsSeenOnAttackSoldier ] ) ) { - TacticalCharacterDialogueWithSpecialEvent( MercPtrs[ gTacticalStatus.ubItemsSeenOnAttackSoldier ], (UINT16)( QUOTE_SPOTTED_SOMETHING_ONE + Random( 2 ) ), DIALOGUE_SPECIAL_EVENT_SIGNAL_ITEM_LOCATOR_START, gTacticalStatus.usItemsSeenOnAttackGridNo, 0 ); + //ddd TacticalCharacterDialogueWithSpecialEvent( MercPtrs[ gTacticalStatus.ubItemsSeenOnAttackSoldier ], (UINT16)( QUOTE_SPOTTED_SOMETHING_ONE + Random( 2 ) ), DIALOGUE_SPECIAL_EVENT_SIGNAL_ITEM_LOCATOR_START, gTacticalStatus.sItemsSeenOnAttackGridNo, 0 ); + if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) + TacticalCharacterDialogueWithSpecialEvent( MercPtrs[ gTacticalStatus.ubItemsSeenOnAttackSoldier ], (UINT16)( QUOTE_SPOTTED_SOMETHING_ONE + Random( 2 ) ), DIALOGUE_SPECIAL_EVENT_SIGNAL_ITEM_LOCATOR_START, gTacticalStatus.usItemsSeenOnAttackGridNo, 0 ); } else { @@ -8544,7 +8758,7 @@ void EndBattleWithUnconsciousGuysCallback( UINT8 bExitValue ) else { ScreenMsg( FONT_LTGREEN, MSG_CHAT, MPClientMessage[40] ); - if(!DISABLE_SPEC_MODE) + if(!cDisableSpectatorMode) { gTacticalStatus.uiFlags |= SHOW_ALL_MERCS;//hayden ScreenMsg( FONT_YELLOW, MSG_CHAT, MPClientMessage[41] ); @@ -8916,6 +9130,7 @@ INT8 CheckStatusNearbyFriendlies( SOLDIERTYPE *pSoldier ) UINT16 usEffectiveRangeToLeader = 0; INT16 usBestLeader = 0; INT16 usFriendBonus = 0; + UINT8 ubLevelDifference = 0; // Run through each friendly. for ( UINT8 iCounter = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID ; iCounter <= gTacticalStatus.Team[ pSoldier->bTeam ].bLastID ; iCounter ++ ) @@ -8924,27 +9139,39 @@ INT8 CheckStatusNearbyFriendlies( SOLDIERTYPE *pSoldier ) // Make sure that character is alive, not too shocked, and conscious, and of higher experience level // than the character being suppressed. if (pLeader != pSoldier && pLeader->bActive && pLeader->aiData.bShock < pLeader->stats.bLeadership/5 && - pLeader->stats.bLife >= OKLIFE && pLeader->stats.bExpLevel >= pSoldier->stats.bExpLevel) + pLeader->stats.bLife >= OKLIFE ) { + ubLevelDifference = (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel ); // Calculate character's leadership and range/3 usEffectiveLeadership = ((EffectiveLeadership( pLeader ) - 25) / 15); usEffectiveRangeToLeader = PythSpacesAway( pSoldier->sGridNo, pLeader->sGridNo ) / 3; - // If leader is within range of his leadership stat - if (usEffectiveRangeToLeader <= usEffectiveLeadership+1) - { - // The difference in experience level is important! - usEffectiveLeadership += (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel); - // Reduce effective leadership with every 3 tiles of distance - usEffectiveLeadership -= usEffectiveRangeToLeader-1; - // If this is the best leader we've seen so far, - if (usEffectiveLeadership > usBestLeader) + // SANDRO - add effective leadership and level to determine if we can help our friend to feel better :) + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pLeader, SQUADLEADER_NT ) ) + { + ubLevelDifference += (gSkillTraitValues.ubSLEffectiveLevelAsStandby * NUM_SKILL_TRAITS( pLeader, SQUADLEADER_NT )); + usEffectiveLeadership += (gSkillTraitValues.ubSLEffectiveLevelAsStandby * NUM_SKILL_TRAITS( pLeader, SQUADLEADER_NT )); + } + + if ( ubLevelDifference >= 0 ) + { + // If leader is within range of his leadership stat + if (usEffectiveRangeToLeader <= usEffectiveLeadership+1) { - // Set this as the best leader - usBestLeader = usEffectiveLeadership; + // The difference in experience level is important! + usEffectiveLeadership += ubLevelDifference; + // Reduce effective leadership with every 3 tiles of distance + usEffectiveLeadership -= usEffectiveRangeToLeader-1; + + // If this is the best leader we've seen so far, + if (usEffectiveLeadership > usBestLeader) + { + // Set this as the best leader + usBestLeader = usEffectiveLeadership; + } + // Friends within range always give at least one tolerance bonus point. + usFriendBonus += 1; } - // Friends within range always give at least one tolerance bonus point. - usFriendBonus += 1; } } // Incapacitated or heavily suppressed friends will not be good for our tolerance! @@ -8959,6 +9186,12 @@ INT8 CheckStatusNearbyFriendlies( SOLDIERTYPE *pSoldier ) usEffectiveLeadership = (pLeader->stats.bExpLevel - pSoldier->stats.bExpLevel) / __max(1,(usEffectiveRangeToLeader/2)); usFriendBonus -= __max(1, usEffectiveLeadership); } + // SANDRO - however, dead squadleader is very bad for our psychics + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pLeader, SQUADLEADER_NT ) && + ( pLeader->flags.uiStatusFlags & SOLDIER_DEAD ) && usEffectiveRangeToLeader <= 10 ) + { + usFriendBonus -= ( gSkillTraitValues.ubSLDeathMoralelossMultiplier * NUM_SKILL_TRAITS( pLeader, SQUADLEADER_NT )); + } } } diff --git a/Tactical/Overhead.h b/Tactical/Overhead.h index cff37107..bb14dfd1 100644 --- a/Tactical/Overhead.h +++ b/Tactical/Overhead.h @@ -179,6 +179,8 @@ typedef struct UINT8 ubMorePadding; UINT16 sCreatureTenseQuoteDelay; UINT32 uiCreatureTenseQuoteLastUpdate; + // SANDRO - added this + UINT8 ubLastRequesterSurgeryTargetID; // PADDING GONE!!!!! diff --git a/Tactical/PATHAI.H b/Tactical/PATHAI.H index 12f977e3..93ca437a 100644 --- a/Tactical/PATHAI.H +++ b/Tactical/PATHAI.H @@ -278,6 +278,12 @@ extern UINT8 gubGlobalPathFlags; #define TRAVELCOST_WALL 254 #define TRAVELCOST_EXITGRID 255 +///ddd{okno +#define TRAVELCOST_JUMPABLEWINDOW 46 +#define TRAVELCOST_JUMPABLEWINDOW_N 47 +#define TRAVELCOST_JUMPABLEWINDOW_W 48 +///dddokno} + #define TRAVELCOST_TRAINTRACKS 30 #define TRAVELCOST_DIRTROAD 9 #define TRAVELCOST_PAVEDROAD 9 diff --git a/Tactical/PATHAI.cpp b/Tactical/PATHAI.cpp index 80e46de2..45dad61e 100644 --- a/Tactical/PATHAI.cpp +++ b/Tactical/PATHAI.cpp @@ -41,9 +41,13 @@ #include "keys.h" #include "gamesettings.h" #include "Buildings.h" + #include "soldier profile.h" // added by SANDRO #endif #include "connect.h" #include "PathAIDebug.h" + +#include "LOS.h" //ddd + //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; @@ -109,7 +113,7 @@ typedef struct path_s path_t; struct trail_s { - INT16 nextLink; + INT32 nextLink; INT8 stepDir; INT8 fFlags; INT32 sGridNo; @@ -496,11 +500,29 @@ void AStarPathfinder::ResetAStarList() // SetAStarStatus(node, AStar_Init); // SetAStarG(node, 0); //} - for (INT32 node = 0; node < WORLD_MAX; node++) + //comm by ddd{ + //for (INT16 node = 0; node < WORLD_MAX; node++) + //{ + // SetAStarStatus(node, AStar_Init); //comm by ddd + // SetAStarG(node, 0); //comm by ddd + //} + //comm by ddd} + + //ddd{ + + INT32 node; + for (node = 0; node < (WORLD_MAX & ~3); node+=4) //ddd { - SetAStarStatus(node, AStar_Init); - SetAStarG(node, 0); + AStarData[node].status = AStarData[node+1].status + = AStarData[node+2].status = AStarData[node+3].status = AStar_Init; + + AStarData[node+3].cost = AStarData[node+2].cost = + AStarData[node+1].cost = AStarData[node].cost = 0; } + for(node=(WORLD_MAX & ~3); node < WORLD_MAX; node++) + {AStarData[node].status = AStar_Init; AStarData[node].cost = 0;} + ////ddd} + //ClosedList.clear(); OpenHeap.clear(); @@ -804,13 +826,17 @@ int AStarPathfinder::GetPath(SOLDIERTYPE *s , trackNode.resize(1,current); while (current != -1) { - sizePath += GetNumSteps( current); + //sizePath += GetNumSteps( current); //comm by ddd + sizePath +=AStarData[current].numSteps; while (sizePath > MAX_PATH_LIST_SIZE) { - sizePath -= GetNumSteps( parent); - parent = GetAStarParent( parent); + //sizePath -= GetNumSteps( parent);//comm by ddd + sizePath -=AStarData[parent].numSteps; + //parent = GetAStarParent( parent);//comm by ddd + parent = AStarData[parent].parent; } - current = GetAStarParent( current); + //current = GetAStarParent( current); + current = AStarData[current].parent ; for(unsigned int i = 0; i TopHeap(StartNode, 0); @@ -1095,6 +1122,11 @@ void AStarPathfinder::ExecuteAStarLogic() continue; } + //dddokno ;) + //if (gubWorldMovementCosts[CurrentNode][direction][pSoldier->pathing.bLevel] == TRAVELCOST_JUMPABLEWINDOW) + // continue; + + if (gubWorldMovementCosts[CurrentNode][direction][pSoldier->pathing.bLevel] == TRAVELCOST_FENCE) { SetAStarStatus(CurrentNode, AStar_Closed); @@ -1256,7 +1288,7 @@ INT16 AStarPathfinder::CalcStartingAP() { if ( movementMode == RUNNING && pSoldier->usAnimState != RUNNING ) { - startingAPCost = startingAPCost - APBPConstants[AP_START_RUN_COST]; + startingAPCost = startingAPCost - GetAPsStartRun( pSoldier ); // changed by SANDRO } } return startingAPCost; @@ -1314,6 +1346,12 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction) //case TRAVELCOST_DOOR: movementAPCost = APBPConstants[AP_MOVEMENT_FLAT]; break; case TRAVELCOST_FENCE: movementAPCost = APBPConstants[AP_JUMPFENCE]; break; + ///dddokno{ + case TRAVELCOST_JUMPABLEWINDOW: + case TRAVELCOST_JUMPABLEWINDOW_N: + case TRAVELCOST_JUMPABLEWINDOW_W: + movementAPCost = APBPConstants[AP_JUMPFENCE]; break; + ///dddokno} case TRAVELCOST_OBSTACLE: default: return -1; // Cost too much to be considered! @@ -1357,6 +1395,14 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction) break; } + /////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits - Athletics trait decreases movement cost + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + { + movementAPCost = max(1, (INT16)((movementAPCost * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + /////////////////////////////////////////////////////////////////////////////////////////////// + if (terrainCost == TRAVELCOST_FENCE) { switch( movementModeToUseForAPs ) @@ -1364,12 +1410,12 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction) case RUNNING: case WALKING : // Here pessimistically assume the path will continue after hopping the fence - movementAPCost += APBPConstants[AP_CROUCH]; + movementAPCost += GetAPsCrouch( pSoldier, TRUE ); // SANDRO - changed break; case SWATTING: // Add cost to stand once there BEFORE jumping.... - movementAPCost += APBPConstants[AP_CROUCH]; + movementAPCost += GetAPsCrouch( pSoldier, TRUE ); // SANDRO - changed break; case CRAWLING: @@ -1377,6 +1423,24 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction) return -1; } } + //dddokno + else if ( terrainCost == TRAVELCOST_JUMPABLEWINDOW + || terrainCost == TRAVELCOST_JUMPABLEWINDOW_N + || terrainCost == TRAVELCOST_JUMPABLEWINDOW_W ) + { + switch(movementModeToUseForAPs) + { + case RUNNING: + case WALKING : + case SWATTING: + movementAPCost += APBPConstants[AP_CROUCH]; + break; + + default: + break; + } + } +//dddokno else if (terrainCost == TRAVELCOST_NOT_STANDING) { switch(movementModeToUseForAPs) @@ -1384,7 +1448,7 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction) case RUNNING: case WALKING : // charge crouch APs for ducking head! - movementAPCost += APBPConstants[AP_CROUCH]; + movementAPCost += GetAPsCrouch( pSoldier, TRUE ); // SANDRO - changed break; default: @@ -1395,7 +1459,7 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction) { // Uh, there IS a cost to close the door too! // Then if the door has to be unlocked to open there's the cost of locking and unlocking. - movementAPCost += APBPConstants[AP_OPEN_DOOR] + APBPConstants[AP_OPEN_DOOR]; + movementAPCost += GetAPsToOpenDoor( pSoldier ) + GetAPsToOpenDoor( pSoldier ); // changed by SANDRO fGoingThroughDoor = FALSE; } return movementAPCost; @@ -1454,6 +1518,24 @@ int AStarPathfinder::CalcG(int* pPrevCost) nextCost = gTileTypeMovementCost[ gpWorldLevelData[ CurrentNode ].ubTerrainID ]; } } + + //dddokno { 2 1 . + //2. . . + else if ( nextCost == TRAVELCOST_JUMPABLEWINDOW + || nextCost == TRAVELCOST_JUMPABLEWINDOW_N + || nextCost == TRAVELCOST_JUMPABLEWINDOW_W) + { + + // don't let anyone path diagonally through doors! + if (IsDiagonal(direction) == true) + { + return -1; + } + nextCost = gTileTypeMovementCost[ gpWorldLevelData[ CurrentNode ].ubTerrainID ];//? + + } + //dddokno } + else if ( nextCost == TRAVELCOST_FENCE && fNonFenceJumper ) { return -1; @@ -2242,6 +2324,51 @@ bool AStarPathfinder::WantToTraverse() { return false; } + + ///ddd{ + if(gGameExternalOptions.bNewTacticalAIBehavior) + { + // . : 80% ? + if ( ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) ) + && pSoldier->bTeam == ENEMY_TEAM + //&& IsCorpseAtGridNo( CurrentNode, pSoldier->pathing.bLevel ) + && gubIsCorpseThere[CurrentNode] + ) + return false; + + //from niht ops // AI , + if( ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) ) + && pSoldier->bTeam == ENEMY_TEAM && pSoldier->ubProfile == NO_PROFILE + && pSoldier->aiData.bAction != AI_ACTION_LEAVE_WATER_GAS + //&& (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE + //|| ( (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY + // || pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR) + // && (BOOLEAN)(Random( 100 ) < 50) )) + //&& InLightAtNight((INT16)CurrentNode, gpWorldLevelData[ CurrentNode ].sHeight) + && gubWorldTileInLight[CurrentNode] + && gubMerkCanSeeThisTile[CurrentNode] + ) + { + return false; + //ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, L"svet!" ); + /*INT32 tcnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; + SOLDIERTYPE *tS; + // look for all mercs on the same team, + for ( tS = MercPtrs[ tcnt ]; tcnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; tcnt++,tS++ ) + { + if ( tS->stats.bLife >= OKLIFE && tS->sGridNo != NOWHERE && tS->bInSector ) + if ( SoldierTo3DLocationLineOfSightTest( + tS, tS->sGridNo, pSoldier->pathing.bLevel, 3, + TRUE, CALC_FROM_WANTED_DIR )) + { + //if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE ) + return false; + //else if ( Chance(35) ) return false; + } + }*/ + } + } + ///ddd} return true; }//end CanTraverse @@ -2344,7 +2471,14 @@ INT32 FindBestPath(SOLDIERTYPE *s , INT32 sDestination, INT8 ubLevel, INT16 usMo s->sPlotSrcGrid = s->sGridNo; #ifdef USE_ASTAR_PATHS +//ddd +CHAR8 errorBuf[511]; UINT32 b,e; +b=GetJA2Clock();//return s->sGridNo+6; + int retVal = ASTAR::AStarPathfinder::GetInstance().GetPath(s, sDestination, ubLevel, usMovementMode, bCopy, fFlags); + + e=GetJA2Clock();sprintf(errorBuf, "timefind bestpath= %d",e-b );LiveMessage(errorBuf); + if (retVal || TileIsOutOfBounds(sDestination)) { return retVal; } @@ -3322,10 +3456,11 @@ if(!GridNoOnVisibleWorldTile(iDestination)) // break; case TRAVELCOST_FENCE : - if((UsingNewInventorySystem() == true) && s->inv[BPACKPOCKPOS].exists() == true) - ubAPCost = APBPConstants[AP_JUMPFENCEBPACK]; + // SANDRO - slightly changed + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND ) + ubAPCost = GetAPsToJumpFence( s, TRUE ); else - ubAPCost = APBPConstants[AP_JUMPFENCE]; + ubAPCost = GetAPsToJumpFence( s, FALSE ); /* if ( sSwitchValue == TRAVELCOST_FENCE ) @@ -3390,38 +3525,42 @@ if(!GridNoOnVisibleWorldTile(iDestination)) // adjust AP cost for movement mode // CHRISL: Adjusted system to use different move costs while wearing a backpack + // SANDRO - slightly changed this to add backpack modifier after Athletics trait check switch( usMovementModeToUseForAPs ) { case RUNNING: case ADULTMONSTER_WALKING: // save on casting - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND ) - //ubAPCost = ubAPCost * 10 / ( (UINT8) (RUNDIVISORBPACK * 10)); - ubAPCost = ubAPCost + APBPConstants[AP_MODIFIER_RUN] + APBPConstants[AP_MODIFIER_PACK]; - else - //ubAPCost = (UINT8)(ubAPCost * 10 / ( (UINT8) (RUNDIVISOR * 10))); - ubAPCost = (UINT8)ubAPCost + APBPConstants[AP_MODIFIER_RUN]; - //ubAPCost = (INT16)(DOUBLE)( (sTileCost / RUNDIVISOR) ); break; + //ubAPCost = (UINT8)(ubAPCost * 10 / ( (UINT8) (RUNDIVISOR * 10))); + ubAPCost += APBPConstants[AP_MODIFIER_RUN]; + //ubAPCost = (INT16)(DOUBLE)( (sTileCost / RUNDIVISOR) ); break; break; case WALKING: case ROBOT_WALK: - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND ) - ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_PACK]); //WALKCOSTBPACK); - else - ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_WALK]); //WALKCOST); + ubAPCost += APBPConstants[AP_MODIFIER_WALK]; //WALKCOST); break; case SWATTING: - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND ) - ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_SWAT] + APBPConstants[AP_MODIFIER_PACK]); //SWATCOSTBPACK); - else - ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_SWAT]); //SWATCOST); + ubAPCost += APBPConstants[AP_MODIFIER_SWAT]; //SWATCOST); break; case CRAWLING: - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND ) - ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_CRAWL] + APBPConstants[AP_MODIFIER_PACK]); //CRAWLCOSTBPACK); - else - ubAPCost = (ubAPCost + APBPConstants[AP_MODIFIER_CRAWL]); //CRAWLCOST); + ubAPCost += APBPConstants[AP_MODIFIER_CRAWL]; //CRAWLCOST); break; + default: + ubAPCost += APBPConstants[AP_MODIFIER_WALK]; + break; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits - Athletics trait decreases movement cost + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( s, ATHLETICS_NT )) + { + ubAPCost = max(1, (INT16)((ubAPCost * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + /////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - moved backpack check to here + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND ) + { + ubAPCost += APBPConstants[AP_MODIFIER_PACK]; } if (nextCost == TRAVELCOST_FENCE) @@ -3431,13 +3570,13 @@ if(!GridNoOnVisibleWorldTile(iDestination)) case RUNNING: case WALKING : // Here pessimistically assume the path will continue after hopping the fence - ubAPCost += APBPConstants[AP_CROUCH]; + ubAPCost += GetAPsCrouch( s, TRUE ); // SANDRO - changed break; case SWATTING: // Add cost to stand once there BEFORE jumping.... - ubAPCost += APBPConstants[AP_CROUCH]; + ubAPCost += GetAPsCrouch( s, TRUE ); // SANDRO - changed break; case CRAWLING: @@ -3453,7 +3592,7 @@ if(!GridNoOnVisibleWorldTile(iDestination)) case RUNNING: case WALKING : // charge crouch APs for ducking head! - ubAPCost += APBPConstants[AP_CROUCH]; + ubAPCost += GetAPsCrouch( s, TRUE ); // SANDRO - changed break; default: @@ -3462,7 +3601,7 @@ if(!GridNoOnVisibleWorldTile(iDestination)) } else if (fGoingThroughDoor) { - ubAPCost += APBPConstants[AP_OPEN_DOOR]; + ubAPCost += GetAPsToOpenDoor( s ); // changed by SANDRO fGoingThroughDoor = FALSE; } @@ -3538,7 +3677,8 @@ if(!GridNoOnVisibleWorldTile(iDestination)) } // NOTE: on September 24, 1997, Chris went back to a diagonal bias system - if (iCnt & 1) + // SANDRO - you know this is here twice if gubNPCAPBudget is set + if (iCnt & 1 && !gubNPCAPBudget) { // moving on a diagonal //nextCost = gubDiagCost[nextCost]; @@ -3860,7 +4000,7 @@ ENDOFLOOP: if (pathQNotEmpty && pathFound) { //dnl ch53 121009 - INT16 _nextLink; + INT32 _nextLink; INT32 z, _z; _z = 0; @@ -4163,6 +4303,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl INT16 sTileCost,sPoints=0,sAnimCost=0; INT16 sPointsWalk=0,sPointsCrawl=0,sPointsRun=0,sPointsSwat=0; INT16 sExtraCostStand,sExtraCostSwat,sExtraCostCrawl; + INT16 sMovementAPsCost = 0; // added by SANDRO INT32 iLastGrid, sTempGrid; INT32 iCnt; INT32 sOldGrid=0; @@ -4187,6 +4328,9 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl sFootOrderIndex = 0; + // check for active reverse mode ( ALT key pressed ) + if ( gUIUseReverse ) + bReverse = gUIUseReverse; //gubNPCMovementMode = (UINT8) usMovementMode; // distance limit to reduce the cost of plotting a path to a location we can't reach @@ -4199,7 +4343,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl if (pSold->usAnimState != RUNNING) { // for estimation purposes, always pay penalty - sPointsRun = APBPConstants[AP_START_RUN_COST]; + sPointsRun = GetAPsStartRun( pSold ); // changed by SANDRO } // Add to points, those needed to start from different stance! @@ -4212,7 +4356,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl { if ( usMovementMode == RUNNING && pSold->usAnimState != RUNNING ) { - sPoints -= APBPConstants[AP_START_RUN_COST]; + sPoints -= GetAPsStartRun( pSold ); // changed by SANDRO } } @@ -4266,10 +4410,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl // Get switch value... sSwitchValue = gubWorldMovementCosts[ sTempGrid ][ (INT8)guiPathingData[iCnt] ][ pSold->pathing.bLevel]; - // get the tile cost for that tile based on WALKING - sTileCost = TerrainActionPoints( pSold, sTempGrid, (INT8)guiPathingData[iCnt], pSold->pathing.bLevel ); - - usMovementModeToUseForAPs = usMovementMode; + usMovementModeToUseForAPs = usMovementMode; // ATE - MAKE MOVEMENT ALWAYS WALK IF IN WATER if ( TERRAIN_IS_WATER( gpWorldLevelData[ sTempGrid ].ubTerrainID) ) @@ -4277,6 +4418,10 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl usMovementModeToUseForAPs = WALKING; } + // get the tile cost for that tile based on WALKING + sTileCost = TerrainActionPoints( pSold, sTempGrid, (INT8)guiPathingData[iCnt], pSold->pathing.bLevel ); + + if ( bIgnoreNextCost ) { bIgnoreNextCost = FALSE; @@ -4301,7 +4446,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl // Since it's AFTER.. make sure we will be moving after jump... if ( ( iCnt + 2 ) < iLastGrid ) { - sExtraCostStand += APBPConstants[AP_CROUCH]; + sExtraCostStand += GetAPsCrouch(pSold, TRUE); // changed by SANDRO // ATE: if running, charge extra point to srart again if ( usMovementModeToUseForAPs== RUNNING ) @@ -4316,7 +4461,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl case SWATTING: // Add cost to stand once there BEFORE.... - sExtraCostSwat += APBPConstants[AP_CROUCH]; + sExtraCostSwat += GetAPsCrouch(pSold, TRUE); // changed by SANDRO sPoints = sPoints + sExtraCostSwat; break; @@ -4338,7 +4483,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl case RUNNING: case WALKING : // charge crouch APs for ducking head! - sExtraCostStand += APBPConstants[AP_CROUCH]; + sExtraCostStand += GetAPsCrouch(pSold, TRUE); // changed by SANDRO break; default: @@ -4348,34 +4493,61 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl // so, then we must modify it for other movement styles and accumulate // CHRISL: Force display path to calculate AP cost differently if we're wearing a backpack + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - This part have been modified "a bit" (see also "TerrainActionPoints" in "points.cpp") + // Check movement modifiers switch( usMovementModeToUseForAPs ) { case RUNNING: - sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_RUN]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; + sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_RUN]; break; - case WALKING : - sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_WALK]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; + case WALKING: + sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK]; break; case SWATTING: - sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_SWAT]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; + sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_SWAT]; break; case CRAWLING: - sPoints += sTileCost + sExtraCostStand + APBPConstants[AP_MODIFIER_CRAWL]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; + sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_CRAWL]; break; - default : - sPoints += sPoints + sTileCost; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; + default: + sMovementAPsCost = sTileCost; break; } + + // Check for reverse mode + if ( pSold->bReverse || bReverse ) + sMovementAPsCost += APBPConstants[AP_REVERSE_MODIFIER]; + + // STOMP traits - Athletics trait decreases movement cost + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSold, ATHLETICS_NT )) + { + sMovementAPsCost = max(1, (INT16)((sMovementAPsCost * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + // Check if doors if not player's merc (they have to open them manually) + if ( sSwitchValue == TRAVELCOST_DOOR && pSold->bTeam != gbPlayerNum ) + { + sMovementAPsCost += GetAPsToOpenDoor( pSold ) + GetAPsToOpenDoor( pSold ); // Include open and close costs! + } + // Check for stealth mode + if ( pSold->bStealthMode || bStealth ) + { + // STOMP traits - Stealthy trait decreases stealth AP modifier + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSold, STEALTHY_NT )) + { + sMovementAPsCost += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + } + else + { + sMovementAPsCost += APBPConstants[AP_STEALTH_MODIFIER]; + } + } + // Check for backpack + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) + sMovementAPsCost += APBPConstants[AP_MODIFIER_PACK]; + + sPoints += sMovementAPsCost + sExtraCostStand; + /////////////////////////////////////////////////////////////////////////////////////////////////////////// } } @@ -4386,25 +4558,65 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl // ATE; TODO: Put stuff in here to allow for fact of costs other than movement ( jump fence, open door ) // CHRISL: Adjusted system to use different move costs while wearing a backpack - // store WALK cost - sPointsWalk += sTileCost + APBPConstants[AP_MODIFIER_WALK] + sExtraCostStand; + //////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - This part was modified "a bit" + sMovementAPsCost = sTileCost; + // Check for reverse mode + if ( pSold->bReverse || bReverse ) + { + sMovementAPsCost += APBPConstants[AP_REVERSE_MODIFIER]; + } + // STOMP traits - Athletics trait decreases movement cost + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSold, ATHLETICS_NT )) + { + sPointsWalk += max(1, (INT16)(((sMovementAPsCost + APBPConstants[AP_MODIFIER_WALK]) * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + sPointsCrawl += max(1, (INT16)(((sMovementAPsCost + APBPConstants[AP_MODIFIER_CRAWL]) * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + sPointsSwat += max(1, (INT16)(((sMovementAPsCost + APBPConstants[AP_MODIFIER_SWAT]) * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + sPointsRun += max(1, (INT16)(((sMovementAPsCost + APBPConstants[AP_MODIFIER_RUN]) * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + // Specify movement modes + else + { + sPointsWalk += sMovementAPsCost + APBPConstants[AP_MODIFIER_WALK]; + sPointsCrawl += sMovementAPsCost + APBPConstants[AP_MODIFIER_CRAWL]; + sPointsSwat += sMovementAPsCost + APBPConstants[AP_MODIFIER_SWAT]; + sPointsRun += sMovementAPsCost + APBPConstants[AP_MODIFIER_RUN]; + } + // Check for stealth mode + if ( pSold->bStealthMode || bStealth ) + { + // STOMP traits - Stealthy trait decreases stealth AP modifier + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSold, STEALTHY_NT )) + { + sPointsWalk += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + sPointsCrawl += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + sPointsSwat += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + sPointsRun += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + } + else + { + sPointsWalk += APBPConstants[AP_STEALTH_MODIFIER]; + sPointsCrawl += APBPConstants[AP_STEALTH_MODIFIER]; + sPointsSwat += APBPConstants[AP_STEALTH_MODIFIER]; + sPointsRun += APBPConstants[AP_STEALTH_MODIFIER]; + } + } + // Check for backpack if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) + { sPointsWalk += APBPConstants[AP_MODIFIER_PACK]; - - // now get cost as if CRAWLING - sPointsCrawl += sTileCost + APBPConstants[AP_MODIFIER_CRAWL] + sExtraCostCrawl; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) sPointsCrawl += APBPConstants[AP_MODIFIER_PACK]; - - // now get cost as if SWATTING - sPointsSwat += sTileCost + APBPConstants[AP_MODIFIER_SWAT] + sExtraCostSwat; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) sPointsSwat += APBPConstants[AP_MODIFIER_PACK]; - - // now get cost as if RUNNING - sPointsRun += sTileCost + APBPConstants[AP_MODIFIER_RUN] + sExtraCostStand; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND ) sPointsRun += APBPConstants[AP_MODIFIER_PACK]; + } + if ( sExtraCostStand ) + { + sPointsWalk += sExtraCostStand; + sPointsCrawl += sExtraCostStand; + sPointsSwat += sExtraCostStand; + sPointsRun += sExtraCostStand; + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////// } if ( iCnt == 0 && bPlot ) diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp index eb60ad77..cb515d4a 100644 --- a/Tactical/Points.cpp +++ b/Tactical/Points.cpp @@ -31,8 +31,9 @@ #include "GameSettings.h" #include "worldman.h" #include "math.h" -#include "Map Information.h" -#include "Interface Items.h" + #include "Map Information.h" + #include "Interface Items.h" + #include "Soldier Control.h" // added by SANDRO #endif #include "connect.h" //rain @@ -41,20 +42,21 @@ extern BOOLEAN IsValidSecondHandShot( SOLDIERTYPE *pSoldier ); +////////////////////////////////////////////////////////////////////////////// +// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne() +// On the bottom here, there are these functions made +////////////////////////////////////////////////////////////////////// INT16 GetBreathPerAP( SOLDIERTYPE *pSoldier, UINT16 usAnimState ); INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, INT8 bLevel ) { + // SANDRO - Note: this procedure was changed a bit INT16 sAPCost = 0; INT16 sSwitchValue; BOOLEAN fHiddenStructVisible; // Used for hidden struct visiblity - if ( pSoldier->bStealthMode ) - sAPCost += APBPConstants[AP_STEALTH_MODIFIER]; - - if ( pSoldier->bReverse || gUIUseReverse ) - sAPCost += APBPConstants[AP_REVERSE_MODIFIER]; + // SANDRO - removed AP cost of moving stealthy or reversed outside this procedure //if (GridCost[gridno] == NPCMINECOST) // switchValue = BackupGridCost[gridno]; @@ -76,7 +78,18 @@ INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, INT8 } } } - if ( sSwitchValue == TRAVELCOST_NOT_STANDING ) + //dddokno + if ( sSwitchValue == TRAVELCOST_JUMPABLEWINDOW + || sSwitchValue == TRAVELCOST_JUMPABLEWINDOW_N + || sSwitchValue == TRAVELCOST_JUMPABLEWINDOW_W) + { + if (bDir & 1) + return -1; + + } + //ddd ^^^^^^ , , 1 + // , + if ( sSwitchValue == TRAVELCOST_NOT_STANDING)// || sSwitchValue == TRAVELCOST_JUMPABLEWINDOW) { // use the cost of the terrain! sSwitchValue = gTileTypeMovementCost[ gpWorldLevelData[ sGridNo ].ubTerrainID ]; @@ -101,7 +114,8 @@ INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, INT8 } //CHRISL: We can't jump a fence while wearing a backpack, to consider fences as impassible - if(sSwitchValue == TRAVELCOST_FENCE && UsingNewInventorySystem() == true && pSoldier->inv[BPACKPOCKPOS].exists() == true) + // SANDRO - Headrocks change to backpack check implemented + if(sSwitchValue == TRAVELCOST_FENCE && UsingNewInventorySystem() == true && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND) { return(-1); } @@ -142,25 +156,32 @@ INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, INT8 case TRAVELCOST_VEINMID : sAPCost += APBPConstants[AP_MOVEMENT_FLAT]; break; */ - case TRAVELCOST_DOOR : + // SANDRO - opening door cost will be added after Athletics check + case TRAVELCOST_DOOR: sAPCost += APBPConstants[AP_MOVEMENT_FLAT]; if (pSoldier->bTeam == gbPlayerNum) { return -1; } - sAPCost += APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_OPEN_DOOR] + APBPConstants[AP_OPEN_DOOR]; // Include open and close costs! + //sAPCost += APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_OPEN_DOOR] + APBPConstants[AP_OPEN_DOOR]; // Include open and close costs! break; // cost for jumping a fence REPLACES all other AP costs! case TRAVELCOST_FENCE : + //dddokno{ + case TRAVELCOST_JUMPABLEWINDOW: + case TRAVELCOST_JUMPABLEWINDOW_N: + case TRAVELCOST_JUMPABLEWINDOW_W: + //dddokno} if (!IS_MERC_BODY_TYPE( pSoldier )) { return -1; } // CHRISL: - if((UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true) - return( APBPConstants[AP_JUMPFENCEBPACK] ); + // SANDRO - some little changes here + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND) + return( GetAPsToJumpFence( pSoldier, TRUE ) ); else - return( APBPConstants[AP_JUMPFENCE] ); + return( GetAPsToJumpFence( pSoldier, FALSE ) ); case TRAVELCOST_NONE : return( 0 ); @@ -172,12 +193,12 @@ INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, INT8 } + // SANDRO - note: as it is, the modifiers for walking/running/etc are not multiplied for diagonal movement, but is it intentional? if (bDir & 1) { sAPCost = (sAPCost * 14) / 10; } - return(sAPCost); } @@ -286,6 +307,12 @@ INT16 TerrainBreathPoints(SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bDir, UINT } + // SANDRO - STOMP traits - Athletics reduce breath points spent for moving + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + { + iPoints = max(1, (INT16)((iPoints * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + // ATE: Adjust these by realtime movement if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { @@ -332,51 +359,74 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 u // CHRISL: Adjusted system to use different move costs while wearing a backpack if (sTileCost > 0) { - switch(usMovementMode) + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - This part have been modified "a bit" + // Check movement modifiers + switch( usMovementMode ) { case RUNNING: case ADULTMONSTER_WALKING: case BLOODCAT_RUN: - // CHRISL sPoints = sTileCost + APBPConstants[AP_MODIFIER_RUN]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; - case CROW_FLY: case SIDE_STEP: case WALK_BACKWARDS: case ROBOT_WALK: case BLOODCAT_WALK_BACKWARDS: case MONSTER_WALK_BACKWARDS: - case LARVAE_WALK: + case LARVAE_WALK: case WALKING : - // CHRISL sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; - case START_SWAT: case SWAT_BACKWARDS: - // CHRISL case SWATTING: sPoints = sTileCost + APBPConstants[AP_MODIFIER_SWAT]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; case CRAWLING: sPoints = sTileCost + APBPConstants[AP_MODIFIER_CRAWL]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; default: // Invalid movement mode DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Invalid movement mode %d used in ActionPointCost", usMovementMode ) ); - sPoints = 1; + sPoints = sTileCost; + break; } + // Check for reverse mode + if ( pSoldier->bReverse || gUIUseReverse ) + sPoints += APBPConstants[AP_REVERSE_MODIFIER]; + + // STOMP traits - Athletics trait decreases movement cost + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + { + sPoints = max(1, (INT16)((sPoints * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + // Check if doors if not player's merc (they have to open them manually) + if ( sSwitchValue == TRAVELCOST_DOOR && pSoldier->bTeam != gbPlayerNum ) + { + sPoints += GetAPsToOpenDoor( pSoldier ) + GetAPsToOpenDoor( pSoldier ); // Include open and close costs! + } + // Check for stealth mode + if ( pSoldier->bStealthMode ) + { + // STOMP traits - Stealthy trait decreases stealth AP modifier + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) + { + sPoints += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + } + else + { + sPoints += APBPConstants[AP_STEALTH_MODIFIER]; + } + } + // Check for backpack + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) + sPoints += APBPConstants[AP_MODIFIER_PACK]; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// } if (sSwitchValue == TRAVELCOST_NOT_STANDING) @@ -385,11 +435,11 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 u { case RUNNING: case WALKING : - case LARVAE_WALK: + case LARVAE_WALK: case SIDE_STEP: case WALK_BACKWARDS: // charge crouch APs for ducking head! - sPoints += APBPConstants[AP_CROUCH]; + sPoints += GetAPsCrouch(pSoldier, TRUE); // SANDRO changed break; default: @@ -414,55 +464,93 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, return 100; } + // Get switch value... + sSwitchValue = gubWorldMovementCosts[ sGridNo ][ bDir ][ pSoldier->pathing.bLevel ]; + + // Tile cost should not be reduced based on movement mode... + if ( sSwitchValue == TRAVELCOST_FENCE ) + { + return( sTileCost ); + } + // ATE - MAKE MOVEMENT ALWAYS WALK IF IN WATER + if ( TERRAIN_IS_WATER( gpWorldLevelData[ sGridNo ].ubTerrainID) ) + { + usMovementMode = WALKING; + } + // so, then we must modify it for other movement styles and accumulate // CHRISL: Adjusted system to use different move costs while wearing a backpack if (sTileCost > 0) { - switch(usMovementMode) + /////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - This part have been modified "a bit" + // Check movement modifiers + switch( usMovementMode ) { case RUNNING: case ADULTMONSTER_WALKING: case BLOODCAT_RUN: - // CHRISL sPoints = sTileCost + APBPConstants[AP_MODIFIER_RUN]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; - case CROW_FLY: case SIDE_STEP: - case ROBOT_WALK: case WALK_BACKWARDS: + case ROBOT_WALK: case BLOODCAT_WALK_BACKWARDS: case MONSTER_WALK_BACKWARDS: case LARVAE_WALK: - // CHRISL case WALKING : sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; - case START_SWAT: case SWAT_BACKWARDS: - // CHRISL case SWATTING: sPoints = sTileCost + APBPConstants[AP_MODIFIER_SWAT]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; case CRAWLING: sPoints = sTileCost + APBPConstants[AP_MODIFIER_CRAWL]; - if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) - sPoints += APBPConstants[AP_MODIFIER_PACK]; break; default: // Invalid movement mode DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Invalid movement mode %d used in ActionPointCost", usMovementMode ) ); - sPoints = 1; + sPoints = sTileCost; + break; } + + // Check for reverse mode + if ( pSoldier->bReverse || gUIUseReverse ) + sPoints += APBPConstants[AP_REVERSE_MODIFIER]; + + // STOMP traits - Athletics trait decreases movement cost + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + { + sPoints = max(1, (INT16)((sPoints * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5)); + } + // Check if doors if not player's merc (they have to open them manually) + if ( sSwitchValue == TRAVELCOST_DOOR && pSoldier->bTeam != gbPlayerNum ) + { + sPoints += GetAPsToOpenDoor( pSoldier ) + GetAPsToOpenDoor( pSoldier ); // Include open and close costs! + } + // Check for stealth mode + if ( pSoldier->bStealthMode ) + { + // STOMP traits - Stealthy trait decreases stealth AP modifier + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) + { + sPoints += (max(0, (INT16)((APBPConstants[AP_STEALTH_MODIFIER] * (100 - gSkillTraitValues.ubSTStealthModeSpeedBonus) / 100) + 0.5))); + } + else + { + sPoints += APBPConstants[AP_STEALTH_MODIFIER]; + } + } + // Check for backpack + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) + sPoints += APBPConstants[AP_MODIFIER_PACK]; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////// } // Get switch value... @@ -484,7 +572,7 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, // Since it's AFTER.. make sure we will be moving after jump... if ( ( bPathIndex + 2 ) < bPathLength ) { - sPoints += APBPConstants[AP_CROUCH]; + sPoints += GetAPsCrouch(pSoldier, TRUE); // SANDRO changed.. } break; @@ -493,7 +581,7 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, case SWAT_BACKWARDS: // Add cost to stand once there BEFORE.... - sPoints += APBPConstants[AP_CROUCH]; + sPoints += GetAPsCrouch(pSoldier, TRUE); // SANDRO changed.. break; case CRAWLING: @@ -511,7 +599,7 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, case SIDE_STEP: case WALK_BACKWARDS: // charge crouch APs for ducking head! - sPoints += APBPConstants[AP_CROUCH]; + sPoints += GetAPsCrouch(pSoldier, TRUE); // SANDRO changed.. break; default: @@ -631,8 +719,7 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost,BOOLEAN f { // Adjust breath changes due to spending or regaining of energy if(!pSoldier->bActive) - { - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"test_func2" ); + { } else iBPCost = AdjustBreathPts(pSoldier, iBPCost); @@ -752,13 +839,23 @@ INT32 AdjustBreathPts(SOLDIERTYPE *pSold, INT32 iBPCost) breathFactor += Status.heatFactor; // not used to this! */ + // SANDRO - added heat intolerant penalty + if ( MercIsHot( pSold ) ) + { + sBreathFactor += 100; + } + // SANDRO - Less breath consumption for Primitive chars + if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSold->ubProfile].bCharacterTrait == CHAR_TRAIT_PRIMITIVE ) + { + sBreathFactor -= 15; // -15% breath consumption + } // if a non-swimmer type is thrashing around in deep water - if ( (pSold->ubProfile != NO_PROFILE ) && (gMercProfiles[ pSold->ubProfile ].bPersonalityTrait == NONSWIMMER) ) + if ( (pSold->ubProfile != NO_PROFILE ) && (gMercProfiles[ pSold->ubProfile ].bDisability == NONSWIMMER) ) { if ( pSold->usAnimState == DEEP_WATER_TRED || pSold->usAnimState == DEEP_WATER_SWIM) { - sBreathFactor *= 5; // lose breath 5 times faster in deep water! + sBreathFactor *= 7; // lose breath 5 times faster in deep water! } } @@ -867,8 +964,11 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) // if merc has any APs left unused this turn (that aren't carrying over) if (pSold->bActionPoints > APBPConstants[MAX_AP_CARRIED]) { - - sUnusedAPs = pSold->bActionPoints - APBPConstants[MAX_AP_CARRIED]; + // SANDRO - don't reduce the APs if collapsed + if ( pSold->bCollapsed || pSold->bBreathCollapsed ) + sUnusedAPs = pSold->bActionPoints; + else + sUnusedAPs = pSold->bActionPoints - APBPConstants[MAX_AP_CARRIED]; sBreathPerAP = GetBreathPerAP( pSold, pSold->usAnimState ); @@ -885,34 +985,57 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) // adjust for carried weight sBreathPerAP = sBreathPerAP * 100 / BreathPointAdjustmentForCarriedWeight( pSold ); - if ( pSold->bTeam != CIV_TEAM && pSold->bTeam != gbPlayerNum) + // SANDRO - what the hell!?! This calculation is not correct, it means the less APs you have the more Breath you gain, + // when the exact opposite should happen according to the function of this entire procedure!!! + //if ( pSold->bTeam != CIV_TEAM && pSold->bTeam != gbPlayerNum) + //{ + // switch( gGameOptions.ubDifficultyLevel ) + // { + // case DIF_LEVEL_EASY: + // sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iEasyAPBonus)- sUnusedAPs) * sBreathPerAP; + // break; + + // case DIF_LEVEL_MEDIUM: + // sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iExperiencedAPBonus)-sUnusedAPs) * sBreathPerAP; + // break; + + // case DIF_LEVEL_HARD: + // sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iExpertAPBonus)- sUnusedAPs) * sBreathPerAP; + // break; + + // case DIF_LEVEL_INSANE: + // sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iInsaneAPBonus)- sUnusedAPs) * sBreathPerAP; + // break; + + // default: + // sBreathChange = (APBPConstants[AP_MAXIMUM] - sUnusedAPs) * sBreathPerAP; + // } + //} + //else + //{ + // sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iPlayerAPBonus)- sUnusedAPs) * sBreathPerAP; + //} + // SANDRO - if we want to make difference between difficulty levels, the just make it so with higher difficulty the enemy regenerate faster: + if ( pSold->bTeam == ENEMY_TEAM ) { switch( gGameOptions.ubDifficultyLevel ) { case DIF_LEVEL_EASY: - sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iEasyAPBonus)- sUnusedAPs) * sBreathPerAP; + sBreathPerAP *= 9/10; // -10% break; - case DIF_LEVEL_MEDIUM: - sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iExperiencedAPBonus)-sUnusedAPs) * sBreathPerAP; + sBreathPerAP *= 1; // normal break; - case DIF_LEVEL_HARD: - sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iExpertAPBonus)- sUnusedAPs) * sBreathPerAP; + sBreathPerAP *= 11/10; // +10% break; - case DIF_LEVEL_INSANE: - sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iInsaneAPBonus)- sUnusedAPs) * sBreathPerAP; + sBreathPerAP *= 6/5; // +20% break; - - default: - sBreathChange = (APBPConstants[AP_MAXIMUM] - sUnusedAPs) * sBreathPerAP; } } - else - { - sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iPlayerAPBonus)- sUnusedAPs) * sBreathPerAP; - } + // SANDRO - this simple thing is the correct calculation + sBreathChange = (sUnusedAPs * sBreathPerAP); } else { @@ -921,6 +1044,21 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) // Adjust for on drugs HandleBPEffectDueToDrugs( pSold, &sBreathChange ); + // SANDRO - Penalty for breath regain for being hit by Martial artist + if ((pSold->lUnregainableBreath > 0) && (sBreathChange < 0) && gGameOptions.fNewTraitSystem) + { + if (pSold->lUnregainableBreath >= (0 - sBreathChange)) + { + pSold->lUnregainableBreath += sBreathChange; + sBreathChange = 0; + } + else + { + sBreathChange += (INT16)(pSold->lUnregainableBreath); + pSold->lUnregainableBreath = 0; + } + } + // adjust breath only, don't touch action points! DeductPoints(pSold,0,(INT16)sBreathChange ); @@ -1008,7 +1146,17 @@ INT16 GetBreathPerAP( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) { if( sBreathPerAP < 0 && ( pSoldier->pathing.bLevel || !FindStructure( pSoldier->sGridNo, STRUCTURE_ROOF ) ) && pSoldier->bBreath > 1) { - sBreathPerAP -= (INT16)( sBreathPerAP * gbCurrentRainIntensity * gGameExternalOptions.ubBreathGainReductionPerRainIntensity / 100 ); + // Added a feature to reduce rain effect on regaining breath with Ranger trait - SANDRO + if( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) && ( gGameOptions.fNewTraitSystem )) + { + INT16 sBreathGainPenalty = 0; + sBreathGainPenalty = (INT16)((gGameExternalOptions.ubBreathGainReductionPerRainIntensity * (100 - gSkillTraitValues.ubRAWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) / 100); + sBreathGainPenalty = min( max( 0, sBreathGainPenalty ), 100); // keep it 0-100% + sBreathPerAP -= (INT16)( sBreathPerAP * gbCurrentRainIntensity * sBreathGainPenalty /100 ); + } + else + sBreathPerAP -= (INT16)( sBreathPerAP * gbCurrentRainIntensity * gGameExternalOptions.ubBreathGainReductionPerRainIntensity / 100 ); + } } //end rain @@ -1052,6 +1200,20 @@ INT16 CalcAPsToBurst( INT16 bBaseActionPoints, OBJECTTYPE * pObj ) return (UINT8) aps; } +// HEADROCK HAM 4: Same as above, without percent modifiers. +INT16 CalcAPsToBurstNoModifier( INT16 bBaseActionPoints, OBJECTTYPE * pObj ) +{ + INT32 aps; + + aps = ( Weapon[ pObj->usItem ].bBurstAP * bBaseActionPoints + (APBPConstants[AP_MAXIMUM] - 1) ) / APBPConstants[AP_MAXIMUM]; + + aps = __max( aps, ( Weapon[ pObj->usItem ].bBurstAP + 1 ) / 2 ); + + if ( aps < 0 ) aps = 0; + else if ( aps > APBPConstants[AP_MAXIMUM] ) aps = APBPConstants[AP_MAXIMUM]; + + return (UINT8) aps; +} INT16 CalcAPsToAutofire( INT16 bBaseActionPoints, OBJECTTYPE * pObj, UINT8 bDoAutofire ) { @@ -1096,12 +1258,32 @@ INT16 CalcAPsToAutofire( INT16 bBaseActionPoints, OBJECTTYPE * pObj, UINT8 bDoAu if ( aps < 0 ) aps = 0; //CHRISL: This can cause problem if a player uses any of the xxx_AP_BONUS values in the INI file. //else if ( aps > APBPConstants[AP_MAXIMUM] ) aps = APBPConstants[AP_MAXIMUM]; + // HEADROCK HAM 4: But we NEED an upper cap, so here it is: + else + aps = __min(255,aps); } DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcAPsToAutoFire: return aps = %d", aps)); return (UINT8) aps; } +// HEADROCK HAM 4: Same as above, without modifiers +INT16 CalcAPsToAutofireNoModifier( INT16 bBaseActionPoints, OBJECTTYPE * pObj, UINT8 bDoAutofire ) +{ + + INT32 aps=APBPConstants[AP_MAXIMUM] + 1; + if ( GetAutofireShotsPerFiveAPs (pObj) ) + { + const INT32 autofireaps = + aps = ( ( APBPConstants[AUTOFIRE_SHOTS_AP_VALUE] * bDoAutofire * bBaseActionPoints ) / GetAutofireShotsPerFiveAPs(pObj) + (APBPConstants[AP_MAXIMUM] - 1) ) / APBPConstants[AP_MAXIMUM]; + + aps = __max( aps, ( autofireaps + 1 ) / 2 ); + + if ( aps < 0 ) aps = 0; + } + + return (UINT8) aps; +} INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, INT16 bAimTime ) { @@ -1129,7 +1311,7 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur else sAPCost += CalcAPsToBurst( pSoldier->CalcActionPoints( ), &(pSoldier->inv[HANDPOS]) ); } - else + //else //ddd comment for aimed burst { if (gGameExternalOptions.fIncreasedAimingCost ) { @@ -1157,8 +1339,8 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur // If the weapon has a scope, and the target is within eligible range for scope use - if ( IsScoped(&pSoldier->inv[HANDPOS]) - && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) >= GetMinRangeForAimBonus(&pSoldier->inv[HANDPOS]) ) + if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS]) && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) >= GetMinRangeForAimBonus(&pSoldier->inv[HANDPOS])) + || (UsingNewCTHSystem() == true && GetBestScopeMagnificationFactor(&pSoldier->inv[HANDPOS], GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) > 1.0 )) ) { // Add an individual cost for EACH click, as necessary. @@ -1436,6 +1618,26 @@ INT16 BaseAPsToShootOrStab( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * pObj ) return baseAPsToShootOrStab; } +// HEADROCK HAM 4: Same function as above, except no modifier. +INT16 BaseAPsToShootOrStabNoModifier( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * pObj ) +{ + INT32 Top, Bottom; + FLOAT rof; + + rof = Weapon[ pObj->usItem ].ubShotsPer4Turns; + + Top = 8 * bAPs * 100; + + INT16 baseAPsToShootOrStab = -1; + if (rof > 0) + { + Bottom = (INT32)(( 100 + bAimSkill ) * rof); + baseAPsToShootOrStab = ( Top + Bottom / 2 ) / Bottom; + } + + return baseAPsToShootOrStab; +} + void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise ) { UINT8 ubDirection; @@ -1513,7 +1715,13 @@ UINT16 CalculateTurningCost(SOLDIERTYPE *pSoldier, UINT16 usItem, BOOLEAN fAddin if ( fAddingTurningCost ) { if ( Item[ usItem ].usItemClass == IC_THROWING_KNIFE ) - usTurningCost = APBPConstants[AP_LOOK_STANDING]; + { + // SANDRO - Athletics trait check added + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + usTurningCost = max( 1, (INT16)((APBPConstants[AP_LOOK_STANDING] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/100) + 0.5)); + else + usTurningCost = APBPConstants[AP_LOOK_STANDING]; + } else usTurningCost = GetAPsToLook( pSoldier ); } @@ -1560,46 +1768,7 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sGridNo, ubAddTurningCost, &fAddingTurningCost, &fAddingRaiseGunCost ); - if (ubForceRaiseGunCost) - { - fAddingRaiseGunCost = TRUE; - } - - if ( Item[ usItem ].usItemClass == IC_THROWING_KNIFE ) - { - // Do we need to stand up? - bAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND ); - } - - if ( AM_A_ROBOT( pSoldier ) ) - { - fAddingRaiseGunCost = FALSE; - } - - //Calculate usTurningCost - usTurningCost = CalculateTurningCost(pSoldier, usItem, fAddingTurningCost); - - //Calculate usRaiseGunCost - usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost); - - //charge for turn and/or raise based on the results of fAddingTurningCost & fAddingRaiseGunCost - bAPCost += (usTurningCost + usRaiseGunCost); - - - if (!TileIsOutOfBounds(sGridNo)) - { - // Given a gridno here, check if we are on a guy - if so - get his gridno - if ( FindSoldier( sGridNo, &usTargID, &uiMercFlags, FIND_SOLDIER_GRIDNO ) ) - { - sGridNo = MercPtrs[ usTargID ]->sGridNo; - } - } - - // if attacking a new target (or if the specific target is uncertain) - if (ubForceRaiseGunCost || (( sGridNo != pSoldier->sLastTarget ) && !Item[usItem].rocketlauncher )) - { - bAPCost += APBPConstants[AP_CHANGE_TARGET]; - } + // THE LINES FROM HERE HAVE BEEN MOVED DOWN - SANDRO // Snap: reversed DIGICRAB's change. // bFullAPs are BASE APs, which do not include APs caried over from the previous turn. @@ -1627,21 +1796,155 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni CreateItem( UNDER_GLAUNCHER, 100, &GrenadeLauncher ); } - bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, &GrenadeLauncher ); + //CHRISL: When prone and using a bipod, bipod should help compensate for recoil. To reflect this, our shot AP cost should be minimially reduced + if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier > 0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE && GetBipodBonus(&GrenadeLauncher) > 0){ + bAPCost += (BaseAPsToShootOrStab( bFullAPs, bAimSkill, &GrenadeLauncher ) * (100 - GetBipodBonus(&GrenadeLauncher)) / 100); + } else { + bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, &GrenadeLauncher ); + } + // SANDRO - STOMP traits - reduced APs needed to fire underbarrel grenade launchers for Heavy Weapons trait + if ( HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT ) && gGameOptions.fNewTraitSystem ) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ) ) / 100)+ 0.5); + } } else if ( pSoldier->IsValidSecondHandShot( ) ) { - // charge the maximum of the two - bAPCost += __max( - BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ), - BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[SECONDHANDPOS]) ) ); + // SANDRO - gunslinger check for firing speed + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && gGameOptions.fNewTraitSystem ) + { + INT16 bcst1 = BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ); + INT16 bcst2 = BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[SECONDHANDPOS]) ); + if ( Weapon[ usItem ].ubWeaponType == GUN_PISTOL ) + bcst1 = (INT16)((bcst1 * ( 100 - gSkillTraitValues.ubGSFiringSpeedBonusPistols) / 100)+ 0.5); + if ( Weapon[ pSoldier->inv[SECONDHANDPOS].usItem ].ubWeaponType == GUN_PISTOL ) + bcst2 = (INT16)((bcst2 * ( 100 - gSkillTraitValues.ubGSFiringSpeedBonusPistols) / 100)+ 0.5); + + bAPCost += __max( bcst1, bcst2 ); + } + else + { + // charge the maximum of the two + bAPCost += __max( + BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ), + BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[SECONDHANDPOS]) ) ); + } } else { - bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ); + //CHRISL: When prone and using a bipod, bipod should help compensate for recoil. To reflect this, our shot AP cost should be minimially reduced + if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier > 0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE && GetBipodBonus(&(pSoldier->inv[HANDPOS])) > 0){ + bAPCost += (BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ) * (100 - GetBipodBonus(&(pSoldier->inv[HANDPOS]))) / 100); + } else { + bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ); + } + + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits + //////////////////////////////////////////////////// + if ( gGameOptions.fNewTraitSystem ) + { + // Decreased APs needed for LMG - Auto Weapons + if (Weapon[usItem].ubWeaponType == GUN_LMG && (pSoldier->bDoBurst || pSoldier->bDoAutofire) && ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) ) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubAWFiringSpeedBonusLMGs ) / 100)+ 0.5); + } + // Decreased APs needed for melee attacks - Melee + if ( Item[ usItem ].usItemClass == IC_BLADE && ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) ) ) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubMEBladesAPsReduction ) / 100)+ 0.5); + } + // Decreased APs needed for throwing knives - Throwing + else if ( Item[ usItem ].usItemClass == IC_THROWING_KNIFE && ( HAS_SKILL_TRAIT( pSoldier, THROWING_NT ) ) ) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubTHBladesAPsReduction ) / 100)+ 0.5); + } + // Decreased APs needed for launchers - Heavy Eeapons + else if ( (Item[ usItem ].usItemClass == IC_LAUNCHER || Item[usItem].grenadelauncher ) && !(Item[usItem].rocketlauncher) && !(Item[usItem].mortar) && ( HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT ) )) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubHWGrenadeLaunchersAPsReduction * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ) ) / 100)+ 0.5); + } + // Decreased APs needed for launchers - Heavy Eeapons + else if (( Item[usItem].rocketlauncher || Item[usItem].singleshotrocketlauncher ) && !(Item[usItem].mortar) && ( HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT ) )) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubHWRocketLaunchersAPsReduction * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ) ) / 100)+ 0.5); + } + // Decreased APs needed for mortar - Heavy Eeapons + else if ( Item[usItem].mortar && HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT ) ) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubHWMortarAPsReduction * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ) ) / 100)+ 0.5); + } + // Decreased APs needed for pistols and machine pistols - Gunslinger + else if (Weapon[ usItem ].ubWeaponType == GUN_PISTOL && HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) ) + { + bAPCost = (INT16)((bAPCost * (100 - gSkillTraitValues.ubGSFiringSpeedBonusPistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ) ) / 100)+ 0.5); + } + } + ///////////////////////////////////////////////////////////////////////////////////// } + ///////////////////////////////////////////////////////////////////////// + // THESE MODIFIERS HAVE BEEN JUST MOVED HERE FROM ABOVE - SANDRO + + if (ubForceRaiseGunCost) + { + fAddingRaiseGunCost = TRUE; + } + + if ( Item[ usItem ].usItemClass == IC_THROWING_KNIFE ) + { + // Do we need to stand up? + bAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND ); + } + + if ( AM_A_ROBOT( pSoldier ) ) + { + fAddingRaiseGunCost = FALSE; + } + + //Calculate usTurningCost + usTurningCost = CalculateTurningCost(pSoldier, usItem, fAddingTurningCost); + + //Calculate usRaiseGunCost + usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost); + + //charge for turn and/or raise based on the results of fAddingTurningCost & fAddingRaiseGunCost + // silversurfer: this was different from HandleItem() and therefore it displayed different values + // on the cursor than those deducted for real + // bAPCost += (usTurningCost + usRaiseGunCost); + if ( gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_PRONE ) + { + if ( fAddingTurningCost && fAddingRaiseGunCost ) + { + if(usRaiseGunCost > usTurningCost) + bAPCost += usRaiseGunCost; + else + bAPCost += usTurningCost; + } + else + bAPCost += (usTurningCost + usRaiseGunCost); + } + else + bAPCost += (usTurningCost + usRaiseGunCost); + + if (!TileIsOutOfBounds(sGridNo)) + { + // Given a gridno here, check if we are on a guy - if so - get his gridno + if ( FindSoldier( sGridNo, &usTargID, &uiMercFlags, FIND_SOLDIER_GRIDNO ) ) + { + sGridNo = MercPtrs[ usTargID ]->sGridNo; + } + } + + // if attacking a new target (or if the specific target is uncertain) + // Added check if the weapon is a throwing knife - otherwise it would add APs for change taregt on cursor but not actually deduct them afterwards - SANDRO + if (ubForceRaiseGunCost || (( sGridNo != pSoldier->sLastTarget ) && !Item[usItem].rocketlauncher && (Item[ usItem ].usItemClass != IC_THROWING_KNIFE) )) + { + bAPCost += APBPConstants[AP_CHANGE_TARGET]; + } + ///////////////////////////////////////////////////////////////////////// + // the minimum AP cost of ANY shot can NEVER be more than merc's maximum APs! if ( bAPCost > bFullAPs ) bAPCost = bFullAPs; @@ -1701,18 +2004,34 @@ INT16 MinAPsToPunch(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost // Is it the same as he's facing? if ( ubDirection != pSoldier->ubDirection ) { - bAPCost += APBPConstants[AP_LOOK_STANDING]; + // SANDRO - Athletics trait check added + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + bAPCost += max( 1, (INT16)((APBPConstants[AP_LOOK_STANDING] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/100) + 0.5 )); + else + bAPCost += APBPConstants[AP_LOOK_STANDING]; } } } } - bAPCost += APBPConstants[AP_PUNCH]; + bAPCost += ApsToPunch( pSoldier ); // SANDRO - changed this to direct us to specific calc function return ( bAPCost ); } +// SANDRO - added function +INT16 ApsToPunch( SOLDIERTYPE *pSoldier ) +{ + if (gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && (!(pSoldier->inv[HANDPOS].exists()) || Item[pSoldier->inv[HANDPOS].usItem].brassknuckles) ) + { + return ( max( 1, (INT16)((APBPConstants[AP_PUNCH] * (100 - gSkillTraitValues.ubMAPunchAPsReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/ 100) + 0.5)) ); + } + else + { + return ( APBPConstants[AP_PUNCH] ); + } +} INT16 MinPtsToMove(SOLDIERTYPE *pSoldier) @@ -1769,7 +2088,7 @@ INT8 PtsToMoveDirection(SOLDIERTYPE *pSoldier, INT8 bDirection ) { if ( usMoveModeToUse == RUNNING && pSoldier->usAnimState != RUNNING ) { - sCost += APBPConstants[AP_START_RUN_COST]; + sCost += GetAPsStartRun( pSoldier ); // changed by SANDRO } } @@ -1786,31 +2105,31 @@ INT8 MinAPsToStartMovement( SOLDIERTYPE * pSoldier, UINT16 usMovementMode ) case WALKING: if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) { - bAPs += APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]; + bAPs += GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE); } else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH) { - bAPs += APBPConstants[AP_CROUCH]; + bAPs += GetAPsCrouch(pSoldier, TRUE); } break; case SWATTING: if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) { - bAPs += APBPConstants[AP_PRONE]; + bAPs += GetAPsProne(pSoldier, TRUE); } else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND) { - bAPs += APBPConstants[AP_CROUCH]; + bAPs += GetAPsCrouch(pSoldier, TRUE); } break; case CRAWLING: if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND) { - bAPs += APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]; + bAPs += GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE); } else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH) { - bAPs += APBPConstants[AP_CROUCH]; + bAPs += GetAPsCrouch(pSoldier, TRUE); } break; default: @@ -1819,7 +2138,7 @@ INT8 MinAPsToStartMovement( SOLDIERTYPE * pSoldier, UINT16 usMovementMode ) if (usMovementMode == RUNNING && pSoldier->usAnimState != RUNNING ) { - bAPs += APBPConstants[AP_START_RUN_COST]; + bAPs += GetAPsStartRun( pSoldier ); // changed by SANDRO } return( bAPs ); } @@ -1832,7 +2151,7 @@ BOOLEAN EnoughAmmo( SOLDIERTYPE *pSoldier, BOOLEAN fDisplay, INT8 bInvPos ) { UINT16 glItem = GetAttachedGrenadeLauncher( &(pSoldier->inv[bInvPos])); OBJECTTYPE* pAttachment = FindLaunchableAttachment( &(pSoldier->inv[bInvPos]), glItem); - if ( pAttachment ) + if ( pAttachment->exists() ) return TRUE; else return FALSE; @@ -1852,12 +2171,24 @@ BOOLEAN EnoughAmmo( SOLDIERTYPE *pSoldier, BOOLEAN fDisplay, INT8 bInvPos ) return( TRUE ); } + + if (Item[pSoldier->inv[bInvPos].usItem].usItemClass == IC_BOMB) + { + return (TRUE); + } + // ATE: Did an else if here... if ( FindAttachmentByClass( &(pSoldier->inv[ bInvPos ]), IC_BOMB ) != 0 ) { return( TRUE ); } + // WANNE: If there is a tank, it always have ammo to shoot, no check! + if (Item[pSoldier->inv[bInvPos].usItem].cannon) + { + return ( TRUE ); + } + if ( fDisplay ) { TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_AMMO ); @@ -1937,31 +2268,33 @@ void DeductAmmo( SOLDIERTYPE *pSoldier, INT8 bInvPos ) else if ( Item[ pObj->usItem ].usItemClass == IC_LAUNCHER || Item[pObj->usItem].cannon || pSoldier->bWeaponMode == WM_ATTACHED_GL || pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO ) { OBJECTTYPE* pAttachment = FindAttachmentByClass( pObj, IC_GRENADE ); - if ( pAttachment == 0 ) + if ( !pAttachment->exists() ) { pAttachment = FindAttachmentByClass( pObj, IC_BOMB ); } - if (pAttachment) + //CHRISL: Added a magsize value to Explosives.xml which is checked by GetExpMagSize. This will allow OAS to load individual grenades into + // multi-launch grenades and fire correctly + if (pAttachment->exists()) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DeductAmmo: deducting for GL: found attachment, about to decide whether to remove it")); - if ( Item[ pObj->usItem ].usItemClass == IC_LAUNCHER && GetMagSize(pObj) > 1 ) + if ( Item[ pObj->usItem ].usItemClass == IC_LAUNCHER && GetExpMagSize(pAttachment) > 1 ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DeductAmmo: deducting for milkor")); - (*pAttachment)[0]->data.objectStatus -= (INT8) ceil((double)( 100 / GetMagSize(pObj) )) ; + (*pAttachment)[0]->data.objectStatus -= (INT8) ceil((double)( 100 / GetExpMagSize(pAttachment) )) ; - DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DeductAmmo: deducting for milkor: resulting status: %d, remove? = %d",(*pAttachment)[0]->data.objectStatus,((*pAttachment)[0]->data.objectStatus <= (INT8) ( 100 / Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize )))); - if ( (*pAttachment)[0]->data.objectStatus <= (INT8) ceil((double)( 100 / GetMagSize(pObj) ) )) + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DeductAmmo: deducting for milkor: resulting status: %d, remove? = %d",(*pAttachment)[0]->data.objectStatus,((*pAttachment)[0]->data.objectStatus <= (INT8) ( 100 / GetExpMagSize(pAttachment) )))); + if ( (*pAttachment)[0]->data.objectStatus <= (INT8) ceil((double)( 100 / GetExpMagSize(pAttachment) ) )) { pObj->RemoveAttachment( pAttachment); } } - else if ( (pSoldier->bWeaponMode == WM_ATTACHED_GL || pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO ) && Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize > 1 ) + else if ( (pSoldier->bWeaponMode == WM_ATTACHED_GL || pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO ) && GetExpMagSize(pAttachment) > 1 ) { - (*pAttachment)[0]->data.objectStatus -= (INT8) ceil((double)( 100 / Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize )) ; + (*pAttachment)[0]->data.objectStatus -= (INT8) ceil((double)( 100 / GetExpMagSize(pAttachment) )) ; - DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DeductAmmo: deducting for OICW GL: resulting status: %d, remove? = %d",(*pAttachment)[0]->data.objectStatus,((*pAttachment)[0]->data.objectStatus <= (INT8) ( 100 / Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize )))); - if ( (*pAttachment)[0]->data.objectStatus <= (INT8) ceil((double)( 100 / Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize ) )) + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DeductAmmo: deducting for OICW GL: resulting status: %d, remove? = %d",(*pAttachment)[0]->data.objectStatus,((*pAttachment)[0]->data.objectStatus <= (INT8) ( 100 / GetExpMagSize(pAttachment) )))); + if ( (*pAttachment)[0]->data.objectStatus <= (INT8) ceil((double)( 100 / GetExpMagSize(pAttachment) ) )) { pObj->RemoveAttachment( pAttachment); } @@ -2001,12 +2334,12 @@ UINT16 GetAPsToPickupItem( SOLDIERTYPE *pSoldier, INT32 usMapPos ) if ( sAPCost != 0 ) { // ADD APS TO PICKUP - sAPCost += APBPConstants[AP_PICKUP_ITEM]; + sAPCost += GetBasicAPsToPickupItem( pSoldier ); // changed by SANDRO } } else { - sAPCost += APBPConstants[AP_PICKUP_ITEM]; + sAPCost += GetBasicAPsToPickupItem( pSoldier ); // changed by SANDRO } } @@ -2042,12 +2375,29 @@ INT16 GetAPsToReloadGunWithAmmo( SOLDIERTYPE *pSoldier, OBJECTTYPE * pGun, OBJEC if(Weapon[pGun->usItem].swapClips == 1 && GetMagSize(pGun) == Magazine[Item[pAmmo->usItem].ubClassIndex].ubMagSize) { // normal situation - return GetAPsToReload(pGun) ; + // SANDRO - added a feature here to reduce APs needed to reload if having GUNSLINGER skill + if ( gGameOptions.fNewTraitSystem ) + { + // if pistol or revolver + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && ( Weapon[ pGun->usItem ].ubWeaponType == GUN_PISTOL || Weapon[ pGun->usItem ].ubWeaponType == GUN_M_PISTOL ) ) + return(INT16)(( GetAPsToReload(pGun) * max(0,(100 - gSkillTraitValues.ubGSRealoadSpeedHandgunsBonus * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ) - (HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ? gSkillTraitValues.ubAMReloadSpeedMagazines : 0 )))/100 ) + 0.5); + // other weapons for ambidextrous + else if (HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT )) + return(INT16)(( GetAPsToReload(pGun) * max(0,(100 - gSkillTraitValues.ubAMReloadSpeedMagazines ))/100) + 0.5); + // normal case + else + return GetAPsToReload(pGun); + } + else + return GetAPsToReload(pGun); } else if(Weapon[pGun->usItem].swapClips == 1) { // wrong size ammo item - return (INT8)((GetAPsToReload(pGun) * APBPConstants[AP_WRONG_MAG])/10); + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) // SANDRO - added Ambidextrous check + return (INT8)((((GetAPsToReload(pGun) * APBPConstants[AP_WRONG_MAG])/10)*(100 - gSkillTraitValues.ubAMReloadSpeedLoose)/100) + 0.5); + else + return (INT8)((GetAPsToReload(pGun) * APBPConstants[AP_WRONG_MAG])/10); } else { @@ -2055,22 +2405,48 @@ INT16 GetAPsToReloadGunWithAmmo( SOLDIERTYPE *pSoldier, OBJECTTYPE * pGun, OBJEC int reload = 0; int rounds = __min((GetMagSize(pGun)-(*pGun)[0]->data.gun.ubGunShotsLeft), Magazine[Item[pAmmo->usItem].ubClassIndex].ubMagSize); if(!((*pGun)[0]->data.gun.ubGunState & GS_WEAPON_BEING_RELOADED)) + { reload = GetAPsToReload(pGun); + // SANDRO - added Ambidextrous check + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + { + reload = (INT16)(reload * (100 - gSkillTraitValues.ubAMReloadSpeedMagazines)/100); + } + } if(usAllAPs == 1) { for(int i = 1; i <= rounds; i++) { - if(EnoughPoints(pSoldier,(reload + (i * APBPConstants[AP_RELOAD_LOOSE])),0,FALSE) == FALSE) + // SANDRO - added Ambidextrous check + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) { - rounds = i-1; - break; + if(EnoughPoints(pSoldier,(reload + (i * (INT16)((APBPConstants[AP_RELOAD_LOOSE]*(100 - gSkillTraitValues.ubAMReloadSpeedLoose)/100) + 0.5))),0,FALSE) == FALSE) + { + rounds = i-1; + break; + } + } + else + { + if(EnoughPoints(pSoldier,(reload + (i * APBPConstants[AP_RELOAD_LOOSE])),0,FALSE) == FALSE) + { + rounds = i-1; + break; + } } } } else if (usAllAPs == 2) rounds = 1; - return (reload + (rounds * APBPConstants[AP_RELOAD_LOOSE])); + + // SANDRO - added Ambidextrous check + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return (reload + ((INT16) (rounds * (APBPConstants[AP_RELOAD_LOOSE]*(100 - gSkillTraitValues.ubAMReloadSpeedLoose)/100) + 0.5))); + else + return (reload + (rounds * APBPConstants[AP_RELOAD_LOOSE])); } + + return GetAPsToReload(pGun); // added by SANDRO - safety check } INT16 GetAPsToAutoReload( SOLDIERTYPE * pSoldier ) @@ -2085,7 +2461,24 @@ INT16 GetAPsToAutoReload( SOLDIERTYPE * pSoldier ) // manual recharge if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) ) { - return Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually; + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - SANDRO + if ( gGameOptions.fNewTraitSystem ) + { + // Sniper trait makes chambering a round faster + if (( Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_SN_RIFLE || Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_RIFLE ) && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT )) + return ( (INT16)(((Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubSNChamberRoundAPsReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )))/100) + 0.5)); + // Ranger trait makes pumping shotguns faster + else if (( Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_SHOTGUN ) && HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + return ( (INT16)(((Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubRAPumpShotgunsAPsReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT )))/100) + 0.5)); + else + return (Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually); + } + else + { + return (Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// } // @@ -2175,76 +2568,78 @@ INT16 GetAPsToChangeStance( SOLDIERTYPE *pSoldier, INT8 bDesiredHeight ) if ( bCurrentHeight == bDesiredHeight ) { - sAPCost = 0; + return(0); // no need to got through the code below here - SANDRO } + // SANDRO - changed this here to call specific functions if ( bCurrentHeight == ANIM_STAND && bDesiredHeight == ANIM_PRONE ) { - sAPCost = APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]; + sAPCost = GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE); } if ( bCurrentHeight == ANIM_STAND && bDesiredHeight == ANIM_CROUCH ) { - sAPCost = APBPConstants[AP_CROUCH]; + sAPCost = GetAPsCrouch(pSoldier, TRUE); } if ( bCurrentHeight == ANIM_CROUCH && bDesiredHeight == ANIM_PRONE ) { - sAPCost = APBPConstants[AP_PRONE]; + sAPCost = GetAPsProne(pSoldier, TRUE); } if ( bCurrentHeight == ANIM_CROUCH && bDesiredHeight == ANIM_STAND ) { - sAPCost = APBPConstants[AP_CROUCH]; + sAPCost = GetAPsCrouch(pSoldier, TRUE); } if ( bCurrentHeight == ANIM_PRONE && bDesiredHeight == ANIM_STAND ) { - sAPCost = APBPConstants[AP_PRONE] + APBPConstants[AP_CROUCH]; + sAPCost = GetAPsProne(pSoldier, TRUE) + GetAPsCrouch(pSoldier, TRUE); } if ( bCurrentHeight == ANIM_PRONE && bDesiredHeight == ANIM_CROUCH ) { - sAPCost = APBPConstants[AP_PRONE]; + sAPCost = GetAPsProne(pSoldier, TRUE); } return( sAPCost ); } -INT16 GetBPsToChangeStance( SOLDIERTYPE *pSoldier, INT8 bDesiredHeight ) -{ - UINT16 sBPCost = 0; - INT8 bCurrentHeight; - - bCurrentHeight = gAnimControl[ pSoldier->usAnimState ].ubEndHeight; - - if ( bCurrentHeight == bDesiredHeight ) - { - sBPCost = 0; - } - - if ( bCurrentHeight == ANIM_STAND && bDesiredHeight == ANIM_PRONE ) - { - sBPCost = APBPConstants[BP_CROUCH] + APBPConstants[BP_PRONE]; - } - if ( bCurrentHeight == ANIM_STAND && bDesiredHeight == ANIM_CROUCH ) - { - sBPCost = APBPConstants[BP_CROUCH]; - } - if ( bCurrentHeight == ANIM_CROUCH && bDesiredHeight == ANIM_PRONE ) - { - sBPCost = APBPConstants[BP_PRONE]; - } - if ( bCurrentHeight == ANIM_CROUCH && bDesiredHeight == ANIM_STAND ) - { - sBPCost = APBPConstants[BP_CROUCH]; - } - if ( bCurrentHeight == ANIM_PRONE && bDesiredHeight == ANIM_STAND ) - { - sBPCost = APBPConstants[BP_PRONE] + APBPConstants[BP_CROUCH]; - } - if ( bCurrentHeight == ANIM_PRONE && bDesiredHeight == ANIM_CROUCH ) - { - sBPCost = APBPConstants[BP_PRONE]; - } - - return( sBPCost ); -} +// SANDRO - actually this procedure is nowhere used in the entire JA2 code - commented out +//INT16 GetBPsToChangeStance( SOLDIERTYPE *pSoldier, INT8 bDesiredHeight ) +//{ +// UINT16 sBPCost = 0; +// INT8 bCurrentHeight; +// +// bCurrentHeight = gAnimControl[ pSoldier->usAnimState ].ubEndHeight; +// +// if ( bCurrentHeight == bDesiredHeight ) +// { +// sBPCost = 0; +// } +// +// if ( bCurrentHeight == ANIM_STAND && bDesiredHeight == ANIM_PRONE ) +// { +// sBPCost = APBPConstants[BP_CROUCH] + APBPConstants[BP_PRONE]; +// } +// if ( bCurrentHeight == ANIM_STAND && bDesiredHeight == ANIM_CROUCH ) +// { +// sBPCost = APBPConstants[BP_CROUCH]; +// } +// if ( bCurrentHeight == ANIM_CROUCH && bDesiredHeight == ANIM_PRONE ) +// { +// sBPCost = APBPConstants[BP_PRONE]; +// } +// if ( bCurrentHeight == ANIM_CROUCH && bDesiredHeight == ANIM_STAND ) +// { +// sBPCost = APBPConstants[BP_CROUCH]; +// } +// if ( bCurrentHeight == ANIM_PRONE && bDesiredHeight == ANIM_STAND ) +// { +// sBPCost = APBPConstants[BP_PRONE] + APBPConstants[BP_CROUCH]; +// } +// if ( bCurrentHeight == ANIM_PRONE && bDesiredHeight == ANIM_CROUCH ) +// { +// sBPCost = APBPConstants[BP_PRONE]; +// } +// +// return( sBPCost ); +//} INT16 GetAPsToLook( SOLDIERTYPE *pSoldier ) @@ -2254,17 +2649,26 @@ INT16 GetAPsToLook( SOLDIERTYPE *pSoldier ) { // Now change to appropriate animation case ANIM_STAND: - return( APBPConstants[AP_LOOK_STANDING] ); + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + return( max( 1, (INT16)((APBPConstants[AP_LOOK_STANDING] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))); + else + return( APBPConstants[AP_LOOK_STANDING] ); break; case ANIM_CROUCH: - return( APBPConstants[AP_LOOK_CROUCHED] ); + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + return( max( 1, (INT16)((APBPConstants[AP_LOOK_CROUCHED] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))); + else + return( APBPConstants[AP_LOOK_CROUCHED] ); break; case ANIM_PRONE: // APBPConstants[AP_PRONE] is the AP cost to go to or from the prone stance. To turn while prone, your merc has to get up to // crouched, turn, and then go back down. Hence you go up (APBPConstants[AP_PRONE]), turn (APBPConstants[AP_LOOK_PRONE]) and down (APBPConstants[AP_PRONE]). - return( APBPConstants[AP_LOOK_PRONE] + APBPConstants[AP_PRONE] + APBPConstants[AP_PRONE] ); + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + return( max( 1, (INT16)((APBPConstants[AP_LOOK_PRONE] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5)) + GetAPsProne(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE) ); + else + return( APBPConstants[AP_LOOK_PRONE] + GetAPsProne(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE) ); break; // no other values should be possible @@ -2346,10 +2750,20 @@ INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) if ( pSoldier->IsValidSecondHandShot( ) ) { //Madd: return the greater of the two weapons + 1: - UINT8 rt1, rt2; - rt1 = Weapon[usItem].ubReadyTime * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) / 100; - rt2 = Weapon[pSoldier->inv[SECONDHANDPOS].usItem].ubReadyTime * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ SECONDHANDPOS ]) ) / 100; - + INT16 rt1 = 0, rt2 = 0; + // SANDRO - STOMP traits - decrease APs to ready pistols and revolvers if having Gunslinger trait + if ( HAS_SKILL_TRAIT(pSoldier, GUNSLINGER_NT) && ( gGameOptions.fNewTraitSystem )) + { + if (Weapon[usItem].ubWeaponType == GUN_PISTOL) + rt1 = (INT16)(Weapon[usItem].ubReadyTime * max(0, (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) - gSkillTraitValues.ubGSPercentReadyPistolsReduction * NUM_SKILL_TRAITS(pSoldier, GUNSLINGER_NT) ) ) / 100); + if (Weapon[pSoldier->inv[SECONDHANDPOS].usItem].ubWeaponType == GUN_PISTOL) + rt2 = (INT16)(Weapon[pSoldier->inv[SECONDHANDPOS].usItem].ubReadyTime * max(0, (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) - gSkillTraitValues.ubGSPercentReadyPistolsReduction * NUM_SKILL_TRAITS(pSoldier, GUNSLINGER_NT) ) ) / 100); + } + else + { + rt1 = Weapon[usItem].ubReadyTime * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) / 100; + rt2 = Weapon[pSoldier->inv[SECONDHANDPOS].usItem].ubReadyTime * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ SECONDHANDPOS ]) ) / 100; + } return( max(rt1,rt2) + APBPConstants[AP_READY_DUAL] ); } @@ -2369,9 +2783,25 @@ INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) if (Weapon[ usItem ].ubReadyTime == 0) { return 0; } - else { - return ( Weapon[ usItem ].ubReadyTime - * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) ) / 100; + else + { + // SANDRO - STOMP traits + // Decrease APs to ready LMG if having Auto Weapon trait + if ( (Weapon[usItem].ubWeaponType == GUN_LMG) && HAS_SKILL_TRAIT(pSoldier, AUTO_WEAPONS_NT) && ( gGameOptions.fNewTraitSystem )) + { + return (INT16)(( Weapon[ usItem ].ubReadyTime + * max(0, (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) - gSkillTraitValues.ubAWPercentReadyLMGReduction * NUM_SKILL_TRAITS(pSoldier, AUTO_WEAPONS_NT) ) ) / 100)); // -10% per trait + } + // Decrease APs to ready pistols and revolvers if having Gunslinger trait + else if ( (Weapon[usItem].ubWeaponType == GUN_PISTOL) && HAS_SKILL_TRAIT(pSoldier, GUNSLINGER_NT) && ( gGameOptions.fNewTraitSystem )) + { + return (INT16)(( Weapon[ usItem ].ubReadyTime + * max(0, (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) - gSkillTraitValues.ubGSPercentReadyPistolsReduction * NUM_SKILL_TRAITS(pSoldier, GUNSLINGER_NT) ) ) / 100)); // -15% per trait + } + //Normal ready time + else + return (INT16)(( Weapon[ usItem ].ubReadyTime + * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) ) / 100); } } } @@ -2382,32 +2812,128 @@ INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) INT16 GetAPsToClimbRoof( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ) { + // SANDRO - STOMP traits - added a feature to reduce APs needed to climb on or off roof for Martial Arts trait + UINT16 iAPsToClimb = 0; + + if ( !fClimbDown ) + { + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + iAPsToClimb = max( 1, (INT16)((APBPConstants[AP_CLIMBROOF] * ( 100 - gSkillTraitValues.ubMAAPsClimbOrJumpReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5)); // -25% per trait + else + iAPsToClimb = APBPConstants[AP_CLIMBROOF]; + + // OK, add aps to goto stand stance... + iAPsToClimb += GetAPsToChangeStance( pSoldier, ANIM_STAND ); + } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + iAPsToClimb = max( 1, (INT16)((APBPConstants[AP_CLIMBOFFROOF] * ( 100 - gSkillTraitValues.ubMAAPsClimbOrJumpReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5)); // -25% per trait + else + iAPsToClimb = APBPConstants[AP_CLIMBOFFROOF]; + + // Add aps to goto crouch + iAPsToClimb += GetAPsToChangeStance( pSoldier, ANIM_CROUCH ); + } + + // A check if we don't go to zero somehow - SANDRO + if( iAPsToClimb < 1 ) + iAPsToClimb = 1; + + // return our value + return(iAPsToClimb); +} + +INT16 GetAPsToJumpThroughWindows( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ) +{ + //return( GetAPsToChangeStance( pSoldier, ANIM_STAND ) + APBPConstants[AP_JUMPWINDOW] ); + + // SANDRO - STOMP traits - added a feature to reduce APs needed to jump through window for Martial Arts trait + UINT16 iAPsToJump = 0; + + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + iAPsToJump = max( 1, (INT16)(( APBPConstants[AP_JUMPWINDOW] * ( 100 - gSkillTraitValues.ubMAAPsClimbOrJumpReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5)); // -25% per trait + else + iAPsToJump = APBPConstants[AP_JUMPWINDOW]; + if ( !fClimbDown ) { // OK, add aps to goto stand stance... - return(( APBPConstants[AP_CLIMBROOF] + GetAPsToChangeStance( pSoldier, ANIM_STAND ) ) ); + iAPsToJump += GetAPsToChangeStance( pSoldier, ANIM_STAND ); } else { // Add aps to goto crouch - return(( APBPConstants[AP_CLIMBOFFROOF] + GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) ) ); + iAPsToJump += GetAPsToChangeStance( pSoldier, ANIM_CROUCH ); } -} + return( iAPsToJump ); + +} INT16 GetBPsToClimbRoof( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ) { + // SANDRO - STOMP traits - Athletics reduce breath points spent for moving if ( !fClimbDown ) { - return( APBPConstants[BP_CLIMBROOF] ); + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + return( APBPConstants[BP_CLIMBROOF] * (100 - gSkillTraitValues.ubATBPsMovementReduction) / 100 ); + else + return( APBPConstants[BP_CLIMBROOF] ); + } else { - return( APBPConstants[BP_CLIMBOFFROOF] ); + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + return( APBPConstants[BP_CLIMBOFFROOF] * (100 - gSkillTraitValues.ubATBPsMovementReduction) / 100 ); + else + return( APBPConstants[BP_CLIMBOFFROOF] ); } } +// SANDRO - added function to calculate APs for jumping over fence +INT16 GetAPsToJumpFence( SOLDIERTYPE *pSoldier, BOOLEAN fWithBackpack ) +{ + // STOMP traits - Martial Arts reduce APs spent for jumping obstacles + if ( !fWithBackpack ) + { + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT )) + return( max( 1, (INT16)((APBPConstants[AP_JUMPFENCE] * ( 100 - gSkillTraitValues.ubMAAPsClimbOrJumpReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))); // -25% per trait + else + return( APBPConstants[AP_JUMPFENCE] ); + + } + else + { + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT )) + return( max( 1, (INT16)((APBPConstants[AP_JUMPFENCEBPACK] * ( 100 - gSkillTraitValues.ubMAAPsClimbOrJumpReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))); // -25% per trait + else + return( APBPConstants[AP_JUMPFENCEBPACK] ); + } +} + +// SANDRO - added function to calculate BPs for jumping over fence +INT16 GetBPsToJumpFence( SOLDIERTYPE *pSoldier, BOOLEAN fWithBackpack ) +{ + // STOMP traits - Athletics reduce breath points spent for moving + if ( !fWithBackpack ) + { + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + return( APBPConstants[BP_JUMPFENCE] * (100 - gSkillTraitValues.ubATBPsMovementReduction) / 100 ); + else + return( APBPConstants[BP_JUMPFENCE] ); + + } + else + { + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT )) + return( APBPConstants[BP_JUMPFENCEBPACK] * (100 - gSkillTraitValues.ubATBPsMovementReduction) / 100 ); + else + return( APBPConstants[BP_JUMPFENCEBPACK] ); + } +} + INT16 GetAPsToCutFence( SOLDIERTYPE *pSoldier ) { // OK, it's normally just cost, but add some if different stance... @@ -2507,7 +3033,7 @@ INT16 MinAPsToThrow( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCos // iAPCost += APBPConstants[AP_CHANGE_TARGET]; //} - iAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND ); + //iAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND ); // moved lower - SANDRO // Calculate default top & bottom of the magic "aiming" formula) @@ -2531,6 +3057,22 @@ INT16 MinAPsToThrow( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCos // This works because 'top' is 2x what it really should be throughout iAPCost += ( ( ( 100 * iTop ) / iBottom) + 1) / 2; + // SANDRO - STOMP traits - reduce APs needed to throw grenades if having Demolitions skill + if( HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT ) && gGameOptions.fNewTraitSystem ) + { + if ( Item[ usInHand ].usItemClass & IC_GRENADE ) + { + iAPCost = max( 1, (INT32)(iAPCost * (100 - gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction) / 100)); + } + // if we've thrown the object for real, it disapears from our hands and is converted to TempObject + else if ( pSoldier->pTempObject != NULL && pSoldier->pThrowParams != NULL && + pSoldier->pThrowParams->ubActionCode == THROW_ARM_ITEM && (Item[ pSoldier->pTempObject->usItem ].usItemClass & IC_GRENADE) ) + { + iAPCost = max( 1, (INT32)(iAPCost * (100 - gSkillTraitValues.ubDEAPsNeededToThrowGrenadesReduction) / 100)); + } + } + + iAPCost += GetAPsToChangeStance( pSoldier, ANIM_STAND ); // moved from above - SANDRO // the minimum AP cost of ANY throw can NEVER be more than merc has APs! if ( iAPCost > iFullAPs ) @@ -2546,12 +3088,20 @@ INT16 MinAPsToThrow( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCos INT16 GetAPsToDropBomb( SOLDIERTYPE *pSoldier ) { - return( APBPConstants[AP_DROP_BOMB] ); + // SANDRO - STOMP traits - Ambidextrous bonus + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_DROP_BOMB] * (100 - gSkillTraitValues.ubAMHandleBombsAPsReduction)/100 ) + 0.5)) ); + else + return( APBPConstants[AP_DROP_BOMB] ); } INT16 GetAPsToPlantMine( SOLDIERTYPE *pSoldier ) { - return( APBPConstants[AP_BURY_MINE] ); + // SANDRO - STOMP traits - Ambidextrous bonus + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_BURY_MINE] * (100 - gSkillTraitValues.ubAMHandleBombsAPsReduction)/100 ) + 0.5)) ); + else + return( APBPConstants[AP_BURY_MINE] ); } UINT16 GetTotalAPsToDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ) @@ -2563,9 +3113,9 @@ UINT16 GetTotalAPsToDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ) if ( sAPs > 0 ) { if(Item[pSoldier->inv[HANDPOS].usItem].mine == 1) - sAPs += APBPConstants[AP_BURY_MINE]; + sAPs += GetAPsToPlantMine( pSoldier ); // changed by SANDRO else - sAPs += APBPConstants[AP_DROP_BOMB]; + sAPs += GetAPsToDropBomb( pSoldier ); // changed by SANDRO } return( sAPs ); @@ -2579,17 +3129,31 @@ INT16 GetAPsToUseRemote( SOLDIERTYPE *pSoldier ) } -INT16 GetAPsToStealItem( SOLDIERTYPE *pSoldier, INT32 usMapPos ) +INT16 GetAPsToStealItem( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT16 sMapPos ) // SANDRO - added target { INT16 sAPCost = 0; - if (usMapPos != -1) + if (sMapPos != -1) { - sAPCost = PlotPath( pSoldier, usMapPos, NO_COPYROUTE, NO_PLOT, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints ); + sAPCost = PlotPath( pSoldier, sMapPos, NO_COPYROUTE, NO_PLOT, TEMPORARY, (UINT16)pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints ); } // ADD APS TO PICKUP - sAPCost += APBPConstants[AP_STEAL_ITEM]; + ///////////////////////////////////////////////////////////////////////////////////////// + // CHANGED BY SANDRO - REDUCE AP COST TO STEAL FOR MARTIAL ARTS AND HAND TO HAND + if (pTargetSoldier != NULL && pTargetSoldier->bCollapsed && gGameExternalOptions.fEnhancedCloseCombatSystem) + { + sAPCost += (GetBasicAPsToPickupItem( pSoldier )); // stealing from collapsed soldiers is treated differently + } + else if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && ( gGameOptions.fNewTraitSystem )) + { + sAPCost += max( 1, (INT16)((APBPConstants[AP_STEAL_ITEM] * (100 - gSkillTraitValues.ubMAReducedAPsToSteal * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/ 100) + 0.5)); + } + else + { + sAPCost += APBPConstants[AP_STEAL_ITEM]; + } + ///////////////////////////////////////////////////////////////////////////////////////// // CJC August 13 2002: added cost to stand into equation if (!(PTR_STANDING)) @@ -2644,7 +3208,11 @@ INT16 GetAPsToUseCan( SOLDIERTYPE *pSoldier, INT32 usMapPos ) INT16 GetAPsToJumpOver( SOLDIERTYPE *pSoldier ) { - return( GetAPsToChangeStance( pSoldier, ANIM_STAND ) + APBPConstants[AP_JUMP_OVER] ); + // -25% APs needed to for MA traits + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + return( GetAPsToChangeStance( pSoldier, ANIM_STAND ) + max( 1, (INT16)((APBPConstants[AP_JUMP_OVER] * (100 - gSkillTraitValues.ubMAAPsClimbOrJumpReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/100) + 0.5))); + else + return( GetAPsToChangeStance( pSoldier, ANIM_STAND ) + APBPConstants[AP_JUMP_OVER] ); } // HEADROCK HAM 3.6: Calculate the actual AP cost to add this many Extra Aiming levels, taking into account @@ -2677,8 +3245,8 @@ INT32 CalcAPCostForAiming( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, INT8 bAim // If the weapon has a scope, and the target is within eligible range for scope use - if ( IsScoped(&pSoldier->inv[HANDPOS]) - && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) >= GetMinRangeForAimBonus(&pSoldier->inv[HANDPOS]) ) + if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS]) && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) >= GetMinRangeForAimBonus(&pSoldier->inv[HANDPOS])) + || (UsingNewCTHSystem() == true && GetBestScopeMagnificationFactor(&pSoldier->inv[HANDPOS], GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) > 1.0 ))) { // Add an individual cost for EACH click, as necessary. @@ -2726,11 +3294,11 @@ INT8 CalcAimingLevelsAvailableWithAP( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo { INT8 bAllowedLevels = 0; - for (INT16 x = APBPConstants[AP_MIN_AIM_ATTACK]; x <= AllowedAimingLevels(pSoldier); x++) + for (INT16 x = APBPConstants[AP_MIN_AIM_ATTACK]; x <= AllowedAimingLevels(pSoldier, sTargetGridNo); x++) { - if (CalcAPCostForAiming( pSoldier, sTargetGridNo, x ) <= (INT16)bAPsLeft) + if (CalcAPCostForAiming( pSoldier, sTargetGridNo, (INT8)x ) <= (INT32)bAPsLeft) { - bAllowedLevels = x; + bAllowedLevels = (INT8)x; } else { @@ -2739,3 +3307,108 @@ INT8 CalcAimingLevelsAvailableWithAP( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo } return (bAllowedLevels); } + + +// SANDRO - Added feature to reduce APs for change states, if having MA trait +INT16 GetAPsCrouch( SOLDIERTYPE *pSoldier, BOOLEAN fBackpackCheck ) +{ + UINT16 iFinalAPsToCrouch; + + iFinalAPsToCrouch = APBPConstants[AP_CROUCH]; + + // if backpack and new inventory + if ( fBackpackCheck && (UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) + iFinalAPsToCrouch += 1; + + // -x% APs needed to change stance for MA trait + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && ( gGameOptions.fNewTraitSystem )) + iFinalAPsToCrouch = (INT16)((iFinalAPsToCrouch * ( 100 - gSkillTraitValues.ubMAAPsChangeStanceReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ); + + if (iFinalAPsToCrouch < 1 ) + iFinalAPsToCrouch = 1; + + return( iFinalAPsToCrouch ); +} +// SANDRO - Added feature to reduce APs for change states, if having MA trait +INT16 GetAPsProne( SOLDIERTYPE *pSoldier, BOOLEAN fBackpackCheck ) +{ + UINT16 iFinalAPsToLieDown; + + iFinalAPsToLieDown = APBPConstants[AP_PRONE]; + + // if backpack and new inventory + if ( fBackpackCheck && (UsingNewInventorySystem() == true) && pSoldier->inv[BPACKPOCKPOS].exists() == true && !pSoldier->flags.ZipperFlag) + iFinalAPsToLieDown += 1; + + // -x% APs needed to change stance for MA trait + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && ( gGameOptions.fNewTraitSystem )) + iFinalAPsToLieDown = (INT16)((iFinalAPsToLieDown * ( 100 - gSkillTraitValues.ubMAAPsChangeStanceReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ); + + if (iFinalAPsToLieDown < 1 ) + iFinalAPsToLieDown = 1; + + return( iFinalAPsToLieDown ); +} +// SANDRO - Added feature to calculate start run cost (for Athletics trait) +INT16 GetAPsStartRun( SOLDIERTYPE *pSoldier ) +{ + // Athletics trait + if ( HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT ) && gGameOptions.fNewTraitSystem ) + return( max( 1, (INT16)((APBPConstants[AP_START_RUN_COST] * (100 - gSkillTraitValues.ubATAPsMovementReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_START_RUN_COST] ); +} + +// SANDRO - Added feature to calculate APs for handling doors (for Ambidextrous trait) +INT16 GetAPsToOpenDoor( SOLDIERTYPE *pSoldier ) +{ + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_OPEN_DOOR] * (100 - gSkillTraitValues.ubAMHandleDoorsAPsReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_OPEN_DOOR] ); +} + +// SANDRO - Added feature to calculate APs for handling doors (for Ambidextrous trait) +INT16 GetAPsToPicklock( SOLDIERTYPE *pSoldier ) +{ + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_PICKLOCK] * (100 - gSkillTraitValues.ubAMHandleDoorsAPsReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_PICKLOCK] ); +} + +// SANDRO - Added feature to calculate APs for handling doors (for Ambidextrous trait) +INT16 GetAPsToBombDoor( SOLDIERTYPE *pSoldier ) +{ + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_EXPLODE_DOOR] * (100 - gSkillTraitValues.ubAMHandleDoorsAPsReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_EXPLODE_DOOR] ); +} + +// SANDRO - Added feature to calculate APs for handling doors (for Ambidextrous trait) +INT16 GetAPsToUntrapDoor( SOLDIERTYPE *pSoldier ) +{ + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_UNTRAP_DOOR] * (100 - gSkillTraitValues.ubAMHandleDoorsAPsReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_UNTRAP_DOOR] ); +} + +// SANDRO - Added feature to calculate APs for pickup items (for Ambidextrous trait) +INT16 GetBasicAPsToPickupItem( SOLDIERTYPE *pSoldier ) +{ + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_PICKUP_ITEM] * (100 - gSkillTraitValues.ubAMPickItemsAPsReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_PICKUP_ITEM] ); +} + +// SANDRO - Added feature to calculate APs for disarming mine (for Ambidextrous trait) +INT16 GetAPsToDisarmMine( SOLDIERTYPE *pSoldier ) +{ + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ) + return( max( 1, (INT16)((APBPConstants[AP_DISARM_MINE] * (100 - gSkillTraitValues.ubAMHandleBombsAPsReduction)/100) + 0.5 )) ); + else + return( APBPConstants[AP_DISARM_MINE] ); +} \ No newline at end of file diff --git a/Tactical/Points.h b/Tactical/Points.h index 7a3d0df8..d220569b 100644 --- a/Tactical/Points.h +++ b/Tactical/Points.h @@ -113,6 +113,7 @@ #define AP_JUMPFENCE 6 // time to jump over a fence #define AP_JUMPFENCEBPACK 10 // time to jump over a fence +#define AP_JUMPWINDOW 10 // APs to Jump window #define AP_OPEN_SAFE 8 // time to use combination @@ -195,8 +196,6 @@ #define BP_JUMPFENCE 200 // BPs to jump fence #define BP_JUMPFENCEBPACK 500 // BPs to jump fence - - //#define BP_MOVE_ITEM_FREE 0 // same place, pocket->pocket //#define BP_MOVE_ITEM_FAST 0 // hand, holster, ground only //#define BP_MOVE_ITEM_AVG 0 // everything else! @@ -277,8 +276,12 @@ extern INT16 APBPConstants[TOTAL_APBP_VALUES]; INT16 BaseAPsToShootOrStab( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * pObj ); +// HEADROCK HAM 4: Same function as above, except no modifier. +INT16 BaseAPsToShootOrStabNoModifier( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * pObj ); +// HEADROCK HAM 4: Same function as above, except no modifier. +INT16 BaseAPsToShootOrStabNoModifier( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * pObj ); -INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, INT8 bLevel ); +INT16 TerrainActionPoints( SOLDIERTYPE *pSoldier, INT32 sGridno, INT8 bDir, INT8 bLevel ); INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 usMovementMode ); INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 usMovementMode, INT8 bPathIndex, INT8 bPathLength ); BOOLEAN SelectedMercCanAffordMove( ); @@ -301,11 +304,21 @@ void DeductAmmo( SOLDIERTYPE *pSoldier, INT8 bInvPos ); UINT16 GetAPsToPickupItem( SOLDIERTYPE *pSoldier, INT32 usMapPos ); INT16 MinAPsToPunch(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost ); +INT16 ApsToPunch( SOLDIERTYPE *pSoldier ); // SANDRO added this INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, INT16 bAimTime ); INT16 CalcAPsToBurst( INT16 bBaseActionPoints, OBJECTTYPE * pObj ); +// HEADROCK HAM 4: Same as above, without percent modifiers. +INT16 CalcAPsToBurstNoModifier( INT16 bBaseActionPoints, OBJECTTYPE * pObj ); +// HEADROCK HAM 4: Same as above, without percent modifiers. +INT16 CalcAPsToBurstNoModifier( INT16 bBaseActionPoints, OBJECTTYPE * pObj ); INT16 CalcAPsToAutofire( INT16 bBaseActionPoints, OBJECTTYPE * pObj, UINT8 bDoAutofire ); +// HEADROCK HAM 4: Same as above, without modifiers +INT16 CalcAPsToAutofireNoModifier( INT16 bBaseActionPoints, OBJECTTYPE * pObj, UINT8 bDoAutofire ); +// HEADROCK HAM 4: Same as above, without modifiers +INT16 CalcAPsToAutofireNoModifier( INT16 bBaseActionPoints, OBJECTTYPE * pObj, UINT8 bDoAutofire ); INT16 GetAPsToChangeStance( SOLDIERTYPE *pSoldier, INT8 bDesiredHeight ); -INT16 GetBPsToChangeStance( SOLDIERTYPE *pSoldier, INT8 bDesiredHeight ); +// SANDRO - actually this procedure is nowhere used in the entire JA2 code - commented out +//INT16 GetBPsToChangeStance( SOLDIERTYPE *pSoldier, INT8 bDesiredHeight ); INT16 GetAPsToLook( SOLDIERTYPE *pSoldier ); UINT16 GetAPsToGiveItem( SOLDIERTYPE *pSoldier, INT32 usMapPos ); @@ -317,8 +330,10 @@ INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ); INT16 GetAPsToClimbRoof( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ); INT16 GetBPsToClimbRoof( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ); -INT16 GetAPsToJumpFence( SOLDIERTYPE *pSoldier ); -INT16 GetBPsToJumpFence( SOLDIERTYPE *pSoldier ); +INT16 GetAPsToJumpThroughWindows( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ); //Jump +// SANDRO - changed these 2 +INT16 GetAPsToJumpFence( SOLDIERTYPE *pSoldier, BOOLEAN fWithBackpack ); +INT16 GetBPsToJumpFence( SOLDIERTYPE *pSoldier, BOOLEAN fWithBackpack ); INT16 GetAPsToCutFence( SOLDIERTYPE *pSoldier ); INT16 GetAPsToBeginFirstAid( SOLDIERTYPE *pSoldier ); @@ -332,7 +347,7 @@ INT16 GetAPsToPlantMine( SOLDIERTYPE *pSoldier ); UINT16 GetTotalAPsToDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ); INT16 GetAPsToUseRemote( SOLDIERTYPE *pSoldier ); -INT16 GetAPsToStealItem( SOLDIERTYPE *pSoldier, INT32 usMapPos ); +INT16 GetAPsToStealItem( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT16 sMapPos ); // SANDRO - added target INT16 GetBPsToStealItem( SOLDIERTYPE *pSoldier ); INT16 GetAPsToUseJar( SOLDIERTYPE *pSoldier, INT32 usMapPos ); @@ -350,4 +365,15 @@ INT16 GetAPsToAutoReload( SOLDIERTYPE * pSoldier ); INT32 CalcAPCostForAiming( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, INT8 bAimTime ); INT8 CalcAimingLevelsAvailableWithAP( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, INT8 bAPsLeft ); +// SANDRO - added these: +INT16 GetAPsCrouch( SOLDIERTYPE *pSoldier, BOOLEAN fBackpackCheck ); +INT16 GetAPsProne( SOLDIERTYPE *pSoldier, BOOLEAN fBackpackCheck ); +INT16 GetAPsStartRun( SOLDIERTYPE *pSoldier ); +INT16 GetAPsToOpenDoor( SOLDIERTYPE *pSoldier ); +INT16 GetAPsToPicklock( SOLDIERTYPE *pSoldier ); +INT16 GetAPsToBombDoor( SOLDIERTYPE *pSoldier ); +INT16 GetAPsToUntrapDoor( SOLDIERTYPE *pSoldier ); +INT16 GetBasicAPsToPickupItem( SOLDIERTYPE *pSoldier ); +INT16 GetAPsToDisarmMine( SOLDIERTYPE *pSoldier ); + #endif diff --git a/Tactical/QARRAY.cpp b/Tactical/QARRAY.cpp index dd97234f..3331e140 100644 --- a/Tactical/QARRAY.cpp +++ b/Tactical/QARRAY.cpp @@ -5,6 +5,9 @@ #include "qarray.h" #endif +QARRAY_VALUES QuoteExp[NUM_PROFILES]; + + BOOLEAN QuoteExp_HeadShotOnly[NUM_PROFILES] = { // this is for quote 33 (0=generic grossout, 1=headshot specific) diff --git a/Tactical/Real Time Input.cpp b/Tactical/Real Time Input.cpp index 61c58d2e..87e7ed27 100644 --- a/Tactical/Real Time Input.cpp +++ b/Tactical/Real Time Input.cpp @@ -64,6 +64,16 @@ #include "Militia Control.h" #include "render dirty.h" #include "Militia Control.h" +///***dddd +#include "Squads.h" +#include "Interface Panels.h" +#include "Soldier functions.h" +#include "SaveLoadMap.h" +#include "worlddat.h" //for gtileset +#include "Debug Control.h" //for livelog + + + #endif @@ -85,6 +95,11 @@ extern INT32 gsOverItemsGridNo; extern INT16 gsOverItemsLevel; extern UINT32 guiUITargetSoldierId; extern BOOLEAN gfUIShowExitSouth; +//***ddd +extern BOOLEAN fMiddleButtonDown; +extern BOOLEAN fX1ButtonDown; +extern BOOLEAN fX2ButtonDown; +extern SOLDIERTYPE *gpSMCurrentMerc; BOOLEAN gfStartLookingForRubberBanding = FALSE; @@ -99,11 +114,23 @@ BOOLEAN gfRTHaveClickedRightWhileLeftDown = FALSE; extern BOOLEAN ValidQuickExchangePosition( ); +extern INT32 iSMPanelButtons[ NUM_SM_BUTTONS ]; +extern INT32 iTEAMPanelButtons[ NUM_TEAM_BUTTONS ]; +extern INT32 giSMStealthButton; + +void QueryRTMButton( UINT32 *puiNewEvent ); +void QueryRTWheels( UINT32 *puiNewEvent ); +void QueryRTX1Button( UINT32 *puiNewEvent ); +void QueryRTX2Button( UINT32 *puiNewEvent ); void GetRTMouseButtonInput( UINT32 *puiNewEvent ) { QueryRTLeftButton( puiNewEvent ); QueryRTRightButton( puiNewEvent ); + QueryRTMButton( puiNewEvent ); + QueryRTWheels( puiNewEvent ); + QueryRTX1Button( puiNewEvent ); + QueryRTX2Button( puiNewEvent ); } void QueryRTLeftButton( UINT32 *puiNewEvent ) @@ -1562,6 +1589,446 @@ void GetRTMousePositionInput( UINT32 *puiNewEvent ) } } +//***13.02.2008*** +//usSubIndex 1 10 +//void PlaceSandbag (UINT16 usSubIndex) +//{ +// INT16 sGridNo; +// UINT16 usIndex, cnt; +// INT8 bOverTerrainType; +// UINT32 uiType; +// //SECTORINFO *pSector; +// +// /*if( (gTacticalStatus.uiFlags & INCOMBAT) && (gTacticalStatus.uiFlags & TURNBASED) ) +// { +// return; +// } +// +// if( gWorldSectorX != -1 && gWorldSectorY != -1 && gWorldSectorX != 0 && gWorldSectorY != 0 && +// NumEnemiesInAnySector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ) > 0 ) +// { +// return; +// } +// +// if( gbWorldSectorZ > 0 || gsInterfaceLevel > 0) +// { +// return; +// } +// +// for(uiType = 0; uiType < NUMBEROFTILETYPES; uiType++) +// { +// if( !gTilesets[ giCurrentTilesetID].TileSurfaceFilenames[ uiType ][0] ) +// { +// if( !_strnicmp(gTilesets[ 0 ].TileSurfaceFilenames[ uiType ], "sandbag.sti", 11) ) +// break; +// } +// else +// { +// if( !_strnicmp(gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiType ], "sandbag.sti", 11) ) +// break; +// } +// } +// +// if(uiType >= NUMBEROFTILETYPES) +// return;*/ +// +// if( GetMouseMapPos( &sGridNo ) ) +// { +// //if( InARoom( sGridNo, NULL ) ) +// // return; +// +// //bOverTerrainType = GetTerrainType( sGridNo ); +// //if( bOverTerrainType == MED_WATER || bOverTerrainType == DEEP_WATER || bOverTerrainType == LOW_WATER ) +// // return; +// +// //pSector = &SectorInfo[ SECTOR(gWorldSectorX, gWorldSectorY) ]; +// //if( pSector->bUSUSED <= 0 ) // +// //{ +// // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"No Sandbags"); +// //} +//usIndex =1; +// //GetTileIndexFromTypeSubIndex( SECONDLARGEEXPDEBRIS, usSubIndex, &usIndex ); // 0 +//GetTileIndexFromTypeSubIndex( 150, usSubIndex, &usIndex ); // 0 +//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"No Sandbags"); +// //GetTileIndexFromTypeSubIndex( SECONDLARGEEXPDEBRIS, usSubIndex, &usIndex ); +// ApplyMapChangesToMapTempFile( TRUE ); +// AddStructToHead( sGridNo, usIndex); +// //if( pSector->bUSUSED <= 0 || !AddStructToHead( sGridNo, usIndex ) ) +// //{ +// // +// // for(cnt = 1; cnt <= 10; cnt++) +// // { +// // GetTileIndexFromTypeSubIndex( uiType, cnt, &usIndex ); +// // if(RemoveStruct( sGridNo, usIndex )) +// // { +// // RecompileLocalMovementCosts(sGridNo); +// // pSector->bUSUSED += 1; +// // break; +// // } +// // } +// //} +// //else +// //{ +// RecompileLocalMovementCosts(sGridNo); +//// pSector->bUSUSED -= 1; +// //} +// ApplyMapChangesToMapTempFile( FALSE ); +// SetRenderFlags( RENDER_FLAG_FULL ); +// } +// +//} +// +// +// + +void QueryRTMButton( UINT32 *puiNewEvent ) +{ + INT32 sMapPos; + + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + + if (gViewportRegion.ButtonState & MSYS_MIDDLE_BUTTON) // MID MOUSE BUTTON + { + if ( !fMiddleButtonDown ) + { + fMiddleButtonDown = TRUE; + //RESETCOUNTER( RMOUSECLICK_DELAY_COUNTER ); + } + } + else if ( fMiddleButtonDown ) + { + + /////ddd{ test okop placement + //if ( _KeyDown( CTRL ) ) + //{ + // + // PlaceSandbag(1); + // fMiddleButtonDown = FALSE; + // return; + //} + /////ddd } + + if ( _KeyDown( ALT ) ) + { + // + if ( ( gpItemPointer == NULL ) && ( gusSelectedSoldier != NOBODY ) && + ( ( gsCurInterfacePanel != SM_PANEL ) || ( ButtonList[ iSMPanelButtons[ BURSTMODE_BUTTON ] ]->uiFlags & BUTTON_ENABLED ) ) ) + ChangeWeaponMode( MercPtrs[ gusSelectedSoldier ] ); + } + else + *puiNewEvent = LC_LOOK; + + + + fMiddleButtonDown = FALSE; + // Reset counter + //RESETCOUNTER( RMOUSECLICK_DELAY_COUNTER ); + } + } +}//void QueryRTMButton( UINT32 *puiNewEvent ) + + +void QueryRTWheels( UINT32 *puiNewEvent ) +{ + INT32 sMapPos=0; + UINT8 bID; + + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + if ( gViewportRegion.WheelState != 0 ) + { +// printf("wheel %d\n", gViewportRegion.WheelState);MessageBeep(0x00000040L); + if ( gpItemPointer == NULL ) + { + if ( gusSelectedSoldier != NOBODY ) + { + // Switch on UI mode + switch( gCurrentUIMode ) + { + case IDLE_MODE: + case MOVE_MODE: + + // nothing in hand and either not in SM panel, or the matching button is enabled if we are in SM panel + if ( !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) && + ( ( gsCurInterfacePanel != SM_PANEL ) || ( ButtonList[ iSMPanelButtons[ NEXTMERC_BUTTON ] ]->uiFlags & BUTTON_ENABLED ) ) ) + { + if ( gViewportRegion.WheelState > 0 ) // + { + //change stance ->DOWN + if ( _KeyDown( ALT ) ) + { if ( (gusSelectedSoldier != NOBODY) && ( gpItemPointer == NULL ) ) + GotoLowerStance(MercPtrs[ gusSelectedSoldier ]); + break; + } + + if ( gusSelectedSoldier != NOBODY ) + { //Select prev merc + bID = FindPrevActiveAndAliveMerc( MercPtrs[ gusSelectedSoldier ], TRUE, TRUE ); + HandleLocateSelectMerc( bID, LOCATEANDSELECT_MERC ); + // Center to guy.... + LocateSoldier( gusSelectedSoldier, SETLOCATOR ); + } + } + else + { + + //change stance ->UP + if ( _KeyDown( ALT ) ) + { if ( (gusSelectedSoldier != NOBODY) && ( gpItemPointer == NULL ) ) + GotoHeigherStance( MercPtrs[ gusSelectedSoldier ] ); + break; + } + + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"wheel %d", gViewportRegion.WheelState); + if ( gusSelectedSoldier != NOBODY ) + { //Select next merc + bID = FindNextMercInTeamPanel( MercPtrs[ gusSelectedSoldier ], FALSE, FALSE ); + HandleLocateSelectMerc( bID, LOCATEANDSELECT_MERC ); + // Center to guy.... + LocateSoldier( gusSelectedSoldier, SETLOCATOR ); + } + } + //*puiNewEvent = M_ON_TERRAIN; ???????????????? + } + break; + case ACTION_MODE: + case CONFIRM_MOVE_MODE: + case HANDCURSOR_MODE: + case LOOKCURSOR_MODE: + case TALKCURSOR_MODE: + case MENU_MODE: + break; + case CONFIRM_ACTION_MODE: // . ;) + break; + }//switch + }//if ( gusSelectedSoldier != NOBODY ) + }//if ( gpItemPointer == NULL + ResetWheelState( &gViewportRegion ); + }//if ( gViewportRegion.WheelState != 0 ) + } +}//void QueryRTWheels( UINT32 *puiNewEvent ) +void QueryRTX1Button( UINT32 *puiNewEvent ) +{ + INT32 sMapPos; + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + + if (gViewportRegion.ButtonState & MSYS_X1_BUTTON) // MID MOUSE BUTTON + { + if ( !fX1ButtonDown ) + { + fX1ButtonDown = TRUE; + } + } + else if ( fX1ButtonDown ) + { + fX1ButtonDown = FALSE; + if ( !_KeyDown( ALT ) && !_KeyDown( SHIFT )) + UIHandleChangeLevel( NULL ); + else if( _KeyDown( SHIFT ) ) + { + + +//dddokno ============================================={ +//INT16 sGridNo; +//STRUCTURE * pStructure; +// +//GetMouseMapPos( &sGridNo ); +//ScreenMsg( FONT_MCOLOR_LTYELLOW,0, L"gubMerkCanSeeThisTile=%d,gubWorldTileInLight=%d",gubMerkCanSeeThisTile[sGridNo],gubWorldTileInLight[sGridNo]); +//pStructure = gpWorldLevelData[sGridNo].pStructureHead; +// +//SOLDIERTYPE *pSoldier; +//GetSoldier( &pSoldier, gusSelectedSoldier ); +// +//LEVELNODE *pNode = NULL; UINT32 uiTileType=0; +//pNode = gpWorldLevelData[ sGridNo ].pStructHead; +// +//GetTileType( pNode->usIndex, &uiTileType ); +// +//CHAR8 errorBuf[511]; +// +//sprintf(errorBuf, "Tile=%s at line %d", +//gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiTileType ], uiTileType); +//LiveMessage(errorBuf); + + + //if ( _stricmp( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiTileType ], "build_13.sti" ) == 0 ) + //{ +// UINT16 sNewIndex; +// GetTileIndexFromTypeSubIndex( gTileDatabase[ pNode->usIndex ].fType, uiTileType, (UINT16 *)&sNewIndex ); +// //GetTileIndexFromTypeSubIndex( STRUCTURE_WALLNWINDOW, uiTileType, (UINT16 *)&sNewIndex ); +// +// ScreenMsg( FONT_MCOLOR_LTYELLOW,0, L"13 found=%d,strID=%d",sNewIndex,pNode->usIndex); +// +// UINT16 pusSubIndex; +// GetSubIndexFromTileIndex( pNode->usIndex, (UINT16 *)&pusSubIndex ); +// ScreenMsg( FONT_MCOLOR_LTYELLOW,0, L"subidx=%d",pusSubIndex); +// sprintf(errorBuf, "subidx= %d", pusSubIndex); +//LiveMessage(errorBuf); + + +//STRUCTURE *pBase; +//UINT16 pusSubIndex; +//pBase = FindStructure( sGridNo, STRUCTURE_WALLNWINDOW ); +//pNode = FindLevelNodeBasedOnStructure( pBase->sGridNo, pBase ); +//GetSubIndexFromTileIndex( pNode->usIndex, (UINT16 *)&pusSubIndex ); +//ScreenMsg( FONT_MCOLOR_LTYELLOW,0, L"subidx=%d",pusSubIndex); + + + + //} +//dddokno ============================================= } + + //dddokno{ + // . -------------------------------------- + //SOLDIERTYPE *pjSoldier; + //BOOLEAN fNearHeigherLevel; + //BOOLEAN fNearLowerLevel; + //INT8 bDirection; + + //if ( GetSoldier( &pjSoldier, gusSelectedSoldier ) ) + //{ + // // CHRISL: Turn off manual jumping while wearing a backpack + // if(UsingNewInventorySystem() == true && pjSoldier->inv[BPACKPOCKPOS].exists() == true) + // return; + + // // Make sure the merc is not collapsed! + // if (!IsValidStance(pjSoldier, ANIM_CROUCH) ) + // { + // if ( pjSoldier->bCollapsed && pjSoldier->bBreath < OKBREATH ) + // { + // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pjSoldier->name ); + // } + + // return; + // } + //GetMercOknoDirection( pjSoldier->ubID, &fNearLowerLevel, &fNearHeigherLevel ); + //if ( FindOknoDirection( pjSoldier, pjSoldier->sGridNo, pjSoldier->ubDirection, &bDirection ) ) + // { + // BeginSoldierOkno( pjSoldier ); + // } + //} + //dddokno{ + // . ------------------------------------- + + } + else if (_KeyDown( ALT ) ) + { + + SOLDIERTYPE *pjSoldier; + if ( GetSoldier( &pjSoldier, gusSelectedSoldier ) ) + { + BOOLEAN fNearHeigherLevel; + BOOLEAN fNearLowerLevel; + INT8 bDirection; + // CHRISL: Turn off manual jumping while wearing a backpack + if(UsingNewInventorySystem() == true && pjSoldier->inv[BPACKPOCKPOS].exists() == true) + return; + + // Make sure the merc is not collapsed! + if (!IsValidStance(pjSoldier, ANIM_CROUCH) ) + { + if ( pjSoldier->bCollapsed && pjSoldier->bBreath < OKBREATH ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pjSoldier->name ); + return; + } + + GetMercClimbDirection( pjSoldier->ubID, &fNearLowerLevel, &fNearHeigherLevel ); + + if ( fNearLowerLevel ) + pjSoldier->BeginSoldierClimbDownRoof( ); + + if ( fNearHeigherLevel ) + pjSoldier->BeginSoldierClimbUpRoof( ); + + if ( FindFenceJumpDirection( pjSoldier, pjSoldier->sGridNo, pjSoldier->ubDirection, &bDirection ) ) + pjSoldier->BeginSoldierClimbFence( ); + } + + }//else + + } + } +} +void QueryRTX2Button( UINT32 *puiNewEvent ) +{ + INT32 sMapPos; + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + + if (gViewportRegion.ButtonState & MSYS_X2_BUTTON) // MID MOUSE BUTTON + { + if ( !fX2ButtonDown ) + { + fX2ButtonDown = TRUE; + } + } + else if ( fX2ButtonDown ) + { + fX2ButtonDown = FALSE; + + if ( _KeyDown( ALT ) ) + AutoReload( MercPtrs[ gusSelectedSoldier ] ); + else + // Toggle squad's stealth mode..... + // For each guy on squad... + { + SOLDIERTYPE *pTeamSoldier; + INT8 bLoop; + BOOLEAN fStealthOn = FALSE; + + // Check if at least one guy is on stealth.... + for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++) + { + if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) ) + { + if ( pTeamSoldier->bStealthMode ) + { + fStealthOn = TRUE; + } + } + } + + fStealthOn = !fStealthOn; + + for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++) + { + if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) ) + { + if ( gpSMCurrentMerc != NULL && bLoop == gpSMCurrentMerc->ubID ) + { + gfUIStanceDifferent = TRUE; + } + + pTeamSoldier->bStealthMode = fStealthOn; + } + } + + fInterfacePanelDirty = DIRTYLEVEL2; + + // OK, display message + if ( fStealthOn ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_SQUAD_ON_STEALTHMODE ] ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_SQUAD_OFF_STEALTHMODE ] ); + } + } + } + + } +} \ No newline at end of file diff --git a/Tactical/Rotting Corpses.cpp b/Tactical/Rotting Corpses.cpp index 99f144b3..6e809881 100644 --- a/Tactical/Rotting Corpses.cpp +++ b/Tactical/Rotting Corpses.cpp @@ -362,6 +362,7 @@ BOOLEAN CreateCorpsePalette( ROTTING_CORPSE *pCorpse ); BOOLEAN CreateCorpseShadedPalette( ROTTING_CORPSE *pCorpse, UINT32 uiBase, SGPPaletteEntry *pShadePal); void ReduceAmmoDroppedByNonPlayerSoldiers( SOLDIERTYPE *pSoldier, INT32 iInvSlot ); +void ReduceAttachmentsOnGunForNonPlayerChars(SOLDIERTYPE *pSoldier, OBJECTTYPE * pObj); @@ -811,7 +812,12 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE Corpse.dYPos = pSoldier->dYPos; Corpse.bLevel = pSoldier->pathing.bLevel; Corpse.ubProfile = pSoldier->ubProfile; - +///ddd{ . + if ( pSoldier->bTeam != gbPlayerNum ) + Corpse.ubAIWarningValue = 1; + //def.ubAIWarningValue = 1; //not used value! +///ddd} + if ( Corpse.bLevel > 0 ) { Corpse.sHeightAdjustment = (INT16)( pSoldier->sHeightAdjustment - WALL_HEIGHT ); @@ -949,6 +955,9 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE } } + if(UsingNewAttachmentSystem()==true){ + ReduceAttachmentsOnGunForNonPlayerChars(pSoldier, pObj); + } // HEADROCK HAM B2.8: Militia will drop items only if allowed. if (!(gGameExternalOptions.ubMilitiaDropEquipment == 0 && pSoldier->bTeam == MILITIA_TEAM ) && !(gGameExternalOptions.ubMilitiaDropEquipment == 1 && pSoldier->bTeam == MILITIA_TEAM && Menptr[ pSoldier->ubAttackerID ].bTeam == OUR_TEAM )) @@ -1314,7 +1323,7 @@ void MercLooksForCorpses( SOLDIERTYPE *pSoldier ) return; } - if ( QuoteExp_HeadShotOnly[ pSoldier->ubProfile ] == 1 ) + if ( QuoteExp[ pSoldier->ubProfile ].QuoteExpHeadShotOnly == 1 ) { return; } @@ -1879,7 +1888,37 @@ void ReduceAmmoDroppedByNonPlayerSoldiers( SOLDIERTYPE *pSoldier, INT32 iInvSlot } } +void ReduceAttachmentsOnGunForNonPlayerChars(SOLDIERTYPE *pSoldier, OBJECTTYPE * pObj){ + + //Not meant for use in OAS. + Assert(UsingNewAttachmentSystem()==true); + + //OBJECTTYPE * pObj = &(pSoldier->inv[ invSlot ]); + + //If this item has any attachments, is not from a player, and is overwriteable. It's also only for guns. + if((*pObj)[0]->AttachmentListSize() > 0 && pSoldier->bTeam != gbPlayerNum && !((*pObj).fFlags & OBJECT_NO_OVERWRITE) && Item[pObj->usItem].usItemClass == IC_GUN && !gGameOptions.fEnemiesDropAllItems){ + UINT8 slotCount = 0; + for(std::list::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter, ++slotCount){ + //A few conditions under which we will not delete this attachment + if(!iter->exists()) + continue; + //Loop to find out if this attachment is a default one, if so, we don't want to remove it. + int i; + for(i = 0; i < MAX_DEFAULT_ATTACHMENTS && Item[pObj->usItem].defaultattachments[i] != iter->usItem; i++){} + + if(Item[pObj->usItem].defaultattachments[i] != iter->usItem) + continue; + + //Erase this attachment or not? + if(!Chance(gGameExternalOptions.usAttachmentDropRate)){ + (*pObj).RemoveAttachment(&(*iter), 0, 0, pSoldier, 0, 1); + iter = (*pObj)[0]->attachments.begin(); + advance(iter, slotCount); + } + } + } +} void LookForAndMayCommentOnSeeingCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubLevel ) { ROTTING_CORPSE *pCorpse; diff --git a/Tactical/ShopKeeper Interface.cpp b/Tactical/ShopKeeper Interface.cpp index 46ef855b..61835aa9 100644 --- a/Tactical/ShopKeeper Interface.cpp +++ b/Tactical/ShopKeeper Interface.cpp @@ -322,7 +322,7 @@ typedef struct UINT8 ubCurrentPage; UINT8 ubNumberOfPages; - UINT8 ubFirstItemIndexOnPage; + UINT16 ubFirstItemIndexOnPage; } SELECTED_ARMS_DEALERS_STATS; @@ -396,6 +396,8 @@ extern MOUSE_REGION gItemDescAttachmentRegions[MAX_ATTACHMENTS]; extern MOUSE_REGION gInvDesc; extern BOOLEAN gfSMDisableForItems; extern OBJECTTYPE *gpItemDescObject; +extern OBJECTTYPE *gpItemDescPrevObject; +extern OBJECTTYPE *gpItemDescPrevObject; extern void HandleShortCutExitState( void ); extern UINT8 gubSelectSMPanelToMerc; extern INT32 giItemDescAmmoButton; @@ -451,12 +453,12 @@ ITEM_TO_ADD_AFTER_SKI_OPEN gItemToAdd; //Page up buttons for the merchants void BtnSKI_InvPageUpButtonCallback(GUI_BUTTON *btn,INT32 reason); -UINT32 guiSKI_InvPageUpButton; +UINT32 guiSKI_InvPageUpButton; INT32 guiSKI_InvPageUpButtonImage; //Page down buttons for the merchants void BtnSKI_InvPageDownButtonCallback(GUI_BUTTON *btn,INT32 reason); -UINT32 guiSKI_InvPageDownButton; +UINT32 guiSKI_InvPageDownButton; INT32 guiSKI_InvPageDownButtonImage; @@ -470,17 +472,17 @@ INT32 guiSKI_EvaluateButtonImage; //Transaction buttons void BtnSKI_TransactionButtonCallback(GUI_BUTTON *btn,INT32 reason); -UINT32 guiSKI_TransactionButton; +UINT32 guiSKI_TransactionButton; INT32 guiSKI_TransactionButtonImage; //Done buttons void BtnSKI_DoneButtonCallback(GUI_BUTTON *btn,INT32 reason); -UINT32 guiSKI_DoneButton; +UINT32 guiSKI_DoneButton; INT32 guiSKI_DoneButtonImage; //Atm buttons void BtnSKI_AtmButtonCallback(GUI_BUTTON *btn,INT32 reason); -UINT32 guiSKI_AtmButton[ NUM_SKI_ATM_BUTTONS ]; +UINT32 guiSKI_AtmButton[ NUM_SKI_ATM_BUTTONS ]; INT32 guiSKI_AtmNumButtonImage; INT32 guiSKI_AtmOkButtonImage; INT32 guiSKI_AtmSideMenuButtonImage; @@ -552,9 +554,9 @@ BOOLEAN DetermineArmsDealersSellingInventory( ); void StoreObjectsInNextFreeDealerInvSlot( DEALER_SPECIAL_ITEM* pSpecial, std::vector& pInventory, UINT8 ubOwner ); BOOLEAN RepairIsDone(DEALER_SPECIAL_ITEM* pSpecial); -UINT32 DisplayInvSlot( UINT8 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *ItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea ); +UINT32 DisplayInvSlot( UINT16 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *ItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea ); void DisplayArmsDealerOfferArea(); -INT8 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation ); +INT16 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation ); BOOLEAN RemoveItemFromArmsDealerOfferArea( INT16 bSlotId, BOOLEAN fKeepItem ); void SetSkiRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION* pRegion, UINT8 ubScreenArea ); void SetSkiFaceRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION* pRegion, UINT8 ubScreenArea ); @@ -562,7 +564,7 @@ void RestoreTacticalBackGround(); void DisplayPlayersOfferArea(); UINT32 CalcShopKeeperItemPrice( BOOLEAN fDealerSelling, BOOLEAN fUnitPriceOnly, UINT16 usItemID, FLOAT dModifier, OBJECTTYPE *pItemObject ); FLOAT ItemConditionModifier(UINT16 usItemIndex, INT16 bStatus); -BOOLEAN RemoveItemFromPlayersOfferArea( INT8 bSlotIdInOtherLocation ); +BOOLEAN RemoveItemFromPlayersOfferArea( INT16 bSlotIdInOtherLocation ); //Evaluate: //void EvaluateAllItemsInPlayersOfferArea( ); @@ -572,8 +574,8 @@ UINT32 CalculateTotalPlayersValue(); void MoveAllArmsDealersItemsInOfferAreaToPlayersOfferArea( ); void PerformTransaction( UINT32 uiMoneyFromPlayersAccount ); void MovePlayerOfferedItemsOfValueToArmsDealersInventory( ); -INT8 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT8 ubSpotLocation, UINT8 ubWhere ); -BOOLEAN RemoveItemFromDealersInventory( INVENTORY_IN_SLOT* pInvSlot, UINT8 ubSlot ); +INT16 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT16 ubSpotLocation, UINT8 ubWhere ); +BOOLEAN RemoveItemFromDealersInventory( INVENTORY_IN_SLOT* pInvSlot, UINT16 ubSlot ); BOOLEAN InitShopKeepersFace( UINT8 ubMercID ); void DisplayTalkingArmsDealer(); BOOLEAN StartShopKeeperTalking( UINT16 usQuoteNum ); @@ -605,7 +607,7 @@ BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( ); UINT32 CalculateHowMuchMoneyIsInPlayersOfferArea( ); void MovePlayersItemsToBeRepairedToArmsDealersInventory(); -BOOLEAN RemoveRepairItemFromDealersOfferArea( INT8 bSlot ); +BOOLEAN RemoveRepairItemFromDealersOfferArea( INT16 bSlot ); INT8 GetInvSlotOfUnfullMoneyInMercInventory( SOLDIERTYPE *pSoldier ); void ClearPlayersOfferSlot( INT32 ubSlotToClear ); @@ -620,7 +622,7 @@ void CrossOutUnwantedItems( void ); BOOLEAN CanShopkeeperOverrideDialogue( void ); INT16 GetNumberOfItemsInPlayerOfferArea( void ); void HandleCheckIfEnoughOnTheTable( void ); -void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT8 ubPocket, UINT8 ubFromLocation ); +void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT16 ubPocket, UINT8 ubFromLocation ); void StartSKIDescriptionBox( void ); BOOLEAN ShopkeeperAutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNewItem ); @@ -791,14 +793,17 @@ UINT32 ShopKeeperScreenHandle() //ATM: DisableSMPpanelButtonsWhenInShopKeeperInterface( FALSE ); //Heinz: 22.02.09 BUGFIX: buttons should not render upon shopkeeper's message - if( gfIsTheShopKeeperTalking && !gfInItemDescBox ) + if( gfIsTheShopKeeperTalking && !gfInItemDescBox ) { ButtonList[ guiSKI_TransactionButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY; ButtonList[ guiSKI_DoneButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY; } + RenderButtons( ); + //CHRISL: If we put this function call here, we overwrite the bullet graphic. I don't know why. I just know it happens. -// RenderItemDescriptionBox( ); + //RenderItemDescriptionBox( ); + // render help SaveBackgroundRects( ); RenderButtonsFastHelp( ); @@ -2003,8 +2008,8 @@ void SelectDealersInventoryRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason } else if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); - INT8 ubLocation; + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); + INT16 ubLocation; if( gpTempDealersInventory.empty() == true ) return; @@ -2078,7 +2083,7 @@ void SelectDealersInventoryRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); if( gpTempDealersInventory.empty() == true ) return; @@ -2132,7 +2137,7 @@ void SelectDealersInventoryRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason void SelectDealersInventoryMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage; if( gpTempDealersInventory.empty() == true ) @@ -2168,7 +2173,7 @@ void SelectDealersInventoryMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 void SelectDealersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); if (iReason & MSYS_CALLBACK_REASON_INIT) { @@ -2196,7 +2201,7 @@ void SelectDealersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 void SelectPlayersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); if (iReason & MSYS_CALLBACK_REASON_INIT) { @@ -2227,7 +2232,7 @@ void SelectPlayersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 //Mouse Call back for the dealer's OFFER slot void SelectDealersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); if (iReason & MSYS_CALLBACK_REASON_INIT) { @@ -2350,8 +2355,8 @@ void SelectDealersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason //Mouse Call back for the Players OFFER slot void SelectPlayersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason ) { - UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 ); - INT8 bAddedToSlotID = -1; + UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 ); + INT16 bAddedToSlotID = -1; if (iReason & MSYS_CALLBACK_REASON_INIT) @@ -2633,7 +2638,7 @@ void DisplayArmsDealerCurrentInventoryPage( ) // Display the inventory slot - DisplayInvSlot( (UINT8)usCnt, gpTempDealersInventory[ usCnt ].sItemIndex, usPosX, usPosY, + DisplayInvSlot( usCnt, gpTempDealersInventory[ usCnt ].sItemIndex, usPosX, usPosY, &gpTempDealersInventory[ usCnt ].ItemObject, fDisplayHatchOnItem, ARMS_DEALER_INVENTORY ); @@ -2698,7 +2703,7 @@ void DisplayArmsDealerCurrentInventoryPage( ) } -UINT32 DisplayInvSlot( UINT8 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *pItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea ) +UINT32 DisplayInvSlot( UINT16 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *pItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea ) { CHAR16 zTemp[64]; HVOBJECT hVObject; @@ -3070,7 +3075,7 @@ BOOLEAN RepairIsDone(DEALER_SPECIAL_ITEM* pSpecial) // max condition of all permanent attachments on it for (attachmentList::iterator iter = RepairItem.ItemObject[0]->attachments.begin(); iter != RepairItem.ItemObject[0]->attachments.end(); ++iter) { - if ( CanDealerRepairItem( gbSelectedArmsDealerID, iter->usItem ) ) + if ( CanDealerRepairItem( gbSelectedArmsDealerID, iter->usItem ) && iter->exists()) { // fix it up (*iter)[0]->data.objectStatus = 100; @@ -3197,7 +3202,8 @@ UINT32 CalcShopKeeperItemPrice( BOOLEAN fDealerSelling, BOOLEAN fUnitPriceOnly, // loop through any attachments and add in their price for (attachmentList::iterator iter = (*pItemObject)[ubCnt]->attachments.begin(); iter != (*pItemObject)[ubCnt]->attachments.end(); ++iter) { // add value of this particular attachment - uiItemPrice[ubCnt] += CalcShopKeeperItemPrice( fDealerSelling, fUnitPriceOnly, iter->usItem, dModifier, &(*iter)) ; + if(iter->exists()) + uiItemPrice[ubCnt] += CalcShopKeeperItemPrice( fDealerSelling, fUnitPriceOnly, iter->usItem, dModifier, &(*iter)) ; } // if Flo is doing the dealin' and wheelin' @@ -3337,7 +3343,7 @@ void DisplayArmsDealerOfferArea() fDisplayHatchOnItem = FALSE; // Display the inventory slot - uiTotalCost += DisplayInvSlot( (UINT8)sCnt, ArmsDealerOfferArea[ sCnt ].sItemIndex, usPosX, usPosY, + uiTotalCost += DisplayInvSlot( (UINT16)sCnt, ArmsDealerOfferArea[ sCnt ].sItemIndex, usPosX, usPosY, &ArmsDealerOfferArea[ sCnt ].ItemObject, fDisplayHatchOnItem, ARMS_DEALER_OFFER_AREA ); @@ -3381,9 +3387,9 @@ void DisplayArmsDealerOfferArea() } -INT8 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation ) +INT16 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation ) { - INT8 bCnt; + INT16 bCnt; for( bCnt=0; bCntattachments.size(); ubCnt++) { if( gItemDescAttachmentRegions[ubCnt].uiFlags & MSYS_REGION_EXISTS ) MSYS_ChangeRegionCursor( &gItemDescAttachmentRegions[ubCnt], usCursor ); @@ -4388,7 +4393,7 @@ void SetSkiCursor( UINT16 usCursor ) if( gInvDesc.uiFlags & MSYS_REGION_EXISTS ) MSYS_ChangeRegionCursor( &gInvDesc, usCursor ); - for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++) + for( ubCnt = 0; ubCnt < gMoveingItem.ItemObject[0]->attachments.size(); ubCnt++) { if( gItemDescAttachmentRegions[ubCnt].uiFlags & MSYS_REGION_EXISTS ) MSYS_ChangeRegionCursor( &gItemDescAttachmentRegions[ubCnt], usCursor ); @@ -4417,9 +4422,9 @@ void SetSkiCursor( UINT16 usCursor ) } -INT8 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT8 ubSpotLocation, UINT8 ubWhere ) +INT16 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT16 ubSpotLocation, UINT8 ubWhere ) { - INT8 bSlotAddedTo = -1; + INT16 bSlotAddedTo = -1; switch( ubWhere ) @@ -4739,12 +4744,12 @@ BOOLEAN IsGunOrAmmoOfSameTypeSelected( OBJECTTYPE *pItemObject ) // if( Item[ pItemObject->usItem ].fFlags & ITEM_ATTACHMENT ) if( Item[ pItemObject->usItem ].attachment ) { - if( ValidAttachment( pItemObject->usItem, gpHighLightedItemObject->usItem ) ) + if( ValidAttachment( pItemObject->usItem, gpHighLightedItemObject ) ) return( TRUE ); } else { - if( ValidAttachment( gpHighLightedItemObject->usItem, pItemObject->usItem ) ) + if( ValidAttachment( gpHighLightedItemObject->usItem, pItemObject ) ) return( TRUE ); } @@ -5802,7 +5807,7 @@ void MovePlayersItemsToBeRepairedToArmsDealersInventory() -BOOLEAN RemoveRepairItemFromDealersOfferArea( INT8 bSlot ) +BOOLEAN RemoveRepairItemFromDealersOfferArea( INT16 bSlot ) { //if the item doesn't have a duplicate copy in its owner merc's inventory slot if( ArmsDealerOfferArea[ bSlot ].bSlotIdInOtherLocation == -1 ) @@ -5936,7 +5941,7 @@ void EvaluateItemAddedToPlayersOfferArea( INT8 bSlotID, BOOLEAN fFirstOne ) //if the item is damaged, or is a rocket rifle (which always "need repairing" even at 100%, to reset imprinting) if( ( PlayersOfferArea[ bSlotID ].ItemObject[0]->data.objectStatus < 100 ) || fRocketRifleWasEvaluated ) { - INT8 bSlotAddedTo; + INT16 bSlotAddedTo; // Move the item to the Dealer's Offer Area bSlotAddedTo = AddItemToArmsDealerOfferArea( &PlayersOfferArea[ bSlotID ], PlayersOfferArea[ bSlotID ].bSlotIdInOtherLocation ); @@ -6344,16 +6349,19 @@ void HandleCheckIfEnoughOnTheTable( void ) -void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT8 ubPocket, UINT8 ubFromLocation ) +void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT16 ubPocket, UINT8 ubFromLocation ) { INT16 sPosX, sPosY; + bool showItemDescriptionBox = false; switch( ubFromLocation ) { case ARMS_DEALER_INVENTORY: { - UINT8 ubSelectedInvSlot = ubPocket - gSelectArmsDealerInfo.ubFirstItemIndexOnPage; + showItemDescriptionBox = true; + + UINT16 ubSelectedInvSlot = ubPocket - gSelectArmsDealerInfo.ubFirstItemIndexOnPage; sPosX = SKI_ARMS_DEALERS_INV_START_X; // + ( SKI_INV_OFFSET_X * ( ubSelectedInvSlot % SKI_NUM_ARMS_DEALERS_INV_COLS ) - ( 358 / 2 ) ) + SKI_INV_SLOT_WIDTH / 2; @@ -6382,6 +6390,8 @@ void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT8 ubPocket, UINT8 ubFro case ARMS_DEALER_OFFER_AREA: { + showItemDescriptionBox = false; + sPosX = SKI_ARMS_DEALERS_TRADING_INV_X; // + ( SKI_INV_OFFSET_X * ( ubPocket % ( SKI_NUM_TRADING_INV_SLOTS/2) ) - ( 358 / 2 ) ) + SKI_INV_SLOT_WIDTH / 2; sPosY = SKI_ARMS_DEALERS_TRADING_INV_Y; // + ( ( SKI_INV_OFFSET_Y * ubPocket / ( SKI_NUM_TRADING_INV_SLOTS/2) ) + 1 ) - ( 128 / 2 ) + SKI_INV_SLOT_HEIGHT / 2; @@ -6410,13 +6420,16 @@ void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT8 ubPocket, UINT8 ubFro Assert( 0 ); return; } + + // WANNE: Only allow right click (item desription box) in the arms dealer inventory + if (showItemDescriptionBox) + { + pShopKeeperItemDescObject = pObject; + InitItemDescriptionBox( gpSMCurrentMerc, 255, sPosX, sPosY, 0 ); - pShopKeeperItemDescObject = pObject; - - InitItemDescriptionBox( gpSMCurrentMerc, 255, sPosX, sPosY, 0 ); - - StartSKIDescriptionBox( ); + StartSKIDescriptionBox( ); + } } diff --git a/Tactical/ShopKeeper Interface.h b/Tactical/ShopKeeper Interface.h index 08b1cbcd..ab740682 100644 --- a/Tactical/ShopKeeper Interface.h +++ b/Tactical/ShopKeeper Interface.h @@ -133,7 +133,7 @@ void InitShopKeeperSubTitledText( STR16 pString ); void AddItemToPlayersOfferAreaAfterShopKeeperOpen( OBJECTTYPE *pItemObject); -void BeginSkiItemPointer( UINT8 ubSource, INT8 bSlotNum, BOOLEAN fOfferToDealerFirst ); +void BeginSkiItemPointer( UINT8 ubSource, INT16 bSlotNum, BOOLEAN fOfferToDealerFirst ); void DeleteShopKeeperItemDescBox(); diff --git a/Tactical/SkillCheck.cpp b/Tactical/SkillCheck.cpp index b680ac6d..bbe132d8 100644 --- a/Tactical/SkillCheck.cpp +++ b/Tactical/SkillCheck.cpp @@ -12,6 +12,10 @@ #include "Morale.h" #include "drugs and alcohol.h" #include "strategicmap.h" + // added by SANDRO + #include "GameSettings.h" + #include "Animation Data.h" + #include "Soldier Control.h" #endif INT8 EffectiveStrength( SOLDIERTYPE * pSoldier ) @@ -136,20 +140,36 @@ INT8 EffectiveExpLevel( SOLDIERTYPE * pSoldier ) iEffExpLevel = pSoldier->stats.bExpLevel; + // SANDRO - STOMP traits - Squadleader bonus to effective level + if ( gGameOptions.fNewTraitSystem && IS_MERC_BODY_TYPE( pSoldier )) + { + iEffExpLevel += (gSkillTraitValues.ubSLEffectiveLevelInRadius * GetSquadleadersCountInVicinity( pSoldier, TRUE, FALSE )); + } + bDrunkLevel = GetDrunkLevel( pSoldier ); iEffExpLevel = iEffExpLevel + iExpModifier[ bDrunkLevel ]; if (pSoldier->ubProfile != NO_PROFILE) { - if ( (gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == CLAUSTROPHOBIC) && pSoldier->bActive && pSoldier->bInSector && gbWorldSectorZ > 0) + if ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == CLAUSTROPHOBIC) && pSoldier->bActive && pSoldier->bInSector && gbWorldSectorZ > 0) { // claustrophobic! - iEffExpLevel--; + iEffExpLevel -= 2; + } + else if ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) && MercIsInTropicalSector( pSoldier ) ) + { + // SANDRO - fear of insects, and we are in tropical sector + iEffExpLevel -= 1; } } - - if (iEffExpLevel < 1) + + if (iEffExpLevel > 10) + { + // can't go over 10 - SANDRO + return( 10 ); + } + else if (iEffExpLevel < 1) { // can't go below 1 return( 1 ); @@ -241,15 +261,37 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) iSkill = iSkill * (EffectiveDexterity( pSoldier ) + 100) / 200; // factor in experience iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3; - if (HAS_SKILL_TRAIT( pSoldier, LOCKPICKING ) ) + + // SANDRO - STOMP traits - Technician trait lockpicking bonus + if ( gGameOptions.fNewTraitSystem ) { - // if we specialize in picking locks... - iSkill += gbSkillTraitBonus[LOCKPICKING] * NUM_SKILL_TRAITS( pSoldier, LOCKPICKING ); + iSkill += gSkillTraitValues.bCheckModifierLockpicking; // reduce skill value for untrained mercs + + // Simply reduce the skill value for this as usual + if (bReason == ELECTRONIC_LOCKPICKING_CHECK) + { + iSkill /= 2; + } + // then add a flat bonus (undivided by the electronic lock penalty above) + if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + { + iSkill += gSkillTraitValues.usTELockpickingBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ); + } } - if (bReason == ELECTRONIC_LOCKPICKING_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) ) + else // original code { - // if we are unfamiliar with electronics... - iSkill /= 2; + if (HAS_SKILL_TRAIT( pSoldier, LOCKPICKING_OT ) ) + { + // if we specialize in picking locks... + iSkill += gbSkillTraitBonus[LOCKPICKING_OT] * NUM_SKILL_TRAITS( pSoldier, LOCKPICKING_OT ); + } + + if (bReason == ELECTRONIC_LOCKPICKING_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) ) + { + // if we are unfamiliar with electronics... + iSkill /= 2; + } + } // adjust chance based on status of kit bSlot = FindLocksmithKit( pSoldier ); @@ -268,9 +310,28 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) break; } iSkill = (iSkill * 3 + EffectiveDexterity( pSoldier ) ) / 4; - if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS )) ) + + // SANDRO - STOMP traits - Demolitions trait detonator attaching bonus + if ( gGameOptions.fNewTraitSystem ) { - iSkill /= 2; + iSkill += gSkillTraitValues.bCheckModifierAttachDetonators; // reduce skill value for untrained mercs + + if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK ) + { + iSkill /= 2; + } + // add a flat bonus instead of eliminating the penalty above + if ( HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT )) + { + iSkill += gSkillTraitValues.ubDEAttachDetonatorCheckBonus; + } + } + else // original code + { + if ( bReason == ATTACHING_REMOTE_DETONATOR_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT )) ) + { + iSkill /= 2; + } } break; case PLANTING_BOMB_CHECK: @@ -280,10 +341,28 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) iSkill += EffectiveExpLevel( pSoldier ) * 10; iSkill = iSkill / 10; // bring the value down to a percentage - if ( bReason == PLANTING_REMOTE_BOMB_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) ) + // SANDRO - STOMP traits - Demolitions trait planting bombs bonus + if ( gGameOptions.fNewTraitSystem ) { - // deduct only a bit... - iSkill = (iSkill * 3) / 4; + iSkill += gSkillTraitValues.bCheckModifierSetExplosives; // reduce skill for untrained mercs + + if ( bReason == PLANTING_REMOTE_BOMB_CHECK ) + { + iSkill = (iSkill * 3) / 4; + } + // add a flat bonus instead of eliminating the penalty above + if ( HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT )) + { + iSkill += gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus; + } + } + else // original code + { + if ( bReason == PLANTING_REMOTE_BOMB_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) ) + { + // deduct only a bit... + iSkill = (iSkill * 3) / 4; + } } // Ok, this is really damn easy, so skew the values... @@ -297,26 +376,73 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) fForceDamnSound = TRUE; - iSkill = EffectiveExplosive( pSoldier ) * 7; - if ( iSkill == 0 ) - { - break; + // SANDRO - normal(exploding) traps should be based at least a little on mechanical skill as well + if ( gGameOptions.fNewTraitSystem) + { + // It is impossible without both skills + if ( (EffectiveMechanical( pSoldier ) <= 0) || (EffectiveExplosive( pSoldier ) <= 0) ) + { + iSkill = 0; + break; + } + else + { + iSkill = EffectiveExplosive( pSoldier ) * 5; + iSkill += EffectiveMechanical( pSoldier ) * 2; + } } + else + { + iSkill = EffectiveExplosive( pSoldier ) * 7; + if ( iSkill == 0 ) + { + break; + } + } + iSkill += EffectiveDexterity( pSoldier ) * 2; iSkill += EffectiveExpLevel( pSoldier ) * 10; iSkill = iSkill / 10; // bring the value down to a percentage + + // SANDRO - STOMP traits - Demolitions trait removing traps bonus + if ( gGameOptions.fNewTraitSystem ) + { + iSkill += gSkillTraitValues.bCheckModifierDisarmExplosiveTraps; // -15% for untrained mercs + + if (HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT )) + iSkill += gSkillTraitValues.ubDEPlantAndRemoveBombCheckBonus; // +50% bonus for Demolitions + } + // penalty based on poor wisdom iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5; break; case DISARM_ELECTRONIC_TRAP_CHECK: - fForceDamnSound = TRUE; + fForceDamnSound = TRUE; - iSkill = __max( EffectiveMechanical( pSoldier ) , EffectiveExplosive( pSoldier ) ) * 7; - if ( iSkill == 0 ) + // SANDRO - electronic traps are based more on mechanical skill + if ( gGameOptions.fNewTraitSystem) + { + // It is impossible without both skills + if ( (EffectiveMechanical( pSoldier ) <= 0) || (EffectiveExplosive( pSoldier ) <= 0) ) + { + iSkill = 0; + break; + } + else + { + iSkill = EffectiveExplosive( pSoldier ) * 2; + iSkill += EffectiveMechanical( pSoldier ) * 5; + } + } + else { - break; + iSkill = __max( EffectiveMechanical( pSoldier ) , EffectiveExplosive( pSoldier ) ) * 7; + if ( iSkill == 0 ) + { + break; + } } iSkill += EffectiveDexterity( pSoldier ) * 2; iSkill += EffectiveExpLevel( pSoldier ) * 10; @@ -324,9 +450,25 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) // penalty based on poor wisdom iSkill -= (100 - EffectiveWisdom( pSoldier ) ) / 5; - if ( !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS )) ) + // SANDRO - STOMP traits - Technician trait removing traps bonus + if ( gGameOptions.fNewTraitSystem ) { - iSkill = (iSkill * 3) / 4; + iSkill += gSkillTraitValues.bCheckModifierDisarmElectronicTraps; // penalty for untrained mercs + + iSkill = (iSkill * 3) / 4; // original penalty + + // add a flat bonus instead of eliminating the penalty above + if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + { + iSkill += gSkillTraitValues.usTEDisarmElTrapBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ); + } + } + else // original code + { + if ( !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) ) + { + iSkill = (iSkill * 3) / 4; + } } break; @@ -338,9 +480,19 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) case SMASH_DOOR_CHECK: iSkill = EffectiveStrength( pSoldier ); + // SANDRO - STOMP traits - Martial Arts trait kick doors bonus + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT )) + { + iSkill += gSkillTraitValues.ubMAChanceToCkickDoors * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ); + } break; case UNJAM_GUN_CHECK: iSkill = 30 + EffectiveMechanical( pSoldier ) / 2; + // SANDRO - STOMP traits - Technician trait unjamming guns bonus + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + { + iSkill += gSkillTraitValues.ubTEUnjamGunBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ); + } break; case NOTICE_DART_CHECK: // only a max of ~20% chance @@ -349,6 +501,12 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) case LIE_TO_QUEEN_CHECK: // competitive check vs the queen's wisdom and leadership... poor guy! iSkill = 50 * ( EffectiveWisdom( pSoldier ) + EffectiveLeadership( pSoldier ) ) / ( gMercProfiles[ QUEEN ].bWisdom + gMercProfiles[ QUEEN ].bLeadership ); + // squadleader has bonus for this, muhehe - SANDRO + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SQUADLEADER_NT )) + { + iSkill += (20 * NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT )); + } + break; case ATTACHING_SPECIAL_ITEM_CHECK: case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: @@ -363,10 +521,29 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) iSkill = iSkill * (EffectiveDexterity( pSoldier ) + 100) / 200; // factor in experience iSkill = iSkill + EffectiveExpLevel( pSoldier ) * 3; - if (bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS)) ) + + // SANDRO - STOMP traits - Technician trait attaching special items bonus + if ( gGameOptions.fNewTraitSystem ) { - // if we are unfamiliar with electronics... - iSkill /= 2; + iSkill += gSkillTraitValues.bCheckModifierAttachSpecialItems; // penalty for untrained mercs + + if ( bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK ) + { + iSkill /= 2; + } + // add a flat bonus instead of eliminating the penalty above + if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + { + iSkill += gSkillTraitValues.usTEAttachingItemsBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT ); + } + } + else // original code + { + if (bReason == ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK && !(HAS_SKILL_TRAIT( pSoldier, ELECTRONICS_OT)) ) + { + // if we are unfamiliar with electronics... + iSkill /= 2; + } } break; default: @@ -378,6 +555,88 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) iChance = iSkill + bChanceMod; + //////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP - character traits and disabilities modifiers + + //added heat intolerant penalty + if ( MercIsHot( pSoldier ) ) + { + iChance -= 15; + } + // also added a small penalty for fear of insects in tropical sectors + else if ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) && MercIsInTropicalSector( pSoldier )) + { + // fear of insects, and we are in tropical sector + iChance -= 5; + } + + // character traits influence + // Sociable - better performance in groups + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs > 2 ) + iChance += 5; + else if ( bNumMercs > 0 ) + iChance += 2; + } + // Loner - better performance when alone + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs == 0 ) + iChance += 5; + else if ( bNumMercs <= 1 ) + iChance += 2; + } + // Aggressive - penalty for actions needing patience + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + switch ( bReason ) + { + case LOCKPICKING_CHECK: + case ELECTRONIC_LOCKPICKING_CHECK: + case PLANTING_BOMB_CHECK: + case PLANTING_REMOTE_BOMB_CHECK: + case DISARM_TRAP_CHECK: + case DISARM_ELECTRONIC_TRAP_CHECK: + case ATTACHING_SPECIAL_ITEM_CHECK: + case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: + iChance -= 10; + break; + } + } + // Phlegmatic - bonus for actions needing patience + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC ) + { + switch ( bReason ) + { + case LOCKPICKING_CHECK: + case ELECTRONIC_LOCKPICKING_CHECK: + case PLANTING_BOMB_CHECK: + case PLANTING_REMOTE_BOMB_CHECK: + case DISARM_TRAP_CHECK: + case DISARM_ELECTRONIC_TRAP_CHECK: + case ATTACHING_SPECIAL_ITEM_CHECK: + case ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK: + iChance += 5; + break; + } + } + // Show-off - better performance if some babes around to impress + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SHOWOFF ); + if ( bNumMercs > 1 ) + iChance += 5; + else if ( bNumMercs > 0 ) + iChance += 2; + } + ////////////////////////////////////////////////////////////////////// + + // silversurfer: moved this down here where it belongs + // if this wasn't the last check a merc with certain disability modifiers would never completely fail + // to do something and would never do his speech telling that he can't do this switch (bReason) { case LOCKPICKING_CHECK: @@ -391,7 +650,10 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) // for lockpicking and smashing locks, if the chance isn't reasonable // we set it to 0 so they can never get through the door if they aren't // good enough - if (iChance < 30) + //CHRISL: with this set to 30, some "hard" to open doors become basically impossible. Case in point, Drassen "dentist office" which imposes a + // -75 penalty on lockpicking/forcing chances. You find this near the start of the game but would need an 80 STR + Crowbar to open. It's + // impossible to force with just strength or lockpicking skills, regardless of how skilled you are. + if (iChance < 15) { iChance = 0; break; @@ -422,6 +684,10 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod ) { if (iChance == 0) { + if ( MercIsHot( pSoldier ) && pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER) // SANDRO - added this + { + TacticalCharacterDialogue( pSoldier, QUOTE_PERSONALITY_TRAIT ); + } // do we realize that we just can't do this? if ( (100 - (pSoldier->ubSkillCheckAttempts - 2) * 20) < EffectiveWisdom( pSoldier ) ) { @@ -511,12 +777,26 @@ INT8 CalcTrapDetectLevel( SOLDIERTYPE * pSoldier, BOOLEAN fExamining ) bDetectLevel += (EffectiveExplosive( pSoldier ) / 40); bDetectLevel -= ((100 - EffectiveWisdom( pSoldier ) ) / 20); + // STOMP traits - Technician trait detecting traps bonus - SANDRO + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT )) + { + bDetectLevel += (gSkillTraitValues.ubTEChanceToDetectTrapsBonus * NUM_SKILL_TRAITS( pSoldier, TECHNICIAN_NT )); // +2 trap level per trait + } + // if the examining flag is true, this isn't just a casual glance // and the merc should have a higher chance if (fExamining) { bDetectLevel += (INT8) PreRandom(bDetectLevel / 3 + 2); } + // SANDRO - optimists just don't even think about the traps, randomly ignoring this all + else if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_OPTIMIST ) + { + if ( Chance(50) ) + bDetectLevel = 1; + else + bDetectLevel -= 2; + } // if substantially bleeding, or still in serious shock, randomly lower value if ((pSoldier->bBleeding > 20) || (pSoldier->aiData.bShock > 1)) diff --git a/Tactical/Soldier Add.cpp b/Tactical/Soldier Add.cpp index 4c940bc3..53411fa4 100644 --- a/Tactical/Soldier Add.cpp +++ b/Tactical/Soldier Add.cpp @@ -1223,7 +1223,11 @@ BOOLEAN InternalAddSoldierToSector( UINT8 ubID, BOOLEAN fCalculateDirection, BOO else AddSoldierToSectorGridNo( pSoldier, sGridNo, ubDirection, fUseAnimation, usAnimState, usAnimCode ); - CheckForPotentialAddToBattleIncrement( pSoldier ); + // SANDRO - only do this if we are not loading the game (we keep this value saved) + if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) ) + { + CheckForPotentialAddToBattleIncrement( pSoldier ); + } return( TRUE ); } diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index 3a8c0f23..fffbd6bc 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -8,7 +8,7 @@ #include "debug.h" #include "MemMan.h" #include "Overhead Types.h" -//#include "Soldier Control.h" +#include "Soldier Control.h" // I need this here - SANDRO #include "Animation Cache.h" #include "Animation Data.h" #include "Animation Control.h" @@ -265,7 +265,7 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) { INT16 sXPos, sYPos; - //sNewGridNo = NewGridNo( (INT16)pSoldier->sGridNo, (UINT16)DirectionInc( pSoldier->ubDirection ) ); + //sNewGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)DirectionInc( pSoldier->ubDirection ) ); ConvertMapPosToWorldTileCenter( pSoldier->sTempNewGridNo, &sXPos, &sYPos ); pSoldier->EVENT_SetSoldierPosition( (FLOAT)sXPos, (FLOAT)sYPos ); } @@ -887,8 +887,14 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) //CODE: BEGINHOPFENCE // MOVE TWO FACGIN GRIDNOS - sNewGridNo = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) ); - sNewGridNo = NewGridNo( sNewGridNo, DirectionInc( pSoldier->ubDirection ) ); + sNewGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)( DirectionInc( pSoldier->ubDirection ) ) ); + //dddokno{ + if ( gubWorldMovementCosts[ sNewGridNo ][ (UINT8)pSoldier->pathing.usPathingData[ pSoldier->pathing.usPathIndex ] ][ pSoldier->pathing.bLevel ] == TRAVELCOST_FENCE ) + sNewGridNo = NewGridNo( sNewGridNo, (UINT16)( DirectionInc( pSoldier->ubDirection ) ) ); + //dddokno} + + //comm by ddd + //sNewGridNo = NewGridNo( sNewGridNo, (UINT16)( DirectionInc( pSoldier->ubDirection ) ) ); pSoldier->sForcastGridno = sNewGridNo; break; @@ -1181,11 +1187,22 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) { BOOLEAN fMartialArtist = FALSE; - if ( pSoldier->ubProfile != NO_PROFILE ) + if ( pSoldier->ubProfile != NO_PROFILE && pSoldier->ubBodyType == REGMALE ) // SANDRO - added check for body type { - if ( gMercProfiles[ pSoldier->ubProfile ].bSkillTrait == MARTIALARTS || gMercProfiles[ pSoldier->ubProfile ].bSkillTrait2 == MARTIALARTS ) + // SANDRO - old/new traits + if (gGameOptions.fNewTraitSystem) { - fMartialArtist = TRUE; + if ( NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 ) ) + { + fMartialArtist = TRUE; + } + } + else + { + if ( ProfileHasSkillTrait( pSoldier->ubProfile, MARTIALARTS_OT ) > 0 ) + { + fMartialArtist = TRUE; + } } } @@ -1525,7 +1542,11 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) // CODE: GIVE ITEM SoldierGiveItemFromAnimation( pSoldier ); - if (pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile >= FIRST_NPC ) + // if (pSoldier->ubProfile != NO_PROFILE && pSoldier->ubProfile >= FIRST_NPC ) + //new profiles by Jazz + if (pSoldier->ubProfile != NO_PROFILE && (gProfilesNPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || + gProfilesRPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || + gProfilesVehicle[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile)) { TriggerNPCWithGivenApproach( pSoldier->ubProfile, APPROACH_DONE_GIVING_ITEM, FALSE ); } @@ -1760,6 +1781,27 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) // PLAY SOLDIER'S DODGE ANIMATION pTSoldier->ChangeSoldierState( DODGE_ONE, 0 , FALSE ); + + // SANDRO - after dodging melee attack go to apropriate stance + if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH)) + { + if ((((NUM_SKILL_TRAITS( pTSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || + (HAS_SKILL_TRAIT( pTSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && + pTSoldier->ubBodyType == REGMALE ) + { + //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH; + pTSoldier->usPendingAnimation = NINJA_BREATH ; + } + else + { + pTSoldier->usPendingAnimation = PUNCH_BREATH ; + } + } + else if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE)) + { + //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH; + pTSoldier->usPendingAnimation = KNIFE_BREATH ; + } } } } @@ -2918,7 +2960,7 @@ BOOLEAN ShouldMercSayHappyWithGunQuote( SOLDIERTYPE *pSoldier ) { // How do we do this.... - if ( QuoteExp_GotGunOrUsedGun[ pSoldier->ubProfile ] == QUOTE_SATISFACTION_WITH_GUN_AFTER_KILL ) + if ( QuoteExp[ pSoldier->ubProfile ].QuoteExpGotGunOrUsedGun == QUOTE_SATISFACTION_WITH_GUN_AFTER_KILL ) { // For one, only once a day... if ( pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LIKESGUN ) @@ -3071,7 +3113,7 @@ void HandleKilledQuote( SOLDIERTYPE *pKilledSoldier, SOLDIERTYPE *pKillerSoldier // Are we killing mike? - if ( pKilledSoldier->ubProfile == 149 && pKillerSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) + if ( pKilledSoldier->ubProfile == MIKE && pKillerSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) { // Can we see? if ( fCanWeSeeLocation ) @@ -3080,7 +3122,7 @@ void HandleKilledQuote( SOLDIERTYPE *pKilledSoldier, SOLDIERTYPE *pKillerSoldier } } // Are we killing factory mamager? - else if ( pKilledSoldier->ubProfile == 139 ) + else if ( pKilledSoldier->ubProfile == DOREEN ) { // Can we see? //f ( fCanWeSeeLocation ) @@ -3281,10 +3323,35 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) } else { - UINT8 ubAssister; + ////////////////////////////////////////////////////////////// + // SANDRO - some changes here + UINT8 ubAttacker = pSoldier->ubAttackerID; + UINT8 ubAssister = pSoldier->ubPreviousAttackerID; + // If attacker is nobody, and we died, then set the last attacker(if exists) as our killer + if ( ubAttacker == NOBODY ) + { + if ( ubAssister != NOBODY ) + { + ubAttacker = pSoldier->ubPreviousAttackerID; + ubAssister = pSoldier->ubNextToPreviousAttackerID; + } + else if ( pSoldier->ubNextToPreviousAttackerID != NOBODY ) + { + ubAttacker = pSoldier->ubNextToPreviousAttackerID; + ubAssister = NOBODY; + } + } + else + { + if ( ubAssister == NOBODY ) + { + ubAssister = pSoldier->ubNextToPreviousAttackerID; + } + } + ////////////////////////////////////////////////////////////// // IF this guy has an attacker and he's a good guy, play sound - if ( pSoldier->ubAttackerID != NOBODY ) + if ( ubAttacker != NOBODY ) { if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum && gTacticalStatus.ubAttackBusyCount > 0 ) { @@ -3292,7 +3359,7 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) gTacticalStatus.ubEnemyKilledOnAttack = pSoldier->ubID; gTacticalStatus.ubEnemyKilledOnAttackLocation = pSoldier->sGridNo; gTacticalStatus.bEnemyKilledOnAttackLevel = pSoldier->pathing.bLevel; - gTacticalStatus.ubEnemyKilledOnAttackKiller = pSoldier->ubAttackerID; + gTacticalStatus.ubEnemyKilledOnAttackKiller = ubAttacker; // also check if we are in mapscreen, if so update soldier's list if( guiCurrentScreen == MAP_SCREEN ) @@ -3303,9 +3370,9 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) else if ( pSoldier->bVisible == TRUE ) { // We were a visible enemy, say laugh! - if ( Random(3) == 0 && !CREATURE_OR_BLOODCAT( MercPtrs[ pSoldier->ubAttackerID ] ) ) + if ( Random(3) == 0 && !CREATURE_OR_BLOODCAT( MercPtrs[ ubAttacker ] ) ) { - MercPtrs[ pSoldier->ubAttackerID ]->DoMercBattleSound( BATTLE_SOUND_LAUGH1 ); + MercPtrs[ ubAttacker ]->DoMercBattleSound( BATTLE_SOUND_LAUGH1 ); } } } @@ -3315,37 +3382,72 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) // if a friendly with a profile, increment kills // militia also now track kills... - if ( pSoldier->ubAttackerID != NOBODY ) + if ( ubAttacker != NOBODY ) { - if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == gbPlayerNum ) + if ( MercPtrs[ ubAttacker ]->bTeam == gbPlayerNum ) { // increment kills - gMercProfiles[ MercPtrs[ pSoldier->ubAttackerID ]->ubProfile ].usKills++; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - experimental - more specific statistics of mercs + switch(pSoldier->ubSoldierClass) + { + case SOLDIER_CLASS_ELITE : + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsElites++; + break; + case SOLDIER_CLASS_ARMY : + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsRegulars++; + break; + case SOLDIER_CLASS_ADMINISTRATOR : + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsAdmins++; + break; + case SOLDIER_CLASS_CREATURE : + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++; + break; + default : + if ( CREATURE_OR_BLOODCAT( pSoldier ) ) + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++; + else if ( TANK( pSoldier ) ) + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsTanks++; + else if ( pSoldier->bTeam == CIV_TEAM && !pSoldier->aiData.bNeutral && pSoldier->bSide != gbPlayerNum ) + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsHostiles++; + else + gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsOthers++; + break; + } + //gMercProfiles[ MercPtrs[ pSoldier->ubAttackerID ]->ubProfile ].usKills++; + ///////////////////////////////////////////////////////////////////////////////////// gStrategicStatus.usPlayerKills++; } - else if ( MercPtrs[ pSoldier->ubAttackerID ]->bTeam == MILITIA_TEAM ) + else if ( MercPtrs[ ubAttacker ]->bTeam == MILITIA_TEAM ) { // get a kill! 2 points! - MercPtrs[ pSoldier->ubAttackerID ]->ubMilitiaKills += 2; + MercPtrs[ ubAttacker ]->ubMilitiaKills += 2; } } - // JA2 Gold: if previous and current attackers are the same, the next-to-previous attacker gets the assist - if (pSoldier->ubPreviousAttackerID == pSoldier->ubAttackerID) - { - ubAssister = pSoldier->ubNextToPreviousAttackerID; - } - else - { - ubAssister = pSoldier->ubPreviousAttackerID; - } - if ( ubAssister != NOBODY && ubAssister != pSoldier->ubAttackerID ) + if ( ubAssister != NOBODY && ubAssister != ubAttacker ) { if ( MercPtrs[ ubAssister ]->bTeam == gbPlayerNum ) { - gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].usAssists++; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if( MercPtrs[ ubAttacker ] != NULL ) + { + if( MercPtrs[ ubAttacker ]->bTeam == gbPlayerNum ) + gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].records.usAssistsMercs++; + else if ( MercPtrs[ ubAttacker ]->bTeam == MILITIA_TEAM ) + gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].records.usAssistsMilitia++; + else + gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].records.usAssistsOthers++; + } + else + { + gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].records.usAssistsOthers++; + } + //gMercProfiles[ MercPtrs[ ubAssister ]->ubProfile ].usAssists++; + ///////////////////////////////////////////////////////////////////////////////////// } else if ( MercPtrs[ ubAssister ]->bTeam == MILITIA_TEAM ) { @@ -3561,6 +3663,7 @@ void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier ) INT8 bTestDirection = pSoldier->ubDirection; BOOLEAN fForceDirection = FALSE; BOOLEAN fDoFallback = FALSE; + BOOLEAN fAlwaysFallBack = FALSE; // added by SANDRO // Lesh: lets fix dead humans fallback through obstacles @@ -3571,7 +3674,15 @@ void CheckForAndHandleSoldierIncompacitated( SOLDIERTYPE *pSoldier ) #elif defined ( TESTFALLFORWARD ) if ( 0 ) #else - if ( Random(100 ) > 40 && IS_MERC_BODY_TYPE( pSoldier ) && !IsProfileATerrorist( pSoldier->ubProfile ) ) + // SANDRO - if Martial Artist took someone down, always fall back if possible (for the fun) + if ( pSoldier->ubAttackerID != NOBODY && gGameOptions.fNewTraitSystem ) + { + if ( HAS_SKILL_TRAIT( MercPtrs[ pSoldier->ubAttackerID ], MARTIAL_ARTS_NT ) && (!MercPtrs[ pSoldier->ubAttackerID ]->usAttackingWeapon || Item[MercPtrs[ pSoldier->ubAttackerID ]->inv[HANDPOS].usItem].brassknuckles ) ) + { + fAlwaysFallBack = TRUE; + } + } + if ( (Random(100 ) > 40 || fAlwaysFallBack) && IS_MERC_BODY_TYPE( pSoldier ) && !IsProfileATerrorist( pSoldier->ubProfile ) ) #endif { // CHECK IF WE HAVE AN ATTACKER, TAKE OPPOSITE DIRECTION! diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 70d371ab..6bb3459a 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -96,10 +96,13 @@ #include "civ quotes.h" #include "Strategic Pathing.h" #include "Debug Control.h" +#include "LOS.h" // added by SANDRO #endif #include "fresh_header.h" +#include "Dialogue Control.h" + //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; @@ -231,6 +234,8 @@ BATTLESNDS_STRUCT gBattleSndsData[] = "enem", 0, 1, 1, 1, 0, }; +extern void ReduceAttachmentsOnGunForNonPlayerChars(SOLDIERTYPE *pSoldier, OBJECTTYPE * pObj); + // CHRISL: MERCPROFILEGEAR::MERCPROFILEGEAR() { @@ -250,6 +255,7 @@ MERCPROFILEGEAR& MERCPROFILEGEAR::operator=(const MERCPROFILEGEAR& src) { lStatus = src.lStatus; invCnt = src.invCnt; lbeCnt = src.lbeCnt; + PriceModifier = src.PriceModifier; } return *this; } @@ -270,6 +276,7 @@ void MERCPROFILEGEAR::clearInventory() { //ADB these really should be defines invCnt = 55; lbeCnt = 5; + PriceModifier = 0; inv.clear(); iStatus.clear(); @@ -482,8 +489,8 @@ void STRUCT_Flags::ConvertFrom_101_To_102(const OLDSOLDIERTYPE_101& src) void STRUCT_Statistics::ConvertFrom_101_To_102(const OLDSOLDIERTYPE_101& src) { - this->ubSkillTrait1 = src.ubSkillTrait1; - this->ubSkillTrait2 = src.ubSkillTrait2; + this->ubSkillTraits[0] = src.ubSkillTrait1; + this->ubSkillTraits[1] = src.ubSkillTrait2; this->bDexterity = src.bDexterity; // dexterity (hand coord) value this->bWisdom = src.bWisdom; this->bExpLevel = src.bExpLevel; // general experience level @@ -648,8 +655,9 @@ SOLDIERTYPE& SOLDIERTYPE::operator=(const OLDSOLDIERTYPE_101& src) this->dXPos = src.dXPos; this->dYPos = src.dYPos; - this->dOldXPos = src.dOldXPos; - this->dOldYPos = src.dOldYPos; + // HEADROCK HAM 4: Changed from FLOAT to INT32 to record position at beginning of turn. + this->sOldXPos = src.sOldXPos; + this->sOldYPos = src.sOldYPos; this->sInitialGridNo = src.sInitialGridNo; this->sGridNo = src.sGridNo; this->ubDirection = src.ubDirection; @@ -696,6 +704,13 @@ SOLDIERTYPE& SOLDIERTYPE::operator=(const OLDSOLDIERTYPE_101& src) this->bTargetLevel = src.bTargetLevel; this->bTargetCubeLevel = src.bTargetCubeLevel; this->sLastTarget = src.sLastTarget; + + // HEADROCK HAM 4: TODO: Added four new variables to soldiertype. MAke sure they don't screw it all up! + this->dPrevMuzzleOffsetX = 0.0; + this->dPrevMuzzleOffsetY = 0.0; + this->dPrevCounterForceX = 0.0; + this->dPrevCounterForceY = 0.0; + this->bTilesMoved = src.bTilesMoved; this->dNextBleed = src.dNextBleed; @@ -1047,7 +1062,12 @@ void SOLDIERTYPE::initialize() memset( &pathing, 0, sizeof(STRUCT_Pathing) ); } - +bool SOLDIERTYPE::exists() +{ + if(this == NULL) + return(FALSE); + return (TRUE); +} // Ugly temporary solution // @@ -1289,12 +1309,53 @@ MERCPROFILESTRUCT& MERCPROFILESTRUCT::operator=(const OLD_MERCPROFILESTRUCT_101& this->bExplosivesDelta = src.bExplosivesDelta; this->bStrengthDelta = src.bStrengthDelta; this->bLeadershipDelta = src.bLeadershipDelta; - this->usKills = src.usKills; - this->usAssists = src.usAssists; - this->usShotsFired = src.usShotsFired; - this->usShotsHit = src.usShotsHit; - this->usBattlesFought = src.usBattlesFought; - this->usTimesWounded = src.usTimesWounded; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new records + this->records.usKillsElites = (src.usKills/4); + this->records.usKillsRegulars = (src.usKills/2); + this->records.usKillsAdmins = (src.usKills/4); + this->records.usKillsHostiles = 0; + this->records.usKillsCreatures = 0; + this->records.usKillsTanks = 0; + this->records.usKillsOthers = 0; + this->records.usAssistsMercs = (src.usAssists*3/4); + this->records.usAssistsMilitia = (src.usAssists/4); + this->records.usAssistsOthers = 0; + this->records.usShotsFired = src.usShotsFired; + this->records.usMissilesLaunched = 0; + this->records.usGrenadesThrown = 0; + this->records.usKnivesThrown = 0; + this->records.usBladeAttacks = 0; + this->records.usHtHAttacks = 0; + this->records.usShotsHit = src.usShotsHit; + this->records.usBattlesTactical = (src.usBattlesFought*3/4); + this->records.usBattlesAutoresolve = src.usBattlesFought/4; + this->records.usBattlesRetreated = 0; + this->records.usAmbushesExperienced = 0; + this->records.usLargestBattleFought = 0; + this->records.usTimesWoundedShot = src.usTimesWounded; + this->records.usTimesWoundedStabbed = 0; + this->records.usTimesWoundedPunched = 0; + this->records.usTimesWoundedBlasted = 0; + this->records.usTimesStatDamaged = 0; + this->records.usTimesSurgeryUndergoed = 0; + this->records.usFacilityAccidents = 0; + this->records.usLocksPicked = 0; + this->records.usLocksBreached = 0; + this->records.usTrapsRemoved = 0; + this->records.usExpDetonated = 0; + this->records.usItemsRepaired = 0; + this->records.usItemsCombined = 0; + this->records.usItemsStolen = 0; + this->records.usMercsBandaged = 0; + this->records.usSurgeriesMade = 0; + this->records.usNPCsDiscovered = 0; + this->records.usSectorsDiscovered = 0; + this->records.usMilitiaTrained = 0; + //this->records.usFacilityEvents = 0; + this->records.ubQuestsHandled = 0; + + ///////////////////////////////////////////////////////////////////////////////////// this->usTotalDaysServed = src.usTotalDaysServed; this->sLeadershipGain = src.sLeadershipGain; @@ -1308,12 +1369,13 @@ MERCPROFILESTRUCT& MERCPROFILESTRUCT::operator=(const OLD_MERCPROFILESTRUCT_101& this->sSalary = src.sSalary; this->bLife = src.bLife; this->bDexterity = src.bDexterity;// dexterity (hand coord) value - this->bPersonalityTrait = src.bPersonalityTrait; - this->bSkillTrait = src.bSkillTrait; + this->bDisability = src.bDisability; + + this->bSkillTraits[0] = src.bSkillTrait; + this->bSkillTraits[1] = src.bSkillTrait2; this->bReputationTolerance = src.bReputationTolerance; this->bExplosive = src.bExplosive; - this->bSkillTrait2 = src.bSkillTrait2; this->bLeadership = src.bLeadership; this->bExpLevel = src.bExpLevel;// general experience level @@ -1422,6 +1484,8 @@ void MERCPROFILESTRUCT::initialize() { memset( this, 0, SIZEOF_MERCPROFILESTRUCT_POD); clearInventory(); + // SANDRO - added this + memset( &records, 0, sizeof(STRUCT_Records) ); } // Initialize the soldier. @@ -1888,29 +1952,40 @@ INT16 SOLDIERTYPE::CalcActionPoints( void ) ubPoints = (ubPoints * APBPConstants[AP_MONST_FRENZY_FACTOR]) / 10; } } + // SANDRO - moved this here + // If we are a vehicle, adjust APS... + else if ( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + AdjustVehicleAPs( this, &ubPoints ); + } + // SANDRO - squadleader's bonus to APs + else if ( gGameOptions.fNewTraitSystem && IS_MERC_BODY_TYPE( this ) && + (this->bTeam == ENEMY_TEAM || this->bTeam == MILITIA_TEAM || this->bTeam == gbPlayerNum) ) + { + // +5% APs per trait (+15% is max) (as a default) + ubPoints += (ubPoints * gSkillTraitValues.ubSLBonusAPsPercent * GetSquadleadersCountInVicinity( this, FALSE, FALSE ) / 100); + } // adjust APs for phobia situations if ( this->ubProfile != NO_PROFILE ) { - if ( (gMercProfiles[ this->ubProfile ].bPersonalityTrait == CLAUSTROPHOBIC) && (gbWorldSectorZ > 0) ) + if ( (gMercProfiles[ this->ubProfile ].bDisability == CLAUSTROPHOBIC) && (gbWorldSectorZ > 0) ) { ubPoints = (ubPoints * APBPConstants[AP_CLAUSTROPHOBE]) / 10; } - else if ( (gMercProfiles[ this->ubProfile ].bPersonalityTrait == FEAR_OF_INSECTS) && (MercSeesCreature( this ) ) ) + else if ( (gMercProfiles[ this->ubProfile ].bDisability == FEAR_OF_INSECTS) && (MercSeesCreature( this ) ) ) { ubPoints = (ubPoints * APBPConstants[AP_AFRAID_OF_INSECTS]) / 10; } + else if ( (gMercProfiles[ this->ubProfile ].bDisability == FEAR_OF_INSECTS) && (MercIsInTropicalSector( this ) ) ) + { + ubPoints = (ubPoints * 9) / 10; + } } // Adjusat APs due to drugs... HandleAPEffectDueToDrugs( this, &ubPoints ); - // If we are a vehicle, adjust APS... - if ( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) - { - AdjustVehicleAPs( this, &ubPoints ); - } - //Madd // if ( this->bTeam != CIV_TEAM && this->bTeam != gbPlayerNum && gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) // ubPoints += 5; // everything and everyone moves a little faster against you on insane... @@ -1918,9 +1993,11 @@ INT16 SOLDIERTYPE::CalcActionPoints( void ) //Kaiden: Took your idea a step further adding the bonus for each difficulty level // and then externalized it. AND added it to the Dont max out points section below. - if ( this->bTeam != CIV_TEAM && this->bTeam != gbPlayerNum) + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - following code messed a bit + //if ( this->bTeam != CIV_TEAM && this->bTeam != gbPlayerNum) + if ( this->bTeam == ENEMY_TEAM ) { - switch( gGameOptions.ubDifficultyLevel ) { case DIF_LEVEL_EASY: @@ -1947,9 +2024,56 @@ INT16 SOLDIERTYPE::CalcActionPoints( void ) ubPoints +=0; } } - else + // Bonus to Militia APs + else if ( this->bTeam == MILITIA_TEAM ) + { + // This is only affected from 2/5 + if (this->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaAPsBonus != 0) + ubPoints += gGameExternalOptions.bGreenMilitiaAPsBonus; + else if (this->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaAPsBonus != 0) + ubPoints += gGameExternalOptions.bRegularMilitiaAPsBonus; + else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaAPsBonus != 0) + ubPoints += gGameExternalOptions.bVeteranMilitiaAPsBonus; + } + //Kaiden: Players just max out normally unless drugged + else if ( this->bTeam == gbPlayerNum ) + { ubPoints += gGameExternalOptions.iPlayerAPBonus; - + } + // nothing here + else + { + //ubPoints += 0; + } + + // option to make special NPCs stronger - AP bonus + if ( this->ubProfile != NO_PROFILE && gGameExternalOptions.usSpecialNPCStronger > 0 ) + { + switch( this->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + // Only 1/4 of the bonus + ubPoints += ( ubPoints * gGameExternalOptions.usSpecialNPCStronger/400 ); + break; + } + } + /////////////////////////////////////////////////////////////////////////////////////////// + // if we are in boxing mode, adjust APs... THIS MUST BE LAST! if ( gTacticalStatus.bBoxingState == BOXING || gTacticalStatus.bBoxingState == PRE_BOXING ) { @@ -1986,43 +2110,93 @@ void SOLDIERTYPE::CalcNewActionPoints( void ) // Don't max out if we are drugged.... if ( !GetDrugEffect( this, DRUG_TYPE_ADRENALINE ) ) - { //Kaiden: If Enemy, they can max out, but their Max is NOW = MAX + diffAPBonus + { + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - following code messed a bit + // First get max APs we can have + UINT16 usMaxActionPnts = gubMaxActionPoints[ this->ubBodyType ]; + //Kaiden: If Enemy, they can max out, but their Max is NOW = MAX + diffAPBonus // No sense in giving them a bonus if some of the points are wasted because we // Didn't raise their cap by the same amount. - if ( this->bTeam != CIV_TEAM && this->bTeam != gbPlayerNum) + // squadleader's bonus to APs + if ( gGameOptions.fNewTraitSystem && IS_MERC_BODY_TYPE( this ) && + (this->bTeam == ENEMY_TEAM || this->bTeam == MILITIA_TEAM || this->bTeam == gbPlayerNum) ) + { + // +5% APs per trait (+15% is max) + usMaxActionPnts += (usMaxActionPnts * gSkillTraitValues.ubSLBonusAPsPercent * GetSquadleadersCountInVicinity( this, FALSE, FALSE ) / 100); + } + if ( this->bTeam == ENEMY_TEAM ) { switch( gGameOptions.ubDifficultyLevel ) { - case DIF_LEVEL_EASY: - - this->bActionPoints = __min( this->bActionPoints, (gubMaxActionPoints[ this->ubBodyType ] + gGameExternalOptions.iEasyAPBonus)); - break; - - case DIF_LEVEL_MEDIUM: - - this->bActionPoints = __min( this->bActionPoints, (gubMaxActionPoints[ this->ubBodyType ] + gGameExternalOptions.iExperiencedAPBonus)); - break; - - case DIF_LEVEL_HARD: - - this->bActionPoints = __min( this->bActionPoints, (gubMaxActionPoints[ this->ubBodyType ] + gGameExternalOptions.iExpertAPBonus)); - break; - - case DIF_LEVEL_INSANE: - - this->bActionPoints = __min( this->bActionPoints, (gubMaxActionPoints[ this->ubBodyType ] + gGameExternalOptions.iInsaneAPBonus)); - break; - - default: - this->bActionPoints = __min( this->bActionPoints, gubMaxActionPoints[ this->ubBodyType ] ); + case DIF_LEVEL_EASY: + usMaxActionPnts += gGameExternalOptions.iEasyAPBonus; + break; + case DIF_LEVEL_MEDIUM: + usMaxActionPnts += gGameExternalOptions.iExperiencedAPBonus; + break; + case DIF_LEVEL_HARD: + usMaxActionPnts += gGameExternalOptions.iExpertAPBonus; + break; + case DIF_LEVEL_INSANE: + usMaxActionPnts += gGameExternalOptions.iInsaneAPBonus; + break; } - + } + // Bonus to Militia APs + else if ( this->bTeam == MILITIA_TEAM ) + { + if (this->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaAPsBonus != 0) + usMaxActionPnts += gGameExternalOptions.bGreenMilitiaAPsBonus; + else if (this->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaAPsBonus != 0) + usMaxActionPnts += gGameExternalOptions.bRegularMilitiaAPsBonus; + else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaAPsBonus != 0) + usMaxActionPnts += gGameExternalOptions.bVeteranMilitiaAPsBonus; + } + //Kaiden: Players just max out normally unless drugged + else if ( this->bTeam == gbPlayerNum ) + { + usMaxActionPnts += gGameExternalOptions.iPlayerAPBonus; } else - { //Kaiden: Players just max out normally unless drugged - this->bActionPoints = __min( this->bActionPoints, (gubMaxActionPoints[ this->ubBodyType ] + gGameExternalOptions.iPlayerAPBonus) ); + { + // Nothing here + //MaxActionPnts += 0; } + // option to make special NPCs stronger - AP bonus + if ( this->ubProfile != NO_PROFILE && gGameExternalOptions.usSpecialNPCStronger > 0 ) + { + switch( this->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + // Only 1/4 of the bonus + usMaxActionPnts += (usMaxActionPnts * gGameExternalOptions.usSpecialNPCStronger/400); + break; + } + } + + // Now repair + if ( this->bActionPoints > usMaxActionPnts ) + { + this->bActionPoints = usMaxActionPnts; + } + /////////////////////////////////////////////////////////////////////////////////////////// } this->bInitialActionPoints = this->bActionPoints; @@ -2047,7 +2221,13 @@ void SOLDIERTYPE::DoNinjaAttack( void ) ubTargetStance = gAnimControl[ pTSoldier->usAnimState ].ubEndHeight; // Get his life...if < certain value, do finish! - if ( (pTSoldier->stats.bLife <= 30 || pTSoldier->bBreath <= 30) && ubTargetStance != ANIM_PRONE ) + // SANDRO - Enhanced Close Combat System - Spinning kick is performed on focuse attack + if (gGameExternalOptions.fEnhancedCloseCombatSystem && ( ( this->aiData.bAimTime > 0 ) && ubTargetStance != ANIM_PRONE )) + { + this->ChangeSoldierState( NINJA_SPINKICK, 0 , FALSE ); + + } + else if ( !gGameExternalOptions.fEnhancedCloseCombatSystem && (pTSoldier->stats.bLife <= 30 || pTSoldier->bBreath <= 30) && ubTargetStance != ANIM_PRONE ) { // Do finish! this->ChangeSoldierState( NINJA_SPINKICK, 0 , FALSE ); @@ -2667,7 +2847,7 @@ void CheckForFreeupFromHit( SOLDIERTYPE *pSoldier, UINT32 uiOldAnimFlags, UINT32 //FREEUP GETTING HIT FLAG // pSoldier->flags.fGettingHit = FALSE; - if ( pSoldier->stats.bLife == 0 ) + if ( pSoldier->stats.bLife == 0 && pSoldier->ubPreviousAttackerID != NOBODY) // SANDRO added check { //ATE: Set previous attacker's value! // This is so that the killer can say their killed quote.... @@ -2889,6 +3069,15 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart // Set new state to be animation to move to new stance usNewState = END_SWAT; } + ///***ddd{ + if( (this->usAnimState == SWATTING_WK || this->usAnimState == SWAT_BACKWARDS + || this->usAnimState == SWAT_BACKWARDS_NOTHING || this->usAnimState == SWAT_BACKWARDS_WK) + && usNewState == CROUCHING ) + { + // Set new state to be animation to move to new stance + usNewState = END_SWAT; + } + ///***ddd} if( this->usAnimState == WALKING && usNewState == STANDING && this->stats.bLife < INJURED_CHANGE_THREASHOLD && this->ubBodyType <= REGFEMALE && !this->MercInWater( ) ) { @@ -2982,7 +3171,9 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart // OK, if we have reverse set, do the side step! if ( this->bReverse ) { - if ( usNewState == WALKING || usNewState == RUNNING || usNewState == SWATTING ) + if ( usNewState == WALKING || usNewState == RUNNING || usNewState == SWATTING + //*** ddd + || usNewState == SWATTING_WK) { // CHECK FOR SIDEWAYS! if ( this->ubDirection == gPurpendicularDirection[ this->ubDirection ][ this->pathing.usPathingData[ this->pathing.usPathIndex ] ] ) @@ -2994,7 +3185,19 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart { if ( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_CROUCH ) { - usNewState = SWAT_BACKWARDS; + //*** ddd + UINT16 usItem = this->inv[ HANDPOS ].usItem; + + if( this->inv[ HANDPOS ].exists() == true && Item[ usItem ].usItemClass == IC_GUN && Item[ usItem ].twohanded && !Item[usItem].rocketlauncher) + usNewState = SWAT_BACKWARDS; + else + usNewState = SWAT_BACKWARDS_NOTHING; + // ;) + if( this->inv[ HANDPOS ].exists() == true && + //(this->ubBodyType == BIGMALE || this->ubBodyType == REGFEMALE )&& + (Item[ usItem ].usItemClass == IC_BLADE || Item[ usItem ].usItemClass == IC_THROWING_KNIFE) ) + usNewState = SWAT_BACKWARDS_WK; + } else { @@ -3003,6 +3206,26 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart } } } + //***08.12.2008*** - ;) ddd + else if( usNewState == CRAWLING + && this->ubDirection == + gPurpendicularDirection[ this->ubDirection ][ this->pathing.usPathingData + [ this->pathing.usPathIndex ] ]) + { + if( QuickestDirection( this->ubDirection, this->pathing.usPathingData[ this->pathing.usPathIndex] ) > 0 ) + usNewState = ROLL_PRONE_R; + else if( QuickestDirection( this->ubDirection, this->pathing.usPathingData[ this->pathing.usPathIndex ] ) < 0 ) + usNewState = ROLL_PRONE_L; + + if( usNewState != CRAWLING ) + { + if( this->ubDirection % 2 == 0 ) + gAnimControl[usNewState].dMovementChange = (FLOAT)0.8; + else + gAnimControl[usNewState].dMovementChange = (FLOAT)1.1; + } + }/// + } // ATE: Patch hole for breath collapse for roofs, fences @@ -3319,13 +3542,13 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart if ( this->usAnimState != RUNNING ) { // CHRISL - if((UsingNewInventorySystem() == true) && this->inv[BPACKPOCKPOS].exists() == true) + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( this ) != ITEM_NOT_FOUND) { - sAPCost = APBPConstants[AP_START_RUN_COST] + 2; + sAPCost = GetAPsStartRun( this ) + 2; // changed by SANDRO sBPCost += 2; } else - sAPCost = APBPConstants[AP_START_RUN_COST]; + sAPCost = GetAPsStartRun( this ); // changed by SANDRO DeductPoints( this, sAPCost, sBPCost ); } // Set pending action count to 0 @@ -3349,27 +3572,28 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart if ( !this->flags.fDontChargeAPsForStanceChange ) { // CHRISL - if((UsingNewInventorySystem() == true) && this->inv[BPACKPOCKPOS].exists() == true && !this->flags.ZipperFlag) + // SANDRO - APBPConstants[AP_CROUCH] changed to GetAPsCrouch() + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( this ) != ITEM_NOT_FOUND && !this->flags.ZipperFlag) { if(usNewState == KNEEL_UP || usNewState == BIGMERC_CROUCH_TRANS_OUTOF) { - sAPCost=APBPConstants[AP_CROUCH]+2; + sAPCost=GetAPsCrouch(this, FALSE)+2; sBPCost=APBPConstants[BP_CROUCH]+2; } else if(usNewState == KNEEL_DOWN || usNewState == BIGMERC_CROUCH_TRANS_INTO) { - sAPCost=APBPConstants[AP_CROUCH]+1; + sAPCost=GetAPsCrouch(this, FALSE)+1; sBPCost=APBPConstants[BP_CROUCH]+1; } else { - sAPCost=APBPConstants[AP_CROUCH]; + sAPCost=GetAPsCrouch(this, FALSE); sBPCost=APBPConstants[BP_CROUCH]; } } else { - sAPCost=APBPConstants[AP_CROUCH]; + sAPCost=GetAPsCrouch(this, FALSE); sBPCost=APBPConstants[BP_CROUCH]; } DeductPoints( this, sAPCost, sBPCost ); @@ -3384,26 +3608,27 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart if ( this->flags.bTurningFromPronePosition < TURNING_FROM_PRONE_START_UP_FROM_MOVE && !this->flags.fDontChargeAPsForStanceChange ) { // ATE: Don't do this if we are still 'moving'.... + // SANDRO - APBPConstants[AP_PRONE] changed to GetAPsProne() if ( this->sGridNo == this->pathing.sFinalDestination || this->pathing.usPathIndex == 0 ) { // CHRISL - if((UsingNewInventorySystem() == true) && this->inv[BPACKPOCKPOS].exists() == true && !this->flags.ZipperFlag) + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( this ) != ITEM_NOT_FOUND && !this->flags.ZipperFlag) { if(usNewState == PRONE_UP) { - sAPCost=APBPConstants[AP_PRONE]+2; - sBPCost=APBPConstants[BP_PRONE]+2; + sAPCost=GetAPsProne(this, FALSE)+2; + sBPCost=APBPConstants[BP_PRONE]+2; } else { - sAPCost=APBPConstants[AP_PRONE]+1; - sBPCost=APBPConstants[BP_PRONE]+1; + sAPCost=GetAPsProne(this, FALSE)+1; + sBPCost=APBPConstants[BP_PRONE]+1; } } else { - sAPCost=APBPConstants[AP_PRONE]; - sBPCost=APBPConstants[BP_PRONE]; + sAPCost=GetAPsProne(this, FALSE); + sBPCost=APBPConstants[BP_PRONE]; } DeductPoints( this, sAPCost, sBPCost ); } @@ -3428,14 +3653,15 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart case PLANT_BOMB: if(Item[this->inv[HANDPOS].usItem].mine == 1) // bury a mine - DeductPoints( this, APBPConstants[AP_BURY_MINE], APBPConstants[BP_BURY_MINE] ); + DeductPoints( this, GetAPsToPlantMine( this ), APBPConstants[BP_BURY_MINE] ); // changed by SANDRO else - DeductPoints( this, APBPConstants[AP_DROP_BOMB], APBPConstants[BP_DROP_BOMB] ); + DeductPoints( this, GetAPsToDropBomb( this ), APBPConstants[BP_DROP_BOMB] ); // changed by SANDRO break; case STEAL_ITEM: - DeductPoints( this, APBPConstants[AP_STEAL_ITEM], 0 ); + // we will deduct APs for this elsewhere (see weapons.cpp) - SANDRO + //DeductPoints( this, APBPConstants[AP_STEAL_ITEM], 0 ); break; case CROW_DIE: @@ -3476,10 +3702,11 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart case HOPFENCE: // CHRISL - if((UsingNewInventorySystem() == true) && this->inv[BPACKPOCKPOS].exists() == true) - DeductPoints( this, APBPConstants[AP_JUMPFENCEBPACK], APBPConstants[BP_JUMPFENCEBPACK] ); + // SANDRO - changed this a bit + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( this ) != ITEM_NOT_FOUND ) + DeductPoints( this, GetAPsToJumpFence( this, TRUE ), GetBPsToJumpFence( this, TRUE ) ); else - DeductPoints( this, APBPConstants[AP_JUMPFENCE], APBPConstants[BP_JUMPFENCE] ); + DeductPoints( this, GetAPsToJumpFence( this, FALSE ), GetBPsToJumpFence( this, FALSE ) ); break; // Deduct aps for falling down.... @@ -3505,7 +3732,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart // disable sight gTacticalStatus.uiFlags |= DISALLOW_SIGHT; - DeductPoints( this, APBPConstants[AP_CLIMBOFFROOF], APBPConstants[BP_CLIMBOFFROOF] ); + DeductPoints( this, GetAPsToClimbRoof( this, TRUE), GetBPsToClimbRoof( this, TRUE) ); // changed by SANDRO break; case CLIMBUPROOF: @@ -3513,7 +3740,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart // disable sight gTacticalStatus.uiFlags |= DISALLOW_SIGHT; - DeductPoints( this, APBPConstants[AP_CLIMBROOF], APBPConstants[BP_CLIMBROOF] ); + DeductPoints( this, GetAPsToClimbRoof( this, FALSE), GetBPsToClimbRoof( this, FALSE) ); // changed by SANDRO break; case JUMP_OVER_BLOCKING_PERSON: @@ -3522,7 +3749,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart { INT32 usNewGridNo; - DeductPoints( this, APBPConstants[AP_JUMP_OVER], APBPConstants[BP_JUMP_OVER] ); + DeductPoints( this, GetAPsToJumpOver( this ), APBPConstants[BP_JUMP_OVER] ); // changed by SANDRO usNewGridNo = NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ); usNewGridNo = NewGridNo( usNewGridNo, DirectionInc( this->ubDirection ) ); @@ -3815,9 +4042,10 @@ void SOLDIERTYPE::EVENT_InternalSetSoldierPosition( FLOAT dNewXPos, FLOAT dNewYP this->pathing.sFinalDestination = sNewGridNo; } + // HEADROCK HAM 4: TODO: Figure out whether this has any influence in-game? // Copy old values - this->dOldXPos = this->dXPos; - this->dOldYPos = this->dYPos; + //this->sOldXPos = this->dXPos; + //this->sOldYPos = this->dYPos; // Set New pos this->dXPos = dNewXPos; @@ -4046,8 +4274,24 @@ void SOLDIERTYPE::SetSoldierGridNo( INT32 sNewGridNo, BOOLEAN fForceRemove ) //this->sZLevelOverride = (sZLevel*Z_SUBLAYERS)+ROOF_Z_LEVEL; this->sZLevelOverride = TOPMOST_Z_LEVEL; } + /* + if ( IsJumpableWindowPresentAtGridNo( sNewGridNo ) ) + { + //sX = MapX( sNewGridNo ); + //sY = MapY( sNewGridNo ); + //GetWorldXYAbsoluteScreenXY( sX, sY, &sWorldX, &sZLevel); + //this->sZLevelOverride = (sZLevel*Z_SUBLAYERS)+ROOF_Z_LEVEL; + this->sZLevelOverride = TOPMOST_Z_LEVEL; + } + */ - + //dddokno{ ??????? + //if ( IsOknoFencePresentAtGridno( sNewGridNo ) ) + //{ + // this->sZLevelOverride = TOPMOST_Z_LEVEL; + //} + //dddokno} + // Add/ remove tree if we are near it // CheckForFullStructures( this ); @@ -4453,7 +4697,11 @@ UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight ) // Check for rocket laucncher.... if ( Item[pSoldier->inv[ HANDPOS ].usItem].rocketlauncher ) { - return( SHOOT_ROCKET ); + //***ddd if shoot crouched + if(ubHeight == ANIM_STAND) + return( SHOOT_ROCKET ); + if(ubHeight == ANIM_CROUCH) + return( SHOOT_ROCKET_CROUCHED ); } // Check for mortar.... @@ -4633,7 +4881,16 @@ UINT16 SOLDIERTYPE::GetMoveStateBasedOnStance( UINT8 ubStanceHeight ) } else { - return( SWATTING ); + //***ddd + // .. 1 , + UINT16 usItem = this->inv[ HANDPOS ].usItem; + if( this->inv[ HANDPOS ].exists() == true && + //(this->ubBodyType == BIGMALE || this->ubBodyType == REGFEMALE )&& + (Item[ usItem ].usItemClass == IC_BLADE || Item[ usItem ].usItemClass == IC_THROWING_KNIFE) ) + return( SWATTING_WK ); + else + return( SWATTING ); + } break; @@ -5018,14 +5275,72 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1 } else if ( Item[ usWeaponIndex ].usItemClass & IC_BLADE ) { - sBreathLoss = APBPConstants[BP_GET_HIT]; + // SANDRO - slightly reduce breath damage of melee weapons, it is an issue for martial arts + if (gGameOptions.fNewTraitSystem) + sBreathLoss = (APBPConstants[BP_GET_HIT] * (100 + gSkillTraitValues.bPercentModifierBladesBreathLoss) / 100); + else + sBreathLoss = APBPConstants[BP_GET_HIT]; ubReason = TAKE_DAMAGE_BLADE; } else if ( Item[ usWeaponIndex ].usItemClass & IC_PUNCH ) { - // damage from hand-to-hand is 1/4 normal, 3/4 breath.. the sDamage value - // is actually how much breath we'll take away - sBreathLoss = sDamage * 100; + //////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits + UINT16 sBreathRegainPenaltyMultiplier = 0; + if (gGameOptions.fNewTraitSystem) + { + if ( ubAttackerID != NOBODY ) + { + if (!(MercPtrs[ubAttackerID]->inv[HANDPOS].exists()) || Item[MercPtrs[ubAttackerID]->inv[HANDPOS].usItem].brassknuckles) + { + // with enhanced CCS, make the lost breath harder to regenerate, which makes CQC more usable + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) + sBreathRegainPenaltyMultiplier = 10; + + sBreathLoss = sDamage * ( 100 + gSkillTraitValues.bPercentModifierHtHBreathLoss); // 80% only for untrained mercs + + // martial arts bonus for breath damage + if ( HAS_SKILL_TRAIT( MercPtrs[ubAttackerID], MARTIAL_ARTS_NT )) + { + sBreathLoss += sDamage * gSkillTraitValues.ubMABonusBreathDamageHandToHand * NUM_SKILL_TRAITS( MercPtrs[ubAttackerID], MARTIAL_ARTS_NT ); + + sBreathRegainPenaltyMultiplier += ( gSkillTraitValues.usMALostBreathRegainPenalty * NUM_SKILL_TRAITS( MercPtrs[ubAttackerID], MARTIAL_ARTS_NT )); + } + } + else + { + // with enhanced CCS, make the lost breath harder to regenerate, which makes CQC more usable + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) + sBreathRegainPenaltyMultiplier = 15; + + sBreathLoss = sDamage * (100 + gSkillTraitValues.bPercentModifierBluntBreathLoss); // 50% only for melee weapons + } + } + else + { + sBreathLoss = sDamage * ( 100 + gSkillTraitValues.bPercentModifierHtHBreathLoss); + } + // bodybuilding reduces this to half + if ( HAS_SKILL_TRAIT( this, BODYBUILDING_NT )) + { + sBreathLoss = max( 10, (sBreathLoss * (100 - gSkillTraitValues.ubBBBreathLossForHtHImpactReduction) / 100)); + } + } + else + { + // with enhanced CCS, make the lost breath harder to regenerate, which makes CQC more usable + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) + sBreathRegainPenaltyMultiplier = 10; + // damage from hand-to-hand is 1/4 normal, 3/4 breath.. the sDamage value + // is actually how much breath we'll take away + sBreathLoss = sDamage * 100; + } + if ( sBreathRegainPenaltyMultiplier > 0 ) + { + // unregainable breath damage + this->lUnregainableBreath += ((sBreathLoss * sBreathRegainPenaltyMultiplier )/100); + } + //////////////////////////////////////////////////////////////////////////// sDamage = sDamage / PUNCH_REAL_DAMAGE_PORTION; if ( AreInMeanwhile() && gCurrentMeanwhileDef.ubMeanwhileID == INTERROGATION ) { @@ -5131,6 +5446,53 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1 } #endif + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Increased breath damage resistance of Militia (bonus counted twice) + if (this->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaDamageResistance != 0) + sBreathLoss -= ((sBreathLoss * gGameExternalOptions.bGreenMilitiaDamageResistance) /75); + else if (this->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaDamageResistance != 0) + sBreathLoss -= ((sBreathLoss * gGameExternalOptions.bRegularMilitiaDamageResistance) /75); + else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0) + sBreathLoss -= ((sBreathLoss * gGameExternalOptions.bVeteranMilitiaDamageResistance) /75); + // bonus for enemy too + else if (this->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminDamageResistance != 0) + sBreathLoss -= ((sBreathLoss * gGameExternalOptions.sEnemyAdminDamageResistance) /100); + else if (this->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0) + sBreathLoss -= ((sBreathLoss * gGameExternalOptions.sEnemyRegularDamageResistance) /100); + else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0) + sBreathLoss -= ((sBreathLoss * gGameExternalOptions.sEnemyEliteDamageResistance) /100); + ////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - option to make special NPCs stronger - breath damage resistance + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( this->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + sBreathLoss -= (sBreathLoss * gGameExternalOptions.usSpecialNPCStronger / 100); + break; + } + } + + if ( sBreathLoss < 0 ) + sBreathLoss = 0; + //////////////////////////////////////////////////////////////////////////////////// // OK, If we are a vehicle.... damage vehicle...( people inside... ) if ( this->flags.uiStatusFlags & SOLDIER_VEHICLE ) @@ -6355,20 +6717,34 @@ void EVENT_InternalSetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT8 ubNe { if ( gAnimControl[ usAnimState ].uiFlags & ( ANIM_BREATH | ANIM_OK_CHARGE_AP_FOR_TURN | ANIM_FIREREADY ) && !fInitalMove && !pSoldier->flags.fDontChargeTurningAPs ) { + // SANDRO - hey, we have a function for this around, why not to use it, hm? + // silversurfer: we better don't do that. GetAPsToLook( ... ) will charge APs for getting to crouched/prone position + // which is already done by SOLDIERTYPE::EVENT_InitNewSoldierAnim( ... ), we would charge twice... + // DeductPoints( pSoldier, GetAPsToLook( pSoldier ), 0 ); // Deduct points for initial turn! switch( gAnimControl[ usAnimState ].ubEndHeight ) { // Now change to appropriate animation case ANIM_STAND: - DeductPoints( pSoldier, APBPConstants[AP_LOOK_STANDING], 0 ); + // martial artists can turn faster + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + DeductPoints( pSoldier, ( max( 1, (INT16)((APBPConstants[AP_LOOK_STANDING] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))), 0 ); + else + DeductPoints( pSoldier, APBPConstants[AP_LOOK_STANDING], 0 ); break; case ANIM_CROUCH: - DeductPoints( pSoldier, APBPConstants[AP_LOOK_CROUCHED], 0 ); + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + DeductPoints( pSoldier, ( max( 1, (INT16)((APBPConstants[AP_LOOK_CROUCHED] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))), 0 ); + else + DeductPoints( pSoldier, APBPConstants[AP_LOOK_CROUCHED], 0 ); break; case ANIM_PRONE: - DeductPoints( pSoldier, APBPConstants[AP_LOOK_PRONE], 0 ); + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + DeductPoints( pSoldier, (max( 1, (INT16)((APBPConstants[AP_LOOK_PRONE] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5))), 0 ); + else + DeductPoints( pSoldier, APBPConstants[AP_LOOK_PRONE], 0 ); break; } @@ -6655,8 +7031,20 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou if ( (this->bTeam == gbPlayerNum) && (this->ubProfile != NO_PROFILE) ) { - switch( gMercProfiles[ this->ubProfile ].bPersonalityTrait ) + switch( gMercProfiles[ this->ubProfile ].bDisability ) { + // SANDRO - added heat intolerant + case HEAT_INTOLERANT: + if ( MercIsHot( this ) ) + { + HandleMoraleEvent( this, MORALE_HEAT_INTOLERANT_IN_DESERT, this->sSectorX, this->sSectorY, this->bSectorZ ); + if ( !(this->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_PERSONALITY) && this->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER ) + { + TacticalCharacterDialogue( this, QUOTE_PERSONALITY_TRAIT ); + this->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_PERSONALITY; + } + } + break; case FEAR_OF_INSECTS: if ( MercSeesCreature( this ) ) { @@ -6730,6 +7118,14 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou this->aiData.bPassedLastInterrupt = FALSE; } } + + // HEADROCK HAM 4: Store this soldier's X/Y cell coordinates into his SOLDIERTYPE data. + INT16 sStartPosX = 0; + INT16 sStartPosY = 0; + ConvertGridNoToCenterCellXY( this->sGridNo, &sStartPosX, &sStartPosY ); + this->sOldXPos = sStartPosX; + this->sOldYPos = sStartPosY; + } // UTILITY FUNCTIONS CALLED BY OVERHEAD.H @@ -7446,7 +7842,7 @@ void AdjustAniSpeed( SOLDIERTYPE *pSoldier ) } } - + //pSoldier->sAniDelay =1;//for max speed uncomment //ddd RESETTIMECOUNTER( pSoldier->timeCounters.UpdateCounter, pSoldier->sAniDelay ); } @@ -7519,6 +7915,9 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier break; case SWATTING: + //***ddd + case SWATTING_WK: + case SWAT_BACKWARDS_WK: // Adjust based on body type if ( pStatsSoldier->ubBodyType <= REGFEMALE ) @@ -7603,7 +8002,23 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier // ATE: If realtime, and stealth mode... if ( pStatsSoldier->bStealthMode ) { - pSoldier->sAniDelay = (INT16)( pSoldier->sAniDelay * 2 ); + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) + { + // Stealthy skill decreases movement speed penalty while on stealthy mode - SANDRO + pSoldier->sAniDelay = (INT16)( (pSoldier->sAniDelay * (200 - gSkillTraitValues.ubSTStealthModeSpeedBonus)) / 100 ); + } + else // original + { + pSoldier->sAniDelay = (INT16)( pSoldier->sAniDelay * 2 ); + } + } + // SANDRO - STOMP traits - bonus to movement speed for Athletics + if ( gGameOptions.fNewTraitSystem && (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_MOVING ) ) + { + if ( HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT ) ) + { + pSoldier->sAniDelay = (INT16)( pSoldier->sAniDelay * (100 - min(75, gSkillTraitValues.ubATAPsMovementReduction) ) / 100 ); + } } //pSoldier->sAniDelay = pSoldier->sAniDelay * ( 1 * gTacticalStatus.bRealtimeSpeed / 2 ); @@ -7674,6 +8089,12 @@ void SetSoldierAniSpeed( SOLDIERTYPE *pSoldier ) AdjustAniSpeed( pSoldier ); + // SANDRO - make the spin kick animation a bit faster + if ( pSoldier->usAnimState == NINJA_SPINKICK ) + { + pSoldier->sAniDelay = (pSoldier->sAniDelay *3/4); + } + if ( _KeyDown( SPACE ) ) { //pSoldier->sAniDelay = 1000; @@ -8055,6 +8476,116 @@ void SOLDIERTYPE::BeginSoldierClimbFence( void ) } +//---legion by JAzz--------------------------------------- + +void SOLDIERTYPE::BeginSoldierClimbWindow( void ) +{ + INT8 bDirection; + + // Make sure we hop the correct fence to follow our path! + if (this->pathing.usPathIndex < this->pathing.usPathDataSize) + { + bDirection = (INT8) this->pathing.usPathingData[ this->pathing.usPathIndex]; + } + else + { + bDirection = this->ubDirection; + } + + if ( FindWindowJumpDirection( this, this->sGridNo, bDirection, &bDirection ) && this->pathing.bLevel == 0 && ( this->ubDirection == NORTH || this->ubDirection == EAST || this->ubDirection == SOUTH || this->ubDirection == WEST ) ) + { + this->sTempNewGridNo = NewGridNo( this->sGridNo, (UINT16)DirectionInc(bDirection ) ); + this->flags.fDontChargeTurningAPs = TRUE; + EVENT_InternalSetSoldierDesiredDirection( this, bDirection, FALSE, this->usAnimState ); + this->flags.fTurningUntilDone = TRUE; + // ATE: Reset flag to go back to prone... + this->flags.bTurningFromPronePosition = TURNING_FROM_PRONE_OFF; + this->usPendingAnimation = HOPFENCE; + } + +} + +void SOLDIERTYPE::BeginSoldierFence( void ) +{ + INT8 bNewDirection; + UINT8 ubWhoIsThere; + + + if ( FindFenceDirection( this, this->sGridNo, this->ubDirection, &bNewDirection ) && ( this->pathing.bLevel == 0 ) ) + { + if ( EnoughPoints( this, GetAPsToClimbRoof( this, FALSE ), 0, TRUE ) ) + { + //Kaiden: Helps if we look where we are going before we try to climb on top of someone + ubWhoIsThere = WhoIsThere2( NewGridNo( this->sGridNo, (UINT16)DirectionInc(bNewDirection ) ), 1 ); + if ( ubWhoIsThere != NOBODY && ubWhoIsThere != this->ubID ) + { + return; + } + else + { + + if (this->bTeam == gbPlayerNum) + { + SetUIBusy( this->ubID ); + } + + this->sTempNewGridNo = NewGridNo( this->sGridNo, (UINT16)DirectionInc(bNewDirection ) ); + + this->ubPendingDirection = bNewDirection; + this->EVENT_InitNewSoldierAnim( CLIMBUPROOF, 0 , FALSE ); + + this->InternalReceivingSoldierCancelServices( FALSE ); + this->InternalGivingSoldierCancelServices( FALSE ); + + this->BeginSoldierFenceUp( ); + } + + } + } + +} + +void SOLDIERTYPE::BeginSoldierFenceUp( void ) +{ + INT8 bNewDirection; + UINT8 ubWhoIsThere; + + if ( FindLowerLevelFence( this, this->sGridNo, this->ubDirection, &bNewDirection ) && ( this->pathing.bLevel > 0 ) ) + { + if ( EnoughPoints( this, GetAPsToClimbRoof( this, TRUE ), 0, TRUE ) ) + { + //Kaiden: Helps if we look where we are going before we try to climb on top of someone + ubWhoIsThere = WhoIsThere2( NewGridNo( this->sGridNo, (UINT16)DirectionInc(bNewDirection ) ), 0 ); + if ( ubWhoIsThere != NOBODY && ubWhoIsThere != this->ubID ) + { + return; + } + else + { + + if (this->bTeam == gbPlayerNum) + { + SetUIBusy( this->ubID ); + } + + this->sTempNewGridNo = NewGridNo( this->sGridNo, (UINT16)DirectionInc(bNewDirection ) ); + + bNewDirection = gTwoCDirection[ bNewDirection ]; + + this->ubPendingDirection = bNewDirection; + this->EVENT_InitNewSoldierAnim( CLIMBDOWNROOF, 0 , FALSE ); + + this->InternalReceivingSoldierCancelServices( FALSE ); + this->InternalGivingSoldierCancelServices( FALSE ); + + } + } + } + +} +//------------------------------------------------------------------------------------------ + + UINT32 SleepDartSuccumbChance( SOLDIERTYPE * pSoldier ) { UINT32 uiChance; @@ -8433,6 +8964,26 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr this->stats.bLife -= sLifeDeduct; } + ///////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Doctor trait - need a variable holding the number of insta-healable hit points + if ((IS_MERC_BODY_TYPE( this ) || IS_CIV_BODY_TYPE( this )) && ( gGameOptions.fNewTraitSystem )) + { + if ( this->stats.bLife <= 0 ) + { + // noone can help him now, he's gone + this->iHealableInjury = 0; + } + else + { + // Otherwise add healable injury value - it's in hundredths for better precision + this->iHealableInjury += (sLifeDeduct * 100); + // check if we are not mysteriously beyond a limit - we cannot have more than life we actually lost + if (this->iHealableInjury > ((this->stats.bLifeMax - this->stats.bLife) * 100) ) + this->iHealableInjury = ((this->stats.bLifeMax - this->stats.bLife) * 100); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////// + // ATE: Put some logic in here to allow enemies to die quicker..... // Are we an enemy? if ( this->bSide != gbPlayerNum && !this->aiData.bNeutral && this->ubProfile == NO_PROFILE ) @@ -8444,7 +8995,7 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr if ( ubReason == TAKE_DAMAGE_BLOODLOSS ) { // Fifty-fifty chance to die now! - if ( Random( 2 ) == 0 || gTacticalStatus.Team[ this->bTeam ].bMenInSector == 1 ) + if ( Random( 3 ) == 0 || gTacticalStatus.Team[ this->bTeam ].bMenInSector == 1 ) { // Kill! this->stats.bLife = 0; @@ -8597,6 +9148,9 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr //add a flag to the item so when all enemies are killed, we can run through and reveal all the enemies items usItemFlags |= WORLD_ITEM_DROPPED_FROM_ENEMY; } + if(UsingNewAttachmentSystem()==true){ + ReduceAttachmentsOnGunForNonPlayerChars(this, &(this->inv[ HANDPOS ])); + } AddItemToPool( this->sGridNo, &(this->inv[ HANDPOS ]), bVisible, this->pathing.bLevel, usItemFlags, -1 ); //Madd: added usItemFlags to function arguments DeleteObj( &(this->inv[HANDPOS]) ); } @@ -8663,12 +9217,20 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr } } - - SOLDIERTYPE *pSoldier = this; - if (PTR_OURTEAM) + // Why this? No need for new declaration.. + //SOLDIERTYPE *pSoldier = this; + //if (PTR_OURTEAM) + if (this->bTeam == gbPlayerNum) { // EXPERIENCE GAIN: Took some damage - StatChange( this, EXPERAMT, ( UINT16 )( 5 * ubCombinedLoss ), FROM_FAILURE ); + if ( ubReason != TAKE_DAMAGE_BLOODLOSS ) + StatChange( this, EXPERAMT, ( UINT16 )( 5 * ubCombinedLoss ), FROM_FAILURE ); + + // SANDRO - gain some exp towards max health if bleeding + if ( this->stats.bLifeMax < 100 && ubReason == TAKE_DAMAGE_BLOODLOSS && !(AM_A_ROBOT( this )) ) + { + StatChange( this, HEALTHAMT, ( UINT16 )( 3 * ubCombinedLoss ), FROM_FAILURE ); + } // Check for quote if ( !(this->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_BEING_PUMMELED ) ) @@ -8691,7 +9253,9 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr } } - if ((ubAttacker != NOBODY) && (Menptr[ubAttacker].bTeam == OUR_TEAM) && (this->ubProfile != NO_PROFILE) && (this->ubProfile >= FIRST_RPC && this->ubProfile < GASTON )) +// if ((ubAttacker != NOBODY) && (Menptr[ubAttacker].bTeam == OUR_TEAM) && (this->ubProfile != NO_PROFILE) && (this->ubProfile >= FIRST_RPC && this->ubProfile < GASTON )) + //new profiles by Jazz + if ( (ubAttacker != NOBODY) && (Menptr[ubAttacker].bTeam == OUR_TEAM) && (this->ubProfile != NO_PROFILE) && gProfilesRPC[this->ubProfile].ProfilId == this->ubProfile || gProfilesNPC[this->ubProfile].ProfilId == this->ubProfile ) { gMercProfiles[this->ubProfile].ubMiscFlags |= PROFILE_MISC_FLAG_WOUNDEDBYPLAYER; if (this->ubProfile == 114) @@ -8961,11 +9525,20 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe // Adjust based on morale... if ( ubBattleSoundID == BATTLE_SOUND_OK1 && pSoldier->aiData.bMorale < LOW_MORALE_BATTLE_SND_THREASHOLD ) { - ubBattleSoundID = BATTLE_SOUND_LOWMARALE_OK1; + //ddd { + if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) + ubBattleSoundID = BATTLE_SOUND_LOWMARALE_OK1; + ///ddd } + + //ubBattleSoundID = BATTLE_SOUND_LOWMARALE_OK1; } if ( ubBattleSoundID == BATTLE_SOUND_ATTN1 && pSoldier->aiData.bMorale < LOW_MORALE_BATTLE_SND_THREASHOLD ) { - ubBattleSoundID = BATTLE_SOUND_LOWMARALE_ATTN1; + //ddd { + if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) + ubBattleSoundID = BATTLE_SOUND_LOWMARALE_ATTN1; + + //ubBattleSoundID = BATTLE_SOUND_LOWMARALE_ATTN1; } ubSoundID = ubBattleSoundID; @@ -8975,6 +9548,11 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe { if( gGameSettings.fOptions[ TOPTION_MUTE_CONFIRMATIONS ] ) return( TRUE ); + //ddd { + if(!Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) + return( TRUE ); + ///ddd } + //else a speech sound is to be played else fSpeechSound = TRUE; @@ -9092,6 +9670,9 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe spParms.uiPan = SoundDir( pSoldier->sGridNo ); spParms.uiPriority=GROUP_PLAYER; + if ( gSoundProfileValue[pSoldier->ubProfile].EnabledSound == TRUE || pSoldier->ubProfile == NO_PROFILE ) + { + if ( ( uiSoundID = SoundPlay( zFilename, &spParms ) ) == SOUND_ERROR ) { return( FALSE ); @@ -9114,6 +9695,12 @@ BOOLEAN SOLDIERTYPE::InternalDoMercBattleSound( UINT8 ubBattleSoundID, INT8 bSpe return( TRUE ); } + + } + else + { + return( TRUE ); + } } BOOLEAN SOLDIERTYPE::DoMercBattleSound( UINT8 ubBattleSoundID ) @@ -10090,6 +10677,7 @@ void SOLDIERTYPE::ReviveSoldier( void ) this->stats.bLife = this->stats.bLifeMax; this->bBleeding = 0; + this->iHealableInjury = 0; // added by SANDRO this->ubDesiredHeight = ANIM_STAND; AddManToTeam( this->bTeam ); @@ -10502,14 +11090,14 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio this->EVENT_SetSoldierDirection( ubDirection ); } - // Are we a martial artist? - if ( HAS_SKILL_TRAIT( this, MARTIALARTS ) ) + // Are we a martial artist? - SANDRO - added new/old traits check + if ( ((NUM_SKILL_TRAITS( this, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 ) ) && gGameOptions.fNewTraitSystem ) || + (HAS_SKILL_TRAIT( this, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) { fMartialArtist = TRUE; } - - if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar ) + if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar && this->ubBodyType == REGMALE ) // SANDRO - added check for body type { // Are we in attack mode yet? if ( this->usAnimState != NINJA_BREATH && gAnimControl[ this->usAnimState ].ubHeight == ANIM_STAND && gAnimControl[ pTSoldier->usAnimState ].ubHeight != ANIM_PRONE ) @@ -10677,10 +11265,25 @@ void SOLDIERTYPE::EVENT_SoldierBeginFirstAid( INT32 sGridNo, UINT8 ubDirection ) { pTSoldier = MercPtrs[ usSoldierIndex ]; + //SANDRO - hack! Find out if we are a doctor with medical bag trying to make a surgery + this->fDoingSurgery = FALSE; + if ((NUM_SKILL_TRAITS( this, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery) && Item[ this->inv[HANDPOS].usItem].medicalkit && gGameOptions.fNewTraitSystem ) + { + if (((pTSoldier->bTeam == OUR_TEAM) || (pTSoldier->bTeam == MILITIA_TEAM)) + && (IS_MERC_BODY_TYPE( pTSoldier ) || IS_CIV_BODY_TYPE( pTSoldier )) + && (pTSoldier->iHealableInjury >= 100) && pTSoldier->ubID != this->ubID + && (gTacticalStatus.ubLastRequesterSurgeryTargetID == pTSoldier->ubID )) + { + this->fDoingSurgery = TRUE; + } + } + // OK, check if we should play quote... if ( pTSoldier->bTeam != gbPlayerNum ) { - if ( pTSoldier->ubProfile != NO_PROFILE && pTSoldier->ubProfile >= FIRST_RPC && pTSoldier->ubProfile < GASTON && !RPC_RECRUITED( pTSoldier ) ) +// if ( pTSoldier->ubProfile != NO_PROFILE && pTSoldier->ubProfile >= FIRST_RPC && pTSoldier->ubProfile < GASTON && !RPC_RECRUITED( pTSoldier ) ) + //new profiles by Jazz + if ( pTSoldier->ubProfile != NO_PROFILE && ( gProfilesRPC[pTSoldier->ubProfile].ProfilId == pTSoldier->ubProfile || gProfilesNPC[pTSoldier->ubProfile].ProfilId == pTSoldier->ubProfile ) && !RPC_RECRUITED( pTSoldier ) ) { fRefused = PCDoesFirstAidOnNPC( pTSoldier->ubProfile ); } @@ -10704,6 +11307,8 @@ void SOLDIERTYPE::EVENT_SoldierBeginFirstAid( INT32 sGridNo, UINT8 ubDirection ) if ( fRefused ) { + this->fDoingSurgery = FALSE; // SANDRO + UnSetUIBusy( this->ubID ); return; } @@ -10768,14 +11373,17 @@ void SOLDIERTYPE::EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection ) UnSetUIBusy( this->ubID ); } - +////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - This whole procedure was merged with the surgery ability of the doctor trait UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT16 sStatus ) { UINT32 uiDressSkill, uiPossible, uiActual, uiMedcost, uiDeficiency, uiAvailAPs, uiUsedAPs; - UINT8 ubBelowOKlife, ubPtsLeft; + UINT8 ubBelowOKlife, ubPtsLeft = 0; BOOLEAN fRanOut = FALSE; + BOOLEAN fOnSurgery = FALSE; + INT8 bInitialBleeding; - if (pVictim->bBleeding < 1 && pVictim->stats.bLife >= OKLIFE ) + if ((pVictim->bBleeding < 1 && pVictim->stats.bLife >= OKLIFE) && !(pVictim->iHealableInjury > 0 && this->fDoingSurgery)) { return(0); // nothing to do, shouldn't have even been called! } @@ -10785,17 +11393,36 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 return(0); } + bInitialBleeding = pVictim->bBleeding; + // in case he has multiple kits in hand, limit influence of kit status to 100%! if (sStatus >= 100) { sStatus = 100; } + // if we are going to do the surgery + if (pVictim->iHealableInjury > 0 && this->fDoingSurgery && this->ubID != pVictim->ubID && gGameOptions.fNewTraitSystem + && (NUM_SKILL_TRAITS( this, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery) && Item[this->inv[ HANDPOS ].usItem].medicalkit) + { + fOnSurgery = TRUE; + } + // calculate wound-dressing skill (3x medical, 2x equip, 1x level, 1x dex) - uiDressSkill = ( ( 3 * EffectiveMedical( this ) ) + // medical knowledge - ( 2 * sStatus) + // state of medical kit - (10 * EffectiveExpLevel( this ) ) + // battle injury experience - EffectiveDexterity( this ) ) / 7; // general "handiness" + if ( gGameOptions.fNewTraitSystem ) + { + uiDressSkill = ( ( 7 * EffectiveMedical( this ) ) + // medical knowledge + ( sStatus) + // state of medical kit + (10 * EffectiveExpLevel( this ) ) + // battle injury experience + EffectiveDexterity( this ) ) / 10; // general "handiness" + } + else + { + uiDressSkill = ( ( 3 * EffectiveMedical( this ) ) + // medical knowledge + ( 2 * sStatus) + // state of medical kit + (10 * EffectiveExpLevel( this ) ) + // battle injury experience + EffectiveDexterity( this ) ) / 7; // general "handiness" + } // try to use every AP that the merc has left uiAvailAPs = this->bActionPoints; @@ -10814,50 +11441,70 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 if (!uiPossible) return(0); - - if (Item[this->inv[ HANDPOS ].usItem].medicalkit ) // using the GOOD medic stuff + // using the GOOD medic stuff + if (Item[this->inv[ HANDPOS ].usItem].medicalkit && !(fOnSurgery)) // added check { uiPossible += ( uiPossible / 2); // add extra 50 % } + // Doctor trait improves basic bandaging ability + if (!(fOnSurgery) && gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( this, DOCTOR_NT )) + { + uiPossible = uiPossible * (100 - gSkillTraitValues.bSpeedModifierBandaging) / 100; + uiPossible += ( uiPossible * gSkillTraitValues.ubDOBandagingSpeedPercent * NUM_SKILL_TRAITS( this, DOCTOR_NT ) / 100); + } uiActual = uiPossible; // start by assuming maximum possible // figure out how far below OKLIFE the victim is - if (pVictim->stats.bLife >= OKLIFE) + // SANDRO - only if we are actually here to bandage the target + if (pVictim->bBleeding) { - ubBelowOKlife = 0; + if (pVictim->stats.bLife >= OKLIFE) + { + ubBelowOKlife = 0; + } + else + { + ubBelowOKlife = OKLIFE - pVictim->stats.bLife; + } + + // figure out how many healing pts we need to stop dying (2x cost) + uiDeficiency = (2 * ubBelowOKlife ); + + // if, after that, the patient will still be bleeding + if ( (pVictim->bBleeding - ubBelowOKlife ) > 0) + { + // then add how many healing pts we need to stop bleeding (1x cost) + uiDeficiency += ( pVictim->bBleeding - ubBelowOKlife ); + } + // On surgery, alter this by amount of life we can heal + if ( fOnSurgery ) + { + uiDeficiency += (pVictim->iHealableInjury / 100); + } + + // now, make sure we weren't going to give too much + if ( uiActual > uiDeficiency) // if we were about to apply too much + uiActual = uiDeficiency; // reduce actual not to waste anything } - else - { - ubBelowOKlife = OKLIFE - pVictim->stats.bLife; - } - - // figure out how many healing pts we need to stop dying (2x cost) - uiDeficiency = (2 * ubBelowOKlife ); - - // if, after that, the patient will still be bleeding - if ( (pVictim->bBleeding - ubBelowOKlife ) > 0) - { - // then add how many healing pts we need to stop bleeding (1x cost) - uiDeficiency += ( pVictim->bBleeding - ubBelowOKlife ); - } - - // now, make sure we weren't going to give too much - if ( uiActual > uiDeficiency) // if we were about to apply too much - uiActual = uiDeficiency; // reduce actual not to waste anything - // now make sure we HAVE that much if (Item[this->inv[ HANDPOS ].usItem].medicalkit ) { - uiMedcost = (uiActual + 1) / 2; // cost is only half, rounded up + if (fOnSurgery) + uiMedcost = (uiActual * gSkillTraitValues.usDOSurgeryMedBagConsumption ) /100; // surgery drains the kit a lot + else + uiMedcost = (uiActual + 1) / 2; // cost is only half, rounded up if ( uiMedcost > (UINT32)sKitPts ) // if we can't afford this { fRanOut = TRUE; uiMedcost = sKitPts; // what CAN we afford? - uiActual = uiMedcost * 2; // give double this as aid + if (fOnSurgery) // surgery check + uiActual = (uiMedcost * 100 )/ gSkillTraitValues.usDOSurgeryMedBagConsumption; + else + uiActual = uiMedcost * 2; // give double this as aid } } else @@ -10882,6 +11529,14 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 // if we have enough points to bring him all the way to OKLIFE this turn if ( ubPtsLeft >= (2 * ubBelowOKlife ) ) { + // insta-healable injury check + if (pVictim->iHealableInjury > 0) + { + pVictim->iHealableInjury -= ((OKLIFE - pVictim->stats.bLife) * 100); + if (pVictim->iHealableInjury < 0) + pVictim->iHealableInjury = 0; + } + // raise life to OKLIFE pVictim->stats.bLife = OKLIFE; @@ -10893,6 +11548,14 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 } else { + // SANDRO - insta-healable injury check + if (pVictim->iHealableInjury > 0) + { + pVictim->iHealableInjury -= (( ubPtsLeft / 2) * 100); + if (pVictim->iHealableInjury < 0) + pVictim->iHealableInjury = 0; + } + pVictim->stats.bLife += ( ubPtsLeft / 2); pVictim->bBleeding -= ( ubPtsLeft / 2); @@ -10919,11 +11582,110 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 // update patient's entire panel (could have regained consciousness, etc.) } + // SURGERY + // first return the real life back, then bandage the rest if possible + if (fOnSurgery && gGameOptions.fNewTraitSystem ) // double check for new traits + { + UINT16 usLifeReturned = 0; + UINT16 usReturnDamagedStatRate = 0; + // find out if we will repair any stats... + if ( NumberOfDamagedStats( pVictim ) > 0 ) + { + usReturnDamagedStatRate = ((gSkillTraitValues.usDORepairStatsRateBasic + gSkillTraitValues.usDORepairStatsRateOnTop * NUM_SKILL_TRAITS( this, DOCTOR_NT ))); + usReturnDamagedStatRate -= max( 0, ((usReturnDamagedStatRate * gSkillTraitValues.ubDORepStPenaltyIfAlsoHealing ) / 100)); + + // ... in which case, reduce the points + ubPtsLeft = max(0,((ubPtsLeft * (100 - gSkillTraitValues.ubDOHealingPenaltyIfAlsoStatRepair )) / 100)); + } + + // Important note! : HealableInjury is always stores the total HPs the victim is missing, not the amount which we will heal, + // so we always take a portion of patient's damage here, reduce the HealableInjury by this portion, while only healing a portion of this portion in actual HPs; + // this means the rest of HPs will remain as "unhealable", the patient will miss X HPs but has no HealableInjury on self.. + if (ubPtsLeft >= (pVictim->iHealableInjury/100)) + { + usLifeReturned = pVictim->iHealableInjury * (gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop * NUM_SKILL_TRAITS( this, DOCTOR_NT ))/100; + + pVictim->iHealableInjury = 0; + // keep the rest of the points to bandaging if neccessary + if (pVictim->bBleeding > 0) + { + ubPtsLeft = max(0, (ubPtsLeft - (usLifeReturned / 100))); + ubPtsLeft += (ubPtsLeft/2); // we use medical bag so add the bonus for that. + } + else + { + ubPtsLeft = 0; + } + + // We are finished !!! + this->fDoingSurgery = FALSE; + gTacticalStatus.ubLastRequesterSurgeryTargetID = NOBODY; // reset last target + + // throw message + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[ MSG113_SURGERY_FINISHED ], pVictim->name ); + + // add to record - another surgery undergoed + if ( pVictim->ubProfile != NO_PROFILE && usLifeReturned >= 100 ) + gMercProfiles[ pVictim->ubProfile ].records.usTimesSurgeryUndergoed++; + + // add to record - another surgery made + if ( this->ubProfile != NO_PROFILE && usLifeReturned >= 100 ) + gMercProfiles[ this->ubProfile ].records.usSurgeriesMade++; + } + else + { + usLifeReturned = ubPtsLeft * (gSkillTraitValues.ubDOSurgeryHealPercentBase + gSkillTraitValues.ubDOSurgeryHealPercentOnTop * NUM_SKILL_TRAITS( this, DOCTOR_NT )); + + pVictim->iHealableInjury -= (ubPtsLeft * 100); + ubPtsLeft = 0; + } + // repair the stats here! + if ( usReturnDamagedStatRate > 0 ) + { + RegainDamagedStats( pVictim, (usLifeReturned * usReturnDamagedStatRate / 100) ); + } + + // some paranoya checks for sure + if ((pVictim->stats.bLife + (usLifeReturned / 100)) <= pVictim->stats.bLifeMax) + { + pVictim->stats.bLife += (usLifeReturned/100); + if (pVictim->bBleeding >= (usLifeReturned/100)) + { + pVictim->bBleeding -= (usLifeReturned/100); + uiMedcost += (usLifeReturned / 200); // add medkit points cost for unbandaged part + } + else + { + pVictim->bBleeding = 0; + uiMedcost += max( 0, (((usLifeReturned/100) - pVictim->bBleeding) / 2)); // add medkit points cost for unbandaged part + } + } + else // this shouldn't even happen, but we still want to have it here for sure + { + pVictim->stats.bLife = pVictim->stats.bLifeMax; + pVictim->iHealableInjury = 0; + pVictim->bBleeding = 0; + } + // Reduce max breath based on life returned + if ( (pVictim->bBreathMax - (((usLifeReturned/100) * gSkillTraitValues.usDOSurgeryMaxBreathLoss )/ 100)) <= BREATHMAX_ABSOLUTE_MINIMUM ) + { + pVictim->bBreathMax = BREATHMAX_ABSOLUTE_MINIMUM; + } + else + { + pVictim->bBreathMax -= (((usLifeReturned/100) * gSkillTraitValues.usDOSurgeryMaxBreathLoss )/ 100); + } + + if (pVictim->iHealableInjury > ((pVictim->stats.bLifeMax - pVictim->stats.bLife)*100)) + pVictim->iHealableInjury = ((pVictim->stats.bLifeMax - pVictim->stats.bLife)*100); + else if (pVictim->iHealableInjury < 0) + pVictim->iHealableInjury = 0; + } // if any healing points remain, apply that to any remaining bleeding (1/1) // DON'T spend any APs/kit pts to cure bleeding until merc is no longer dying //if ( ubPtsLeft && pVictim->bBleeding && !pVictim->dying) - if ( ubPtsLeft && pVictim->bBleeding ) + if ( ubPtsLeft && pVictim->bBleeding ) { // if we have enough points to bandage all remaining bleeding this turn if (ubPtsLeft >= pVictim->bBleeding ) @@ -10940,7 +11702,6 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 // update patient's life bar only } - // if wound has been dressed enough so that bleeding won't occur, turn off // the "warned about bleeding" flag so merc tells us about the next bleeding if ( pVictim->bBleeding <= MIN_BLEEDING_THRESHOLD ) @@ -10950,32 +11711,56 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1 // if there are any ptsLeft now, then we didn't actually get to use them - uiActual -= ubPtsLeft; + uiActual = max(0, (uiActual - ubPtsLeft)); // usedAPs equals (actionPts) * (%of possible points actually used) uiUsedAPs = ( uiActual * uiAvailAPs ) / uiPossible; - if (Item[this->inv[ HANDPOS ].usItem].medicalkit ) // using the GOOD medic stuff + if (Item[this->inv[ HANDPOS ].usItem].medicalkit && !(fOnSurgery)) // using the GOOD medic stuff { uiUsedAPs = ( uiUsedAPs * 2) / 3; // reverse 50% bonus by taking 2/3rds } - DeductPoints( this, (INT16)uiUsedAPs, (INT16)( ( uiUsedAPs * APBPConstants[BP_PER_AP_LT_EFFORT]) ) ); - - - SOLDIERTYPE* pSoldier = this; - if ( PTR_OURTEAM ) + // SANDRO - surgery is harder so cost more BPs + if (fOnSurgery) { - // MEDICAL GAIN (actual / 2): Helped someone by giving first aid - StatChange(this, MEDICALAMT, (UINT16)(uiActual / 2), FALSE); - - // DEXTERITY GAIN (actual / 6): Helped someone by giving first aid - StatChange(this, DEXTAMT, (UINT16)(uiActual / 6), FALSE); + DeductPoints( this, (INT16)uiUsedAPs, (INT16)( uiUsedAPs * 15 ) ); + } + else + { + DeductPoints( this, (INT16)uiUsedAPs, (INT16)( ( uiUsedAPs * APBPConstants[BP_PER_AP_LT_EFFORT]) ) ); } - if(is_networked && pVictim->ubID > 19)send_heal(pVictim); + if ( this->bTeam == gbPlayerNum ) + { + // surgery is harder so gives more exp + if (fOnSurgery) + { + // MEDICAL GAIN (actual / 2): Helped someone by giving first aid + StatChange(this, MEDICALAMT, (UINT16)(uiActual + 2), FALSE); + + // DEXTERITY GAIN (actual / 6): Helped someone by giving first aid + StatChange(this, DEXTAMT, (UINT16)((uiActual / 3) + 2), FALSE); + } + else + { + // MEDICAL GAIN (actual / 2): Helped someone by giving first aid + StatChange(this, MEDICALAMT, (UINT16)(uiActual / 2), FALSE); + + // DEXTERITY GAIN (actual / 6): Helped someone by giving first aid + StatChange(this, DEXTAMT, (UINT16)(uiActual / 6), FALSE); + } + } + + // merc records - bandaging + if( bInitialBleeding > 1 && pVictim->bBleeding == 0 && this->ubProfile != NO_PROFILE ) + gMercProfiles[ this->ubProfile ].records.usMercsBandaged++; + + if(is_networked && pVictim->ubID > 19)send_heal(pVictim); + return( uiMedcost ); } +////////////////////////////////////////////////////////////////////////////////////////////////////// void SOLDIERTYPE::InternalReceivingSoldierCancelServices( BOOLEAN fPlayEndAnim ) @@ -10995,6 +11780,10 @@ void SOLDIERTYPE::InternalReceivingSoldierCancelServices( BOOLEAN fPlayEndAnim ) // END SERVICE! this->ubServiceCount--; + // SANDRO - added end of surgery attempt + if (pTSoldier->fDoingSurgery) + pTSoldier->fDoingSurgery = FALSE; // Surgery finished + pTSoldier->ubServicePartner = NOBODY; if ( gTacticalStatus.fAutoBandageMode ) @@ -11043,6 +11832,10 @@ void SOLDIERTYPE::InternalGivingSoldierCancelServices( BOOLEAN fPlayEndAnim ) this->ubServicePartner = NOBODY; + // SANDRO - added end of surgery attempt + if (this->fDoingSurgery) + this->fDoingSurgery = FALSE; // Surgery finished + if ( gTacticalStatus.fAutoBandageMode ) { pTSoldier->ubAutoBandagingMedic = NOBODY; @@ -11527,11 +12320,18 @@ BOOLEAN SOLDIERTYPE::CheckForBreathCollapse( void ) if ( this->bBreathMax > 70 ) { if ( this->bBreath < 20 && !(this->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LOW_BREATH ) && - gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND ) + gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND && !(this->ubServiceCount) ) // SANDRO - added check to not play this if on healing { - // WARN! - TacticalCharacterDialogue( this, QUOTE_OUT_OF_BREATH ); - + // SANDRO - say our personality quote for being out of breath caused by heat + if ( MercIsHot( this ) && this->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER ) + { + TacticalCharacterDialogue( this, QUOTE_PERSONALITY_TRAIT ); + } + else + { + // WARN! + TacticalCharacterDialogue( this, QUOTE_OUT_OF_BREATH ); + } // Set flag indicating we were warned! this->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LOW_BREATH; } @@ -11553,11 +12353,14 @@ BOOLEAN SOLDIERTYPE::CheckForBreathCollapse( void ) if ( this->bBreath == 0 && !this->bCollapsed && !( this->flags.uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_ANIMAL | SOLDIER_MONSTER ) ) ) { - // Collapse! - // OK, Set a flag, because we may still be in the middle of an animation what is not interruptable... - this->bBreathCollapsed = TRUE; + if (!(this->ubServiceCount)) // added by SANDRO (we don't want to collapse when on surgery) + { + // Collapse! + // OK, Set a flag, because we may still be in the middle of an animation what is not interruptable... + this->bBreathCollapsed = TRUE; - return( TRUE ); + return( TRUE ); + } } return( FALSE ); @@ -11895,6 +12698,8 @@ INT32 CheckBleeding( SOLDIERTYPE *pSoldier ) // bleeding while "dying" costs a PERMANENT point of life each time! pSoldier->stats.bLifeMax--; pSoldier->bBleeding--; + if ( pSoldier->iHealableInjury >= 100) // added check for insta-healable injury - SANDRO + pSoldier->iHealableInjury -= 100; } } } @@ -11952,7 +12757,15 @@ void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed ) // If we are already dead, don't show damage! if ( !fBandagedBleed ) { - pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE ); + // SANDRO - if the soldier is bleeding out, consider this damage as done by the last attacker + if ( pSoldier->ubAttackerID != NOBODY ) + pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubAttackerID, NOWHERE, 0, TRUE ); + else if ( pSoldier->ubPreviousAttackerID != NOBODY ) + pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubPreviousAttackerID, NOWHERE, 0, TRUE ); + else if ( pSoldier->ubNextToPreviousAttackerID != NOBODY ) + pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubNextToPreviousAttackerID, NOWHERE, 0, TRUE ); + else + pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE ); } } @@ -13458,6 +14271,88 @@ void SetSoldierPersonalLightLevel( SOLDIERTYPE *pSoldier ) gpWorldLevelData[pSoldier->sGridNo].pMercHead->ubNaturalShadeLevel = 5; } +//---legion by JAzz--------------------------------------- + +void BeginSoldierFence( SOLDIERTYPE *pSoldier ) +{ + INT8 bNewDirection; + UINT8 ubWhoIsThere; + + + if ( FindFenceDirection( pSoldier, pSoldier->sGridNo, pSoldier->ubDirection, &bNewDirection ) && ( pSoldier->pathing.bLevel == 0 ) ) + { + if ( EnoughPoints( pSoldier, GetAPsToClimbRoof( pSoldier, FALSE ), 0, TRUE ) ) + { + //Kaiden: Helps if we look where we are going before we try to climb on top of someone + ubWhoIsThere = WhoIsThere2( NewGridNo( pSoldier->sGridNo, (UINT16)DirectionInc(bNewDirection ) ), 1 ); + if ( ubWhoIsThere != NOBODY && ubWhoIsThere != pSoldier->ubID ) + { + return; + } + else + { + + if (pSoldier->bTeam == gbPlayerNum) + { + SetUIBusy( pSoldier->ubID ); + } + + pSoldier->sTempNewGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)DirectionInc(bNewDirection ) ); + + pSoldier->ubPendingDirection = bNewDirection; + pSoldier->EVENT_InitNewSoldierAnim( CLIMBUPROOF, 0 , FALSE ); + + pSoldier->InternalReceivingSoldierCancelServices( FALSE ); + pSoldier->InternalGivingSoldierCancelServices( FALSE ); + + BeginSoldierFenceUp( pSoldier ); + } + + } + } + +} + +void BeginSoldierFenceUp( SOLDIERTYPE *pSoldier ) +{ + INT8 bNewDirection; + UINT8 ubWhoIsThere; + + if ( FindLowerLevelFence( pSoldier, pSoldier->sGridNo, pSoldier->ubDirection, &bNewDirection ) && ( pSoldier->pathing.bLevel > 0 ) ) + { + if ( EnoughPoints( pSoldier, GetAPsToClimbRoof( pSoldier, TRUE ), 0, TRUE ) ) + { + //Kaiden: Helps if we look where we are going before we try to climb on top of someone + ubWhoIsThere = WhoIsThere2( NewGridNo( pSoldier->sGridNo, (UINT16)DirectionInc(bNewDirection ) ), 0 ); + if ( ubWhoIsThere != NOBODY && ubWhoIsThere != pSoldier->ubID ) + { + return; + } + else + { + + if (pSoldier->bTeam == gbPlayerNum) + { + SetUIBusy( pSoldier->ubID ); + } + + pSoldier->sTempNewGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)DirectionInc(bNewDirection ) ); + + bNewDirection = gTwoCDirection[ bNewDirection ]; + + pSoldier->ubPendingDirection = bNewDirection; + pSoldier->EVENT_InitNewSoldierAnim( CLIMBDOWNROOF, 0 , FALSE ); + + pSoldier->InternalReceivingSoldierCancelServices( FALSE ); + pSoldier->InternalGivingSoldierCancelServices( FALSE ); + + } + } + } + +} +//------------------------------------------------------------------------------------------ + BOOLEAN DoesSoldierWearGasMask(SOLDIERTYPE *pSoldier)//dnl ch40 200909 { INT8 bPosOfMask = FindGasMask(pSoldier); @@ -13466,3 +14361,335 @@ BOOLEAN DoesSoldierWearGasMask(SOLDIERTYPE *pSoldier)//dnl ch40 200909 return(TRUE); return(FALSE); } + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - added following functions +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOLEAN HAS_SKILL_TRAIT( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber ) +{ + if ( pSoldier == NULL ) + return( FALSE ); + + INT8 bNumMajorTraitsCounted = 0; + + // check old/new traits + if (gGameOptions.fNewTraitSystem) + { + for ( INT8 bCnt = 0; bCnt < gSkillTraitValues.ubMaxNumberOfTraits; bCnt++ ) + { + if ( uiSkillTraitNumber > 0 && uiSkillTraitNumber <= NUM_MAJOR_TRAITS ) + { + if (pSoldier->stats.ubSkillTraits[ bCnt ] == uiSkillTraitNumber) + { + return( TRUE ); + } + else if ( pSoldier->stats.ubSkillTraits[ bCnt ] > 0 && pSoldier->stats.ubSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS ) + { + bNumMajorTraitsCounted++; + } + // if we exceeded the allowed number of major traits, ignore the rest of them + if ( bNumMajorTraitsCounted >= gSkillTraitValues.ubNumberOfMajorTraitsAllowed ) + { + break; + } + } + else + { + if (pSoldier->stats.ubSkillTraits[ bCnt ] == uiSkillTraitNumber) + { + return( TRUE ); + } + } + } + } + else + { + if (pSoldier->stats.ubSkillTraits[ 0 ] == uiSkillTraitNumber) + return( TRUE ); + if (pSoldier->stats.ubSkillTraits[ 1 ] == uiSkillTraitNumber) + return( TRUE ); + } + return( FALSE ); +} + +INT8 NUM_SKILL_TRAITS( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber ) +{ + if ( pSoldier == NULL ) + return( 0 ); + + INT8 bNumberOfTraits = 0; + INT8 bNumMajorTraitsCounted = 0; + + // check old/new traits + if (gGameOptions.fNewTraitSystem) + { + for ( INT8 bCnt = 0; bCnt < gSkillTraitValues.ubMaxNumberOfTraits; bCnt++ ) + { + if ( uiSkillTraitNumber > 0 && uiSkillTraitNumber <= NUM_MAJOR_TRAITS ) + { + if ( pSoldier->stats.ubSkillTraits[ bCnt ] == uiSkillTraitNumber ) + { + bNumberOfTraits++; + bNumMajorTraitsCounted++; + } + else if ( pSoldier->stats.ubSkillTraits[ bCnt ] > 0 && pSoldier->stats.ubSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS ) + { + bNumMajorTraitsCounted++; + } + // if we exceeded the allowed number of major traits, ignore the rest of them + if ( bNumMajorTraitsCounted >= gSkillTraitValues.ubNumberOfMajorTraitsAllowed ) + { + break; + } + } + else + { + if ( pSoldier->stats.ubSkillTraits[ bCnt ] == uiSkillTraitNumber ) + { + bNumberOfTraits++; + } + } + } + // cannot have more than one same minor trait + if( uiSkillTraitNumber > NUM_MAJOR_TRAITS ) + return ( min(1, bNumberOfTraits) ); + else + return ( min(2, bNumberOfTraits) ); + } + else + { + if (pSoldier->stats.ubSkillTraits[ 0 ] == uiSkillTraitNumber) + bNumberOfTraits++; + if (pSoldier->stats.ubSkillTraits[ 1 ] == uiSkillTraitNumber) + bNumberOfTraits++; + + // Electronics, Ambidextrous and Camouflaged can only be of one grade + if( uiSkillTraitNumber == ELECTRONICS_OT || + uiSkillTraitNumber == AMBIDEXT_OT || + uiSkillTraitNumber == CAMOUFLAGED_OT ) + return ( min(1, bNumberOfTraits) ); + else + return ( bNumberOfTraits ); + } +} + +UINT8 GetSquadleadersCountInVicinity( SOLDIERTYPE * pSoldier, BOOLEAN fWithHigherLevel, BOOLEAN fDontCheckDistance ) +{ + UINT8 cnt = 0; + UINT8 ubNumberSL = 0; + + // loop through all soldiers around + for ( cnt = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID ; cnt <= gTacticalStatus.Team[ pSoldier->bTeam ].bLastID ; cnt++ ) + { + // Get active conscious soldier + if (MercPtrs[ cnt ] != pSoldier && MercPtrs[ cnt ]->bActive && //MercPtrs[ cnt ]->aiData.bShock < 20 && + MercPtrs[ cnt ]->stats.bLife >= OKLIFE && HAS_SKILL_TRAIT( MercPtrs[ cnt ], SQUADLEADER_NT )) + { + // check if within distance + // if both have extended ear, the distance is bigger and they don't need to sea each other + // note that enemy always get the bonus if within distance, regardless of extended ears + if (((( HasExtendedEarOn( pSoldier ) && HasExtendedEarOn( MercPtrs[ cnt ] )) || ( pSoldier->bTeam == ENEMY_TEAM ) ) && (PythSpacesAway( pSoldier->sGridNo, MercPtrs[ cnt ]->sGridNo ) <= gSkillTraitValues.usSLRadiusExtendedEar) ) || + //((SoldierToVirtualSoldierLineOfSightTest( MercPtrs[ cnt ], pSoldier->sGridNo, pSoldier->pathing.bLevel, ANIM_STAND, TRUE, CALC_FROM_ALL_DIRS ) || + //SoldierToVirtualSoldierLineOfSightTest( pSoldier, MercPtrs[ cnt ]->sGridNo, MercPtrs[ cnt ]->pathing.bLevel, ANIM_STAND, TRUE, CALC_FROM_ALL_DIRS ) ) && + (PythSpacesAway( pSoldier->sGridNo, MercPtrs[ cnt ]->sGridNo ) <= gSkillTraitValues.usSLRadiusNormal) || + fDontCheckDistance ) + { + // If checking for higher level SL + // also count in already aquired level increses from other SLs + if (fWithHigherLevel) + { + if ( MercPtrs[ cnt ]->stats.bExpLevel > (pSoldier->stats.bExpLevel+(ubNumberSL*gSkillTraitValues.ubSLEffectiveLevelInRadius)) ) + ubNumberSL += min( (max(0,(MercPtrs[ cnt ]->stats.bExpLevel - (pSoldier->stats.bExpLevel+(ubNumberSL*gSkillTraitValues.ubSLEffectiveLevelInRadius))))), (NUM_SKILL_TRAITS( MercPtrs[ cnt ], SQUADLEADER_NT ))); + } + else + { + ubNumberSL += NUM_SKILL_TRAITS( MercPtrs[ cnt ], SQUADLEADER_NT ); + } + if (ubNumberSL >= gSkillTraitValues.ubSLMaxBonuses) + break; + } + } + } + + // special loop for militia - they can get a bonus from our mercs + if ( pSoldier->bTeam == MILITIA_TEAM && ubNumberSL < gSkillTraitValues.ubSLMaxBonuses ) + { + for ( cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID ; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID ; cnt++ ) + { + // Get active conscious soldier + if (MercPtrs[ cnt ] != pSoldier && MercPtrs[ cnt ]->bActive && //MercPtrs[ cnt ]->aiData.bShock < 20 && + MercPtrs[ cnt ]->stats.bLife >= OKLIFE && HAS_SKILL_TRAIT( MercPtrs[ cnt ], SQUADLEADER_NT )) + { + // check if within distance + if (((HasExtendedEarOn( MercPtrs[ cnt ] ) && (PythSpacesAway( pSoldier->sGridNo, MercPtrs[ cnt ]->sGridNo ) <= gSkillTraitValues.usSLRadiusExtendedEar) ) || + //((SoldierToVirtualSoldierLineOfSightTest( MercPtrs[ cnt ], pSoldier->sGridNo, pSoldier->pathing.bLevel, ANIM_STAND, TRUE, CALC_FROM_ALL_DIRS ) || + //SoldierToVirtualSoldierLineOfSightTest( pSoldier, MercPtrs[ cnt ]->sGridNo, MercPtrs[ cnt ]->pathing.bLevel, ANIM_STAND, TRUE, CALC_FROM_ALL_DIRS ) ) && + (PythSpacesAway( pSoldier->sGridNo, MercPtrs[ cnt ]->sGridNo ) <= gSkillTraitValues.usSLRadiusNormal)) || + fDontCheckDistance ) + { + // If checking for higher level SL + // also count in already aquired level increses from other SLs + if (fWithHigherLevel) + { + if ( MercPtrs[ cnt ]->stats.bExpLevel > (pSoldier->stats.bExpLevel+(ubNumberSL*gSkillTraitValues.ubSLEffectiveLevelInRadius)) ) + ubNumberSL += min( (max(0,(MercPtrs[ cnt ]->stats.bExpLevel - (pSoldier->stats.bExpLevel+(ubNumberSL*gSkillTraitValues.ubSLEffectiveLevelInRadius))))), (NUM_SKILL_TRAITS( MercPtrs[ cnt ], SQUADLEADER_NT ))); + } + else + { + ubNumberSL += NUM_SKILL_TRAITS( MercPtrs[ cnt ], SQUADLEADER_NT ); + } + if (ubNumberSL >= gSkillTraitValues.ubSLMaxBonuses) + break; + } + } + } + } + + // 3 bonuses are a max by default + return( min( gSkillTraitValues.ubSLMaxBonuses, ubNumberSL)); +} + +UINT16 NumberOfDamagedStats( SOLDIERTYPE * pSoldier ) +{ + UINT16 ubTotalStatsDamaged = 0; + for (UINT8 cnt = 0; cnt < NUM_DAMAGABLE_STATS; cnt++) + { + if (pSoldier->ubCriticalStatDamage[cnt] > 0 ) + ubTotalStatsDamaged += pSoldier->ubCriticalStatDamage[cnt]; + } + return( ubTotalStatsDamaged ); +} + +UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundredths ) +{ + UINT16 usStatIncreasement; + //BOOLEAN fAnyStatToBeRepaired = FALSE; + UINT8 cnt, ubAmountRegained; + STR16 sStat = L""; + + UINT8 bStatsReturned = 0; + + // First determine how much we can return + ubAmountRegained = (usAmountRegainedHundredths / 100); //transfer to whole numbers + usAmountRegainedHundredths %= 100; // keep rest + if( usAmountRegainedHundredths > 0 ) // if some reamins, solve it as a chance + { + if (Chance(usAmountRegainedHundredths)) // if rolled true, add one point + { + ubAmountRegained += 1; + usAmountRegainedHundredths = 0; + } + else // otherwise ignore the rest + { + usAmountRegainedHundredths = 0; + } + } + // return zero if we are not able to heal anything + if (ubAmountRegained <= 0) + return( 0 ); + + // Second, run through all damagable stats + for (cnt = 0; cnt < NUM_DAMAGABLE_STATS; cnt++) + { + // if we have a damaged stat here + if (pSoldier->ubCriticalStatDamage[cnt] > 0 ) + { + if (ubAmountRegained >= pSoldier->ubCriticalStatDamage[cnt]) + { + // if the amount we can return is bigger than what we need, keep the rest, for other stats + usStatIncreasement = pSoldier->ubCriticalStatDamage[cnt]; + ubAmountRegained = max(0,(ubAmountRegained - usStatIncreasement)); + pSoldier->ubCriticalStatDamage[cnt] = 0; + } + else + { + // if not having full amount, heal what we can + usStatIncreasement = ubAmountRegained; + ubAmountRegained = 0; + pSoldier->ubCriticalStatDamage[cnt] = max( 0, (pSoldier->ubCriticalStatDamage[cnt] - usStatIncreasement)); + } + // so we can start regaining the stats + if ( usStatIncreasement > 0 ) + { + bStatsReturned += usStatIncreasement; // keep value for feedback + + switch(cnt) // look on the stat + { + // actually we only test Health, Dexterity, Agility, Strength and Wisdom now, + // as there are no ways to lost other stats in the current code + case DAMAGED_STAT_HEALTH: + sStat = sStatGainStrings[0]; // set string + pSoldier->stats.bLifeMax += usStatIncreasement; + pSoldier->stats.bLife += usStatIncreasement; + pSoldier->iHealableInjury -= (usStatIncreasement * 100); // don't forget the healable injury + if (pSoldier->iHealableInjury < 0) + pSoldier->iHealableInjury = 0; + if (pSoldier->stats.bLifeMax >= 100 || pSoldier->stats.bLife >= 100 ) // repair if going too far + { + pSoldier->stats.bLifeMax = 100; + pSoldier->stats.bLife = 100; + pSoldier->iHealableInjury = 0; + pSoldier->ubCriticalStatDamage[cnt] = 0; + } + gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax; // update profile + break; + case DAMAGED_STAT_DEXTERITY: + sStat = sStatGainStrings[2]; // set string + pSoldier->stats.bDexterity += usStatIncreasement; + if (pSoldier->stats.bDexterity >= 100 ) // repair if going too far + { + pSoldier->stats.bDexterity = 100; + pSoldier->ubCriticalStatDamage[cnt] = 0; + } + gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity; // update profile + break; + case DAMAGED_STAT_AGILITY: + sStat = sStatGainStrings[1]; // set string + pSoldier->stats.bAgility += usStatIncreasement; + if (pSoldier->stats.bAgility >= 100 ) // repair if going too far + { + pSoldier->stats.bAgility = 100; + pSoldier->ubCriticalStatDamage[cnt] = 0; + } + gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility; // update profile + break; + case DAMAGED_STAT_STRENGTH: + sStat = sStatGainStrings[9]; // set string + pSoldier->stats.bStrength += usStatIncreasement; + if (pSoldier->stats.bStrength >= 100 ) // repair if going too far + { + pSoldier->stats.bStrength = 100; + pSoldier->ubCriticalStatDamage[cnt] = 0; + } + gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength; // update profile + break; + case DAMAGED_STAT_WISDOM: + sStat = sStatGainStrings[3]; // set string + pSoldier->stats.bWisdom += usStatIncreasement; + if (pSoldier->stats.bWisdom >= 100 ) // repair if going too far + { + pSoldier->stats.bWisdom = 100; + pSoldier->ubCriticalStatDamage[cnt] = 0; + } + gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom; // update profile + break; + } + // Throw a message if healed anything + if ( gSkillTraitValues.fDORepStShouldThrowMessage ) + { + if ( usStatIncreasement == 1 ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_REGAINED_ONE_POINTS_OF_STAT], pSoldier->name, sStat ); + else + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_REGAINED_X_POINTS_OF_STATS], pSoldier->name, usStatIncreasement, sStat ); + } + } + //if( pSoldier->ubCriticalStatDamage[cnt] > 0 ) + // fAnyStatToBeRepaired = TRUE; + + } + } + + // Done, return what we healed + return( bStatsReturned ); +} + \ No newline at end of file diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index dec08a35..3427fa53 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -104,8 +104,11 @@ extern UINT16 CivLastNames[MAXCIVLASTNAMES][10]; #define SOLDIER_TRAIT_MARTIALARTS 0x0800 #define SOLDIER_TRAIT_KNIFING 0x1000 */ -#define HAS_SKILL_TRAIT( s, t ) (s->stats.ubSkillTrait1 == t || s->stats.ubSkillTrait2 == t) -#define NUM_SKILL_TRAITS( s, t ) ( (s->stats.ubSkillTrait1 == t) ? ( (s->stats.ubSkillTrait2 == t) ? 2 : 1 ) : ( (s->stats.ubSkillTrait2 == t) ? 1 : 0 ) ) +// SANDRO was here, messed this.. +//#define HAS_SKILL_TRAIT( s, t ) (s->stats.ubSkillTrait1 == t || s->stats.ubSkillTrait2 == t) +//#define NUM_SKILL_TRAITS( s, t ) ( (s->stats.ubSkillTrait1 == t) ? ( (s->stats.ubSkillTrait2 == t) ? 2 : 1 ) : ( (s->stats.ubSkillTrait2 == t) ? 1 : 0 ) ) +BOOLEAN HAS_SKILL_TRAIT( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber ); +INT8 NUM_SKILL_TRAITS( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber ); #define SOLDIER_QUOTE_SAID_IN_SHIT 0x0001 #define SOLDIER_QUOTE_SAID_LOW_BREATH 0x0002 @@ -245,6 +248,22 @@ enum MERC_TYPE__VEHICLE, }; +// SANDRO - added for healing damaged stats +enum +{ + DAMAGED_STAT_HEALTH, + DAMAGED_STAT_DEXTERITY, + DAMAGED_STAT_AGILITY, + DAMAGED_STAT_STRENGTH, + DAMAGED_STAT_WISDOM, + DAMAGED_STAT_LEADERSHIP, + DAMAGED_STAT_MARKSMANSHIP, + DAMAGED_STAT_MECHANICAL, + DAMAGED_STAT_EXPLOSIVES, + DAMAGED_STAT_MEDICAL, + NUM_DAMAGABLE_STATS, +}; + // vehicle/human path structure struct path { @@ -602,21 +621,22 @@ class STRUCT_Statistics//last edited at version 102 { public: void ConvertFrom_101_To_102(const OLDSOLDIERTYPE_101& src); + INT8 bExpLevel; // general experience level INT8 bLife; // current life (hit points or health) INT8 bLifeMax; // maximum life for this merc - INT8 bExpLevel; // general experience level - INT8 bAgility; // agility (speed) value INT8 bStrength; - INT8 bMechanical; - INT8 bMarksmanship; - INT8 bExplosive; - UINT8 ubSkillTrait1; - UINT8 ubSkillTrait2; + INT8 bAgility; // agility (speed) value INT8 bDexterity; // dexterity (hand coord) value INT8 bWisdom; + INT8 bLeadership; + INT8 bMarksmanship; + INT8 bMechanical; + INT8 bExplosive; INT8 bMedical; INT8 bScientific; - INT8 bLeadership; + UINT8 ubSkillTraits[30]; + //UINT8 ubSkillTrait2; + //UINT8 ubSkillTrait3; // added by SANDRO }; class STRUCT_Pathing//last edited at version 102 @@ -664,6 +684,7 @@ public: // Use this instead of the old method of calling memset. // Note that the constructor does this automatically. void initialize(); + bool exists(); // Note: Place all non-POD items at the end (after endOfPOD) // The format of this structure affects what is written into and read from various @@ -708,6 +729,16 @@ public: UINT8 ubAttackingHand; INT16 sWeightCarriedAtTurnStart; + ///////////////////////////////////////////////////////////////////////////////// + // SANDRO - added following + // values for surgery feature + INT32 iHealableInjury; + BOOLEAN fDoingSurgery; + // value for unregainable breath feature (for Martial Arts) + signed long lUnregainableBreath; + // this stores possible stats lost due to critical hits + UINT8 ubCriticalStatDamage[ NUM_DAMAGABLE_STATS ]; + ///////////////////////////////////////////////////////////////////////////////// //NEW MOVEMENT INFORMATION for Strategic Movement UINT8 ubGroupID; //the movement group the merc is currently part of. @@ -720,8 +751,12 @@ public: // WORLD POSITION STUFF FLOAT dXPos; FLOAT dYPos; - FLOAT dOldXPos; - FLOAT dOldYPos; + // HEADROCK HAM 4: These two vars are appropriated for the new Shooting Mechanism. + // They represent the soldier's position at the start of his turn. + //FLOAT dOldXPos; + //FLOAT dOldYPos; + INT16 sOldXPos; + INT16 sOldYPos; INT32 sInitialGridNo; INT32 sGridNo; UINT8 ubDirection; @@ -774,6 +809,13 @@ public: INT8 bTargetLevel; INT8 bTargetCubeLevel; INT32 sLastTarget; + // HEADROCK HAM 4: the muzzle offset of the shooter's previous bullet. (NCTH) + FLOAT dPrevMuzzleOffsetX; + FLOAT dPrevMuzzleOffsetY; + // HEADROCK HAM 4: Two more values. These record the shooter's previous Counter Force applied on the gun. + FLOAT dPrevCounterForceX; + FLOAT dPrevCounterForceY; + INT8 bTilesMoved; FLOAT dNextBleed; @@ -1099,6 +1141,7 @@ public: // Debugging data - not saved INT32 sPlotSrcGrid; + //std::vector CTH; public: @@ -1213,6 +1256,12 @@ public: void BeginSoldierClimbDownRoof( void ); void BeginSoldierClimbFence( void ); void BeginTyingToFall( void ); + + //legion by Jazz + void BeginSoldierFence( void ); + void BeginSoldierFenceUp( void ); + void BeginSoldierClimbWindow( void ); + void HandleAnimationProfile( UINT16 usAnimState, BOOLEAN fRemove ); void HandleSoldierTakeDamageFeedback( void ); void ChangeToFlybackAnimation( UINT8 flyBackDirection ); @@ -1357,6 +1406,10 @@ void CrowsFlyAway( UINT8 ubTeam ); void DebugValidateSoldierData( ); void HandlePlayerTogglingLightEffects( BOOLEAN fToggleValue ); +// added by SANDRO +UINT8 GetSquadleadersCountInVicinity( SOLDIERTYPE * pSoldier, BOOLEAN fWithHigherLevel, BOOLEAN fDontCheckDistance ); +UINT16 NumberOfDamagedStats( SOLDIERTYPE * pSoldier ); +UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundredths ); //typedef struct class OLDSOLDIERTYPE_101 @@ -1477,8 +1530,10 @@ public: // WORLD POSITION STUFF FLOAT dXPos; FLOAT dYPos; - FLOAT dOldXPos; - FLOAT dOldYPos; + //FLOAT dOldXPos; // HEADROCK HAM 4: These values have been reappropriated. + //FLOAT dOldYPos; // not sure what's going to happen with this though. + INT16 sOldXPos; + INT16 sOldYPos; INT32 sInitialGridNo; INT32 sGridNo; UINT8 ubDirection; @@ -1517,6 +1572,7 @@ public: UINT8 ubSkillTrait1; UINT8 ubSkillTrait2; + UINT8 ubSkillTrait3; // added by SANDRO UINT32 uiAIDelay; INT8 bDexterity; // dexterity (hand coord) value @@ -1686,6 +1742,7 @@ public: INT8 bNextTargetLevel; INT8 bOrders; INT8 bAttitude; + INT8 bCharacterTrait; // Added by SANDRO INT8 bUnderFire; INT8 bShock; INT8 bUnderEscort; @@ -2054,5 +2111,3 @@ public: #endif - - diff --git a/Tactical/Soldier Create.cpp b/Tactical/Soldier Create.cpp index 614fa472..ead689cc 100644 --- a/Tactical/Soldier Create.cpp +++ b/Tactical/Soldier Create.cpp @@ -45,6 +45,7 @@ #include "ai.h" #include "Strategic Mines.h" #include "math.h" + #include "Game Clock.h" // added this one - SANDRO #endif #include "connect.h" @@ -67,6 +68,7 @@ #define MAX_PALACE_DISTANCE 20 +INT8 bNumSquadleadersInArmy = 0; // added by SANDRO OLD_SOLDIERCREATE_STRUCT_101::OLD_SOLDIERCREATE_STRUCT_101() { initialize(); @@ -545,7 +547,7 @@ void DecideToAssignSniperOrders( SOLDIERCREATE_STRUCT * pp ) if ( pp->bOrders == STATIONARY || pp->bOrders == ONGUARD ) { // 30% of anybody w/a scope and decent range being a sniper, 80% chance of a guy w/a sniper rifle being a sniper - if ( (GunRange(&pp->Inv[HANDPOS]) >= 40 && IsScoped(&pp->Inv[HANDPOS]) && Random(100) < 30) || ( Weapon[pp->Inv[HANDPOS].usItem].ubWeaponType == GUN_SN_RIFLE && IsScoped(&pp->Inv[HANDPOS]) && Random(100) < 80 ) ) + if ( (GunRange(&pp->Inv[HANDPOS], NULL) >= 40 && IsScoped(&pp->Inv[HANDPOS]) && Random(100) < 30) || ( Weapon[pp->Inv[HANDPOS].usItem].ubWeaponType == GUN_SN_RIFLE && IsScoped(&pp->Inv[HANDPOS]) && Random(100) < 80 ) ) // SANDRO - added argument forGunRange { pp->bOrders = SNIPER; @@ -1173,6 +1175,9 @@ BOOLEAN TacticalCopySoldierFromProfile( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STR pSoldier->stats.bExplosive = pProfile->bExplosive; pSoldier->stats.bScientific = pProfile->bScientific; + // added by SANDRO - insta-healable injury zero on soldier creation + pSoldier->iHealableInjury = 0; + pSoldier->bVocalVolume = MIDVOLUME; pSoldier->uiAnimSubFlags = pProfile->uiBodyTypeSubFlags; pSoldier->ubBodyType = pProfile->ubBodyType; @@ -1181,8 +1186,13 @@ BOOLEAN TacticalCopySoldierFromProfile( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STR // pSoldier->bAssignment=ON_DUTY; pSoldier->bOldAssignment = NO_ASSIGNMENT; - pSoldier->stats.ubSkillTrait1 = pProfile->bSkillTrait; - pSoldier->stats.ubSkillTrait2 = pProfile->bSkillTrait2; + for ( INT8 bCnt = 0; bCnt < 30; bCnt++ ) + { + pSoldier->stats.ubSkillTraits[ bCnt ] = pProfile->bSkillTraits[ bCnt ]; + } + //pSoldier->stats.ubSkillTrait2 = pProfile->bSkillTrait2; + //if ( gGameOptions.fNewTraitSystem ) + // pSoldier->stats.ubSkillTrait3 = pProfile->bSkillTrait3; // added by SANDRO - 3rd skill trait pSoldier->aiData.bOrders = pCreateStruct->bOrders; pSoldier->aiData.bAttitude = pCreateStruct->bAttitude; @@ -1190,25 +1200,34 @@ BOOLEAN TacticalCopySoldierFromProfile( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STR pSoldier->aiData.bPatrolCnt = pCreateStruct->bPatrolCnt; memcpy( pSoldier->aiData.sPatrolGrid, pCreateStruct->sPatrolGrid, sizeof( INT32 ) * MAXPATROLGRIDS ); - if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED ) ) + // SANDRO - Well, it is nonsense to have 4 traits for this, one is enough, as we can now repaint the camo type by another one + if ( !gGameOptions.fNewTraitSystem ) { - // set camouflaged to 100 automatically - pSoldier->bCamo = 100; - } - if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN ) ) - { - // set camouflaged to 100 automatically - pSoldier->urbanCamo = 100; - } - if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT ) ) - { - // set camouflaged to 100 automatically - pSoldier->desertCamo = 100; - } - if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_SNOW ) ) - { - // set camouflaged to 100 automatically - pSoldier->snowCamo = 100; + if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_OT ) ) + { + // set camouflaged to 100 automatically + pSoldier->bCamo = 100; + } + //if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED ) ) + //{ + // // set camouflaged to 100 automatically + // pSoldier->bCamo = 100; + //} + //if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_URBAN ) ) + //{ + // // set camouflaged to 100 automatically + // pSoldier->urbanCamo = 100; + //} + //if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_DESERT ) ) + //{ + // // set camouflaged to 100 automatically + // pSoldier->desertCamo = 100; + //} + //if ( HAS_SKILL_TRAIT( pSoldier, CAMOUFLAGED_SNOW ) ) + //{ + // // set camouflaged to 100 automatically + // pSoldier->snowCamo = 100; + //} } return( TRUE ); } @@ -1493,6 +1512,8 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT // Randomize attributes pSoldier->stats.bLife = pCreateStruct->bLife; pSoldier->stats.bLifeMax = pCreateStruct->bLifeMax; + // added by SANDRO - insta-healable injury zero on soldier creation + pSoldier->iHealableInjury = 0; pSoldier->stats.bAgility = pCreateStruct->bAgility; pSoldier->stats.bDexterity = pCreateStruct->bDexterity; pSoldier->stats.bExpLevel = pCreateStruct->bExpLevel; @@ -1525,98 +1546,138 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT sprintf( pSoldier->SkinPal, pCreateStruct->SkinPal ); } - //KM: March 25, 1999 - //Assign nightops traits to enemies/militia - if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ) + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Added by SANDRO - the enemy/militia has a decent chance to have some traits + if ( gGameExternalOptions.fAssignTraitsToEnemy && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) ) + AssignTraitsToSoldier( pSoldier, pCreateStruct ); + if ( gGameExternalOptions.fAssignTraitsToMilitia && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) ) + AssignTraitsToSoldier( pSoldier, pCreateStruct ); + // SANDRO - If neither of these two options are activated, use the original code + // however, "no traits" means no traits at all, so commented out + /*if ( !(gGameExternalOptions.fAssignTraitsToEnemy) && !(gGameExternalOptions.fAssignTraitsToMilitia) ) { - INT32 iChance; - UINT8 ubProgress; - - ubProgress = HighestPlayerProgressPercentage(); - - if ( ubProgress < 60 ) + //KM: March 25, 1999 + //Assign nightops traits to enemies/militia + if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ) { - // ramp chance from 40 to 80% over the course of 60% progress - // 60 * 2/3 = 40, and 40+40 = 80 - iChance = 40 + (ubProgress * 2) / 3; - } - else - { - iChance = 80; - } + INT32 iChance; + UINT8 ubProgress; - if ( Chance( iChance ) ) - { - pSoldier->stats.ubSkillTrait1 = NIGHTOPS; - if ( ubProgress >= 40 && Chance( 30 ) ) + ubProgress = HighestPlayerProgressPercentage(); + + if ( ubProgress < 60 ) { - pSoldier->stats.ubSkillTrait2 = NIGHTOPS; + // ramp chance from 40 to 80% over the course of 60% progress + // 60 * 2/3 = 40, and 40+40 = 80 + iChance = 40 + (ubProgress * 2) / 3; + } + else + { + iChance = 80; + } + + if ( Chance( iChance ) ) + { + if (gGameOptions.fNewTraitSystem) // SANDRO - new/old traits + { + pSoldier->stats.ubSkillTrait1 = NIGHT_OPS_NT; + } + else + { + pSoldier->stats.ubSkillTrait1 = NIGHTOPS_OT; + if ( ubProgress >= 40 && Chance( 30 ) ) + { + pSoldier->stats.ubSkillTrait2 = NIGHTOPS_OT; + } + } } } - } - else if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY || pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA ) - { - INT32 iChance; - UINT8 ubProgress; - - ubProgress = HighestPlayerProgressPercentage(); - - if ( ubProgress < 60 ) + else if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY || pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA ) { - // ramp chance from 0 to 40% over the course of 60% progress - // 60 * 2/3 = 40 - iChance = (ubProgress * 2) / 3; - } - else - { - iChance = 40; - } + INT32 iChance; + UINT8 ubProgress; - if ( Chance( iChance ) ) - { - pSoldier->stats.ubSkillTrait1 = NIGHTOPS; - if ( ubProgress >= 50 && Chance( 20 ) ) + ubProgress = HighestPlayerProgressPercentage(); + + if ( ubProgress < 60 ) { - pSoldier->stats.ubSkillTrait2 = NIGHTOPS; + // ramp chance from 0 to 40% over the course of 60% progress + // 60 * 2/3 = 40 + iChance = (ubProgress * 2) / 3; + } + else + { + iChance = 40; + } + + if ( Chance( iChance ) ) + { + if (gGameOptions.fNewTraitSystem) // SANDRO - new/old traits + { + pSoldier->stats.ubSkillTrait1 = NIGHT_OPS_NT; + } + else + { + pSoldier->stats.ubSkillTrait1 = NIGHTOPS_OT; + if ( ubProgress >= 50 && Chance( 20 ) ) + { + pSoldier->stats.ubSkillTrait2 = NIGHTOPS_OT; + } + } } } - } - // Lesh: give to enemies AMBIDEXTEROUS skill and a second pistol - if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ) - { - if ( Chance( 20 ) ) + // Lesh: give to enemies AMBIDEXTEROUS skill and a second pistol + if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + if ( Chance( 20 ) ) + { + if (gGameOptions.fNewTraitSystem) // new/old traits - SANDRO + pSoldier->stats.ubSkillTrait1 = AMBIDEXT_OT; + else + pSoldier->stats.ubSkillTrait1 = AMBIDEXTROUS_NT; + + if ( Chance( 10 ) ) + { + if (gGameOptions.fNewTraitSystem) // new/old traits - SANDRO + pSoldier->stats.ubSkillTrait2 = AMBIDEXT_OT; + else + pSoldier->stats.ubSkillTrait2 = AMBIDEXTROUS_NT; + } + if ( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) + { + (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); + } + } + } + else if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY || pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA ) { - pSoldier->stats.ubSkillTrait1 = AMBIDEXT; if ( Chance( 10 ) ) { - pSoldier->stats.ubSkillTrait2 = AMBIDEXT; - } - if ( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) - { - (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); + if (gGameOptions.fNewTraitSystem) // new/old traits - SANDRO + pSoldier->stats.ubSkillTrait1 = AMBIDEXT_OT; + else + pSoldier->stats.ubSkillTrait1 = AMBIDEXTROUS_NT; + + if ( Chance( 5 ) ) + { + if (gGameOptions.fNewTraitSystem) // new/old traits - SANDRO + pSoldier->stats.ubSkillTrait2 = AMBIDEXT_OT; + else + pSoldier->stats.ubSkillTrait2 = AMBIDEXTROUS_NT; + } + if ( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) + { + pCreateStruct->Inv[SECONDHANDPOS] = pCreateStruct->Inv[HANDPOS]; + } } } - } - else if( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY || pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA ) - { - if ( Chance( 10 ) ) - { - pSoldier->stats.ubSkillTrait1 = AMBIDEXT; - if ( Chance( 5 ) ) - { - pSoldier->stats.ubSkillTrait2 = AMBIDEXT; - } - if ( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) - { - pCreateStruct->Inv[SECONDHANDPOS] = pCreateStruct->Inv[HANDPOS]; - } - } - } + }*/ + ////////////////////////////////////////////////////////////////////////////////////////////////// //KM: November 10, 1997 //Adding patrol points @@ -1879,8 +1940,8 @@ INT8 CalcDifficultyModifier( UINT8 ubSoldierClass ) else { bDiffModifier += (INT8)(DIFF_FACTOR_GAME_DIFFICULTY * 1.5); - break; } + break; } @@ -1895,7 +1956,7 @@ INT8 CalcDifficultyModifier( UINT8 ubSoldierClass ) } // drop it down a bit if we still don't have any mine income - if ( PredictIncomeFromPlayerMines() == 0 ) + if ( PredictIncomeFromPlayerMines(TRUE) == 0 ) { // -5 bDiffModifier += DIFF_MODIFIER_NO_INCOME; @@ -2364,6 +2425,8 @@ void CreateDetailedPlacementGivenStaticDetailedPlacementAndBasicPlacementInfo( if( spp->Inv[ i ].fFlags & OBJECT_NO_OVERWRITE ) { pp->Inv[ i ] = spp->Inv[ i ]; + //WarmSteel - if someone in the map editor placed a wrong attachment on this gun, fix it. + RemoveProhibitedAttachments(NULL, &pp->Inv[i], pp->Inv[i].usItem); //return; } } @@ -2447,6 +2510,9 @@ void UpdateSoldierWithStaticDetailedInformation( SOLDIERTYPE *s, SOLDIERCREATE_S if( s->stats.bLife > s->stats.bLifeMax ) s->stats.bLife = s->stats.bLifeMax; + // added by SANDRO - insta-healable injury zero on soldier creation + s->iHealableInjury = 0; + s->ubScheduleID = spp->ubScheduleID; //Copy over the current inventory list. @@ -2514,6 +2580,8 @@ void ModifySoldierAttributesWithNewRelativeLevel( SOLDIERTYPE *s, INT8 bRelative //Stat range is currently 40-99, slightly bell-curved around the bExpLevel s->stats.bLifeMax = (INT8)(bBaseAttribute + Random( 9 ) + Random( 8 )); s->stats.bLife = s->stats.bLifeMax; + // added by SANDRO - insta-healable injury zero on soldier creation + s->iHealableInjury = 0; s->stats.bAgility = (INT8)(bBaseAttribute + Random( 9 ) + Random( 8 )); s->stats.bDexterity = (INT8)(bBaseAttribute + Random( 9 ) + Random( 8 )); s->stats.bMarksmanship = (INT8)(bBaseAttribute + Random( 9 ) + Random( 8 )); @@ -2987,7 +3055,7 @@ void CopyProfileItems( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCreateStruc { for ( cnt2 = INV_START_POS; cnt2 < NUM_INV_SLOTS; cnt2++ ) { - if ( pSoldier->inv[ cnt2 ].exists() == true && ValidAttachment( gTempObject.usItem, pSoldier->inv[ cnt2 ].usItem ) ) + if ( pSoldier->inv[ cnt2 ].exists() == true && ValidAttachment( gTempObject.usItem, &(pSoldier->inv[ cnt2 ]) ) ) { if(pSoldier->inv[ cnt2 ].AttachObject( NULL, &gTempObject, FALSE )) { @@ -3035,18 +3103,19 @@ void CopyProfileItems( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCreateStruc // to provide one which doesn't work and would confuse everything. switch( pCreateStruct->ubProfile ) { + // WANNE: Changed KEY_32 to KEY_8 because we only have 8 keys defined in Items.xml case BREWSTER: - if ( pProfile->inv[ cnt ] >= KEY_1 && pProfile->inv[ cnt ] <= KEY_32){ + if ( pProfile->inv[ cnt ] >= KEY_1 && pProfile->inv[ cnt ] <= KEY_8){ fRet = CreateKeyObject( &gTempObject , pProfile->bInvNumber[ cnt ], 19 ); } break; case SKIPPER: - if ( pProfile->inv[ cnt ] >= KEY_1 && pProfile->inv[ cnt ] <= KEY_32){ + if ( pProfile->inv[ cnt ] >= KEY_1 && pProfile->inv[ cnt ] <= KEY_8){ fRet = CreateKeyObject( &gTempObject, pProfile->bInvNumber[ cnt ], 11 ); } break; case DOREEN: - if ( pProfile->inv[ cnt ] >= KEY_1 && pProfile->inv[ cnt ] <= KEY_32){ + if ( pProfile->inv[ cnt ] >= KEY_1 && pProfile->inv[ cnt ] <= KEY_8){ fRet = CreateKeyObject( &gTempObject, pProfile->bInvNumber[ cnt ], 32 ); } } @@ -3339,3 +3408,1078 @@ BOOLEAN TranslateArrayFields(void* out, const void* inp, int len, int cmd)//dnl } return(TRUE); } + +// SANDRO - function for resetting Squadleader traits number +void ResetNumSquadleadersInArmyGroup( void ) +{ + bNumSquadleadersInArmy = 0; +} + +// SANDRO - Added a function to add traits to soldiers +BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCreateStruct ) +{ + INT32 iChance; + UINT8 ubProgress, ubSolClass; + BOOLEAN ATraitAssigned = FALSE; + BOOLEAN BTraitAssigned = FALSE; + BOOLEAN CTraitAssigned = FALSE; + + ubProgress = HighestPlayerProgressPercentage(); + ubSolClass = pSoldier->ubSoldierClass; + + // First determine who will be the squadleader for this group (administrators do not get a squadleader + if ( gGameOptions.fNewTraitSystem && bNumSquadleadersInArmy < ((ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ARMY) ? gGameOptions.ubDifficultyLevel : 2 ) && + ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA || + ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) ) + { + // set the first in command + if ( bNumSquadleadersInArmy == 0 ) + { + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + iChance = 100; + } + else + { + iChance = 50; + } + if( gGameExternalOptions.bAssignedTraitsRarity < 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + if( Chance( iChance ) ) + { + pSoldier->stats.ubSkillTraits[0] = SQUADLEADER_NT; + // raise level and leadership for this guy + pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); + pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); + ATraitAssigned = TRUE; + + bNumSquadleadersInArmy++; + } + } + + // second level can be given by a chance depending on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + // 60-100% + iChance = 60 + ubProgress * 2/5; + } + else + { + // 30-70% + iChance = 30 + ubProgress * 2/5; + } + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + if( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = SQUADLEADER_NT; + // raise level and leadership for this guy + pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); + pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); + ATraitAssigned = TRUE; + + bNumSquadleadersInArmy++; + } + else + { + pSoldier->stats.ubSkillTraits[1] = SQUADLEADER_NT; + // raise level and leadership for this guy + pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); + pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); + BTraitAssigned = TRUE; + + bNumSquadleadersInArmy++; + } + } + + } + + // Now look what we have in hands and assign traits according to it + + // ASSAULT RIFLE OR LMG - CHANCE FOR AUTO WEAPONS TRAIT + if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + ( Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_AS_RIFLE || + Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_LMG ) ) + { + // setup the chances + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + // 50-100% + iChance = 50 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + { + // 30-80% + iChance = 30 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + { + // 15-65% + iChance = 15 + ubProgress/2; + } + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // Now assign the trait + if( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[0] = AUTO_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[0] = AUTO_WEAPS_OT; + + ATraitAssigned = TRUE; + + // Half chance to assign expert level of the trait + if ( Chance( iChance/2 ) && !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPS_OT; + + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPS_OT; + + BTraitAssigned = TRUE; + } + } + } + // SNIPER RIFLE - CHANCE FOR SNIPER TRAIT + else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_SN_RIFLE ) + { + // setup the chances + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + // 45-95% + iChance = 45 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + { + // 30-80% + iChance = 30 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + { + // 15-65% + iChance = 15 + ubProgress/2; + } + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // Now assign the trait + if( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[0] = SNIPER_NT; + else + pSoldier->stats.ubSkillTraits[0] = PROF_SNIPER_OT; + + ATraitAssigned = TRUE; + + // Lower chance to assign expert level of the trait + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = SNIPER_NT; + else + pSoldier->stats.ubSkillTraits[1] = PROF_SNIPER_OT; + + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = SNIPER_NT; + else + pSoldier->stats.ubSkillTraits[1] = PROF_SNIPER_OT; + + BTraitAssigned = TRUE; + } + } + } + // RIFLE OR SHOTGUN - CHANCE FOR RANGER TRAIT (new traits only) + else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + ( Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_RIFLE || + Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_SHOTGUN ) ) + { + // setup the chances + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + // 40-90% + iChance = 40 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + { + // 25-75% + iChance = 25 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + { + // 10-60% + iChance = 10 + ubProgress/2; + } + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // Now assign the trait + if( gGameOptions.fNewTraitSystem ) // for STOMP traits only + { + if( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = RANGER_NT; + ATraitAssigned = TRUE; + + // Lower chance to assign expert level of the trait + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = RANGER_NT; + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = RANGER_NT; + BTraitAssigned = TRUE; + } + } + } + else + { + // with old traits, we have some chance to gain sniper trait with rifle in hands + if( Chance( iChance*2/3 ) && (Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_RIFLE) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = PROF_SNIPER_OT; + ATraitAssigned = TRUE; + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = PROF_SNIPER_OT; + BTraitAssigned = TRUE; + } + } + } + } + // SMG - CHANCE FOR AUTO WEAPONS TRAIT AND CHANCE FOR A SECOND WEAPON (+GUNSLINGER/AMBIDEXTROUS TRAIT) + else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_SMG ) + { + // setup the chances + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + // 40-90% + iChance = 40 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + { + // 25-75% + iChance = 25 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + { + // 10-60% + iChance = 10 + ubProgress/2; + } + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // Now assign the trait - Auto weapons are superior here + if( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[0] = AUTO_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[0] = AUTO_WEAPS_OT; + + ATraitAssigned = TRUE; + + // Half chance to assign expert level of the trait + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPS_OT; + + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPS_OT; + + BTraitAssigned = TRUE; + } + } + // Chance to gain second weapon + if ( Chance( iChance/4 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) // 1/4 of chance + { + (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); + + // if traits not assigned, small chance to assign Gunslinger/Ambidextrous trait + if (!ATraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + { + if ( pSoldier->stats.ubSkillTraits[1] != AMBIDEXTROUS_NT && pSoldier->stats.ubSkillTraits[2] != AMBIDEXTROUS_NT ) // paranoya check + pSoldier->stats.ubSkillTraits[0] = AMBIDEXTROUS_NT; + } + else + { + if ( pSoldier->stats.ubSkillTraits[1] != AMBIDEXT_OT ) // paranoya check + pSoldier->stats.ubSkillTraits[0] = AMBIDEXT_OT; + } + ATraitAssigned = TRUE; + } + else if (!BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + { + if ( pSoldier->stats.ubSkillTraits[1] != AMBIDEXTROUS_NT && pSoldier->stats.ubSkillTraits[2] != AMBIDEXTROUS_NT ) // paranoya check + pSoldier->stats.ubSkillTraits[0] = AMBIDEXTROUS_NT; + } + else + { + if ( pSoldier->stats.ubSkillTraits[0] != AMBIDEXT_OT ) // paranoya check + pSoldier->stats.ubSkillTraits[1] = AMBIDEXT_OT; + } + BTraitAssigned = TRUE; + } + else if (gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) + { + if ( pSoldier->stats.ubSkillTraits[0] != AMBIDEXTROUS_NT && pSoldier->stats.ubSkillTraits[1] != AMBIDEXTROUS_NT ) // paranoya check + pSoldier->stats.ubSkillTraits[2] = AMBIDEXTROUS_NT; + + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + // PISTOL OR MACHINE PISTOL - CHANCE FOR GUNSLINGER/AMBIDEXTROUS TRAIT AND SECOND WEAPON + else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && + ( Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_PISTOL || + Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_M_PISTOL ) ) + { + // setup the chances + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + // 40-90% + iChance = 40 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + { + // 25-75% + iChance = 25 + ubProgress/2; + } + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + { + // 10-60% + iChance = 10 + ubProgress/2; + } + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // Now assign the trait + if( Chance( iChance ) ) + { + if ( gGameOptions.fNewTraitSystem ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = GUNSLINGER_NT; + ATraitAssigned = TRUE; + + // Lower chance to assign expert level of the trait + if ( Chance( iChance/2 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = GUNSLINGER_NT; + BTraitAssigned = TRUE; + + // elites can have third skill trait + if ( Chance( iChance/3 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded && + ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) ) + { + pSoldier->stats.ubSkillTraits[2] = AMBIDEXTROUS_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + + } + // Chance to gain second weapon and ambidextrous trait + else if ( Chance( iChance/2 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded && !BTraitAssigned ) // 1/2 of chance + { + (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); + + pSoldier->stats.ubSkillTraits[1] = AMBIDEXTROUS_NT; + + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = GUNSLINGER_NT; + BTraitAssigned = TRUE; + + // elites can have third skill trait + if ( Chance( iChance/3 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded && + ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) ) + { + pSoldier->stats.ubSkillTraits[2] = AMBIDEXTROUS_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + else // with original traits + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = AMBIDEXT_OT; + ATraitAssigned = TRUE; + // Ambidextrous trait gives us second weapon automatically + if (!Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) + { + (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); + } + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = AMBIDEXT_OT; + BTraitAssigned = TRUE; + // Ambidextrous trait gives us second weapon automatically + if (!Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) + { + (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); + } + } + } + } + } + // NO GUN IN HANDS, CONTINUE + else + { + } + + //NOW, IF SOME TRAITS HAVEN'T BEEN ASSIGNED, TRY TO ASSIGN DIFFERENT TRAITS + if (!ATraitAssigned || !BTraitAssigned || (!CTraitAssigned && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) ) + { + INT8 bLoop; + BOOLEAN foundMortar = FALSE; + BOOLEAN foundRocketlauncher = FALSE; + BOOLEAN foundGrenadelauncher = FALSE; + BOOLEAN foundKnife = FALSE; + BOOLEAN foundGrenades = FALSE; + BOOLEAN foundThrowing = FALSE; + BOOLEAN foundHtH = FALSE; + BOOLEAN foundMelee = FALSE; + + // FIRST FIND OUT THE COMPOSITION OF OUR GEAR + for (bLoop = 0; bLoop < (INT8) pSoldier->inv.size(); bLoop++) + { + if (pCreateStruct->Inv[bLoop].exists() == true) + { + if (Item[pCreateStruct->Inv[bLoop].usItem].mortar ) + foundMortar = TRUE; + else if (Item[pCreateStruct->Inv[bLoop].usItem].rocketlauncher ) + foundRocketlauncher = TRUE; + else if (Item[pCreateStruct->Inv[bLoop].usItem].grenadelauncher ) + foundGrenadelauncher = TRUE; + else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_BLADE ) + foundKnife = TRUE; + else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_THROWING_KNIFE ) + foundThrowing = TRUE; + else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_GRENADE ) + foundGrenades = TRUE; + else if ( Item[pCreateStruct->Inv[bLoop].usItem].brassknuckles ) + foundHtH = TRUE; + else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == 128 && // 128 is an identifier of blunt melee weapons + Item[pCreateStruct->Inv[bLoop].usItem].uiIndex != 0 ) + foundMelee = TRUE; + } + } + + // NOW BASED ON WHAT WE HAVE FOUND, ASSIGN UNASSIGNED TRAITS + + // HEAVY WEAPONS TRAIT + if ( foundMortar || foundRocketlauncher || foundGrenadelauncher ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 45 + ubProgress/2; // 45-95% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 30 + ubProgress/2; // 30-80% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 15 + ubProgress/2; // 15-65% chance + + // adust the chance by the type of heavy weapon + if (foundMortar) + iChance = 200; // instant chance if we are a mortar guy + else if (foundGrenadelauncher) + iChance -= 15; // -15% chance if we only have a grenade launcher + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[0] = HEAVY_WEAPONS_NT; + else + pSoldier->stats.ubSkillTraits[0] = HEAVY_WEAPS_OT; + + ATraitAssigned = TRUE; + + // half the chance to be an expert + if ( Chance( iChance/2 ) && !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPONS_NT; + else + { + pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPS_OT; + return( TRUE ); // We no longer need to continue from here + } + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + if ( gGameOptions.fNewTraitSystem ) + pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPONS_NT; + else + { + pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPS_OT; + return( TRUE ); // We no longer need to continue from here + } + BTraitAssigned = TRUE; + } + } + } + + // MARTIAL ARTS - new traits + if (( !ATraitAssigned || !BTraitAssigned ) && gGameOptions.fNewTraitSystem ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 20 + ubProgress/4; // 20-45% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 10 + ubProgress/4; // 10-35% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress/4; // 0-25% chance + + if( foundHtH ) // if found brass knuckless, increase the chance (doesn't happen often) + iChance += 35; + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT; + ATraitAssigned = TRUE; + + // reduced chance to be an expert + if ( Chance( iChance/4 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT; + BTraitAssigned = TRUE; + } + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT; + BTraitAssigned = TRUE; + } + } + } + + // NIGHT OPS TRAIT + if ( (DayTime() != TRUE) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 40 + ubProgress*2/5; // 40-80% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 25 + ubProgress*2/5; // 25-65% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 10 + ubProgress*2/5; // 10-50% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + if (gGameOptions.fNewTraitSystem) + { + pSoldier->stats.ubSkillTraits[0] = NIGHT_OPS_NT; + ATraitAssigned = TRUE; + } + else + { + pSoldier->stats.ubSkillTraits[0] = NIGHTOPS_OT; + ATraitAssigned = TRUE; + + // reduced chance to be an expert + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = NIGHTOPS_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + else if ( !BTraitAssigned ) + { + if (gGameOptions.fNewTraitSystem) + pSoldier->stats.ubSkillTraits[1] = NIGHT_OPS_NT; + else + { + pSoldier->stats.ubSkillTraits[1] = NIGHTOPS_OT; + return( TRUE ); // We no longer need to continue from here + } + BTraitAssigned = TRUE; + } + // allow third only to elites + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + { + pSoldier->stats.ubSkillTraits[2] = NIGHT_OPS_NT; + CTraitAssigned = TRUE; + return( TRUE ); + } + } + } + + // THROWING TRAIT + if ( (foundThrowing) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 30 + ubProgress/3 + 30; // 60-92% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 15 + ubProgress/3 + 25; // 40-73% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress/3 + 20; // 20-53% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + if (gGameOptions.fNewTraitSystem) + { + pSoldier->stats.ubSkillTraits[0] = THROWING_NT; + ATraitAssigned = TRUE; + } + else + { + pSoldier->stats.ubSkillTraits[0] = THROWING_OT; + ATraitAssigned = TRUE; + + // reduced the chance to be an expert + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = THROWING_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + else if ( !BTraitAssigned ) + { + if (gGameOptions.fNewTraitSystem) + pSoldier->stats.ubSkillTraits[1] = THROWING_NT; + else + { + pSoldier->stats.ubSkillTraits[1] = THROWING_OT; + return( TRUE ); // We no longer need to continue from here + } + + BTraitAssigned = TRUE; + } + // allow third only to elites + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + { + pSoldier->stats.ubSkillTraits[2] = THROWING_NT; + CTraitAssigned = TRUE; + return( TRUE ); + } + } + } + + // DEMOLITIONS TRAIT + if ( (foundGrenades) && (gGameOptions.fNewTraitSystem)&& (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 20 + ubProgress/3; // 20-53% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 10 + ubProgress/3; // 10-43% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress/3; // 0-33% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = DEMOLITIONS_NT; + ATraitAssigned = TRUE; + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = DEMOLITIONS_NT; + BTraitAssigned = TRUE; + } + // allow third only to elites + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + { + pSoldier->stats.ubSkillTraits[2] = DEMOLITIONS_NT; + CTraitAssigned = TRUE; + return( TRUE ); + } + } + } + + // MELEE / KNIFING TRAIT + if ( ( foundKnife || (foundMelee && gGameOptions.fNewTraitSystem)) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 50 + ubProgress*2/5; // 50-90% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 35 + ubProgress*2/5; // 35-75% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 15 + ubProgress*2/5; // 15-55% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + + if (gGameOptions.fNewTraitSystem) + { + pSoldier->stats.ubSkillTraits[0] = MELEE_NT; + ATraitAssigned = TRUE; + } + else + { + pSoldier->stats.ubSkillTraits[0] = KNIFING_OT; + ATraitAssigned = TRUE; + + // reduced the chance to be an expert + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = KNIFING_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + else if ( !BTraitAssigned ) + { + if (gGameOptions.fNewTraitSystem) + pSoldier->stats.ubSkillTraits[1] = MELEE_NT; + else + { + pSoldier->stats.ubSkillTraits[1] = KNIFING_OT; + return( TRUE ); // We no longer need to continue from here + } + BTraitAssigned = TRUE; + } + // allow third only to elites + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + { + pSoldier->stats.ubSkillTraits[2] = MELEE_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + + // HAND TO HAND TRAIT - old traits nly + if ( foundHtH && !gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned ) ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 40 + ubProgress*2/5; // 40-80% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 25 + ubProgress*2/5; // 25-65% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 10 + ubProgress*2/5; // 10-50% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT; + ATraitAssigned = TRUE; + + // half the chance to be an expert + if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = HANDTOHAND_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = HANDTOHAND_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + + // MARTIAL ARTS - old traits + if (( !ATraitAssigned || !BTraitAssigned ) && !gGameOptions.fNewTraitSystem && (pCreateStruct->bBodyType == REGMALE)) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 10 + ubProgress/4; // 10-35% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = ubProgress/5; // 0-20% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 0; // 0% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = MARTIALARTS_OT; + ATraitAssigned = TRUE; + + // reduced chance to be an expert + if ( Chance( iChance/2 ) && !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT; + BTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + + // BODYBUILDING/ATHLETICS TRAITS (only for new traits) + if ( gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned ) ) + { + // setup basic chances based on soldier type + if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 30 + ubProgress/2; // 30-90% chance + else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 10 + ubProgress/2; // 10-60% chance + else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress/3; // 0-33% chance + + // modify the chance by preset ini setting + if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + { + iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); + } + + // assign the trait based on the chance + if ( Chance( iChance ) ) + { + UINT32 uiBodyBuildChance; // chance to geet bodybuilding rather than athletics + if ( pSoldier->ubBodyType == BIGMALE ) // big guys more likely take bb + uiBodyBuildChance = 90; + else if ( pSoldier->ubBodyType == REGFEMALE ) // while women athletics + uiBodyBuildChance = 10; + else + uiBodyBuildChance = 60; // normally prefer bb a bit + + if ( Chance( uiBodyBuildChance ) ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = BODYBUILDING_NT; + ATraitAssigned = TRUE; + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = BODYBUILDING_NT; + BTraitAssigned = TRUE; + } + else if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + pSoldier->stats.ubSkillTraits[2] = BODYBUILDING_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + // give us also a small chance to get athletics on top + if ( Chance( iChance/3 ) && ( !ATraitAssigned || !BTraitAssigned || !CTraitAssigned )) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = ATHLETICS_NT; + ATraitAssigned = TRUE; + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = ATHLETICS_NT; + BTraitAssigned = TRUE; + } + else if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + pSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + else + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = ATHLETICS_NT; + ATraitAssigned = TRUE; + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = ATHLETICS_NT; + BTraitAssigned = TRUE; + } + else if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + pSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + // give us also a small chance to get bodybuilding on top + if ( Chance( iChance/3 ) && ( !ATraitAssigned || !BTraitAssigned || !CTraitAssigned )) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = BODYBUILDING_NT; + ATraitAssigned = TRUE; + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = BODYBUILDING_NT; + BTraitAssigned = TRUE; + } + else if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + { + pSoldier->stats.ubSkillTraits[2] = BODYBUILDING_NT; + CTraitAssigned = TRUE; + return( TRUE ); // We no longer need to continue from here + } + } + } + } + } + } + // RETURN TRUE IF ALL TRAITS ASSIGNED OTHERWISE FALSE + if (( !gGameOptions.fNewTraitSystem && ATraitAssigned && BTraitAssigned ) || ( gGameOptions.fNewTraitSystem && ATraitAssigned && BTraitAssigned && CTraitAssigned ) ) + return( TRUE ); + else + return( FALSE ); +} \ No newline at end of file diff --git a/Tactical/Soldier Create.h b/Tactical/Soldier Create.h index 0483c538..0903d776 100644 --- a/Tactical/Soldier Create.h +++ b/Tactical/Soldier Create.h @@ -500,6 +500,9 @@ BOOLEAN InternalTacticalRemoveSoldier( UINT16 usSoldierIndex, BOOLEAN fRemoveVeh void OkayToUpgradeEliteToSpecialProfiledEnemy( SOLDIERCREATE_STRUCT *pp ); extern BOOLEAN gfProfiledEnemyAdded; //needs to be saved (used by the above function) +//Legion by Jazz +void BeginSoldierClimbUpOkno( SOLDIERTYPE *pSoldier ); +void BeginSoldierFenceUp( SOLDIERTYPE *pSoldier ); //dnl ch27 240909 typedef enum { @@ -517,4 +520,7 @@ BOOLEAN TranslateArrayFields(void* out, const void* inp, int len, int cmd); #define CENTRAL_GRIDNO (MAPROWCOLTOPOS(WORLD_ROWS/2,WORLD_COLS/2)) #define CENTRAL_RADIUS (min(WORLD_ROWS,WORLD_COLS)/5) +void ResetNumSquadleadersInArmyGroup( void ); // added by SANDRO +BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCreateStruct ); // Added a function to add traits to soldiers - SANDRO + #endif \ No newline at end of file diff --git a/Tactical/Soldier Init List.cpp b/Tactical/Soldier Init List.cpp index 3259f6b9..0ea9d80d 100644 --- a/Tactical/Soldier Init List.cpp +++ b/Tactical/Soldier Init List.cpp @@ -53,6 +53,7 @@ #include "Map Edgepoints.h" #include "Queen Command.h" +#include "Map Edgepoints.h" BOOLEAN gfOriginalList = TRUE; SOLDIERINITNODE *gSoldierInitHead = NULL; @@ -952,6 +953,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("AddSoldierInitListEnemyDefenceSoldiers")); ResetMortarsOnTeamCount(); + ResetNumSquadleadersInArmyGroup(); // added by SANDRO //Specs call for only one profiled enemy can be in a sector at a time due to flavor reasons. gfProfiledEnemyAdded = FALSE; @@ -2142,8 +2144,14 @@ void AddProfilesUsingProfileInsertionData() SOLDIERTYPE *pSoldier; SOLDIERINITNODE * curr; - for( i = FIRST_RPC; i < ( PROF_HUMMER ); i++ ) + //for( i = FIRST_RPC; i < ( PROF_HUMMER ); i++ ) + //new profiles by Jazz + for( i = 0; i < NUM_PROFILES; i++ ) { + + if ( gProfilesRPC[i].ProfilId == i || gProfilesNPC[i].ProfilId == i ) + { + //Perform various checks to make sure the soldier is actually in the same sector, alive, and so on. //More importantly, the flag to use profile insertion data must be set. if( gMercProfiles[ i ].sSectorX != gWorldSectorX || @@ -2213,6 +2221,8 @@ void AddProfilesUsingProfileInsertionData() } } } + + } } } diff --git a/Tactical/Soldier Profile.cpp b/Tactical/Soldier Profile.cpp index bb62f0dc..5037f26d 100644 --- a/Tactical/Soldier Profile.cpp +++ b/Tactical/Soldier Profile.cpp @@ -54,8 +54,13 @@ #include "environment.h" #include "Player Command.h" #include "strategic.h" + #include "strategicmap.h" // added by SANDRO #endif +#include "aim.h" +#include "AimFacialIndex.h" +#include "mercs.h" + #include "connect.h" #ifdef JA2EDITOR extern BOOLEAN gfProfileDataLoaded; @@ -65,7 +70,14 @@ class OBJECTTYPE; class SOLDIERTYPE; - +//new profiles by Jazz------------------------------- +AIM_PROFIL gProfilesAIM[ NUM_PROFILES ]; +MERC_PROFIL gProfilesMERC[ NUM_PROFILES ]; +NPC_PROFIL gProfilesNPC[ NUM_PROFILES ]; +RPC_PROFIL gProfilesRPC[ NUM_PROFILES ]; +VEHICLE_PROFIL gProfilesVehicle[ NUM_PROFILES ]; +IMP_PROFIL gProfilesIMP[NUM_PROFILES]; +//--------------------------------------------------- BOOLEAN gfPotentialTeamChangeDuringDeath = FALSE; @@ -75,12 +87,16 @@ BOOLEAN gfPotentialTeamChangeDuringDeath = FALSE; #define SET_PROFILE_GAINS2 500, 500, 500, 500, 500, 500, 500, 500, 500 -MERCPROFILESTRUCT gMercProfiles[ NUM_PROFILES ]; -MERCPROFILEGEAR gMercProfileGear[ NUM_PROFILES ]; +MERCPROFILESTRUCT gMercProfiles[ NUM_PROFILES ]; +MERCPROFILEGEAR gMercProfileGear[ NUM_PROFILES ][ NUM_MERCSTARTINGGEAR_KITS ]; extern UINT8 gubItemDroppableFlag[NUM_INV_SLOTS]; -INT8 gbSkillTraitBonus[NUM_SKILLTRAITS] = +//Random Stats +RANDOM_STATS_VALUES gRandomStatsValue[NUM_PROFILES]; +void RandomStats (); + +INT8 gbSkillTraitBonus[NUM_SKILLTRAITS_OT] = { 0, //NO_SKILLTRAIT 25, //LOCKPICKING @@ -98,9 +114,9 @@ INT8 gbSkillTraitBonus[NUM_SKILLTRAITS] = 30, //KNIFING 5, //PROF_SNIPER 0, //CAMOUFLAGED - 0, //CAMOUFLAGED_URBAN - 0, //CAMOUFLAGED_DESERT - 0, //CAMOUFLAGED_SNOW + //0, //CAMOUFLAGED_URBAN + //0, //CAMOUFLAGED_DESERT + //0, //CAMOUFLAGED_SNOW }; @@ -224,6 +240,257 @@ void DecideActiveTerrorists( void ); extern SOLDIERTYPE *gpSMCurrentMerc; extern BOOLEAN gfRerenderInterfaceFromHelpText; +BOOLEAN SaveNewSystemMercsToSaveGameFile( HWFILE hFile ); +BOOLEAN LoadNewSystemMercsToSaveGameFile( HWFILE hFile ); +void InitNewProfiles(); + + +// WANNE: This method is not needed anymore. All the stuff is done in the LoadMercProfiles() method. +void InitNewProfiles() +{ + UINT32 uiProfileId = 0; + + UINT32 i = 0; + + UINT32 uiLoop; + + //new profiles by Jazz + for( uiProfileId = 0; uiProfileId < NUM_PROFILES; uiProfileId++ ) + { + gProfilesAIM[ uiProfileId ].ProfilId = -1; + gProfilesMERC[ uiProfileId ].ProfilId = -1; + gProfilesNPC[ uiProfileId ].ProfilId = -1; + gProfilesRPC[ uiProfileId ].ProfilId = -1; + gProfilesVehicle[ uiProfileId ].ProfilId = -1; + gProfilesIMP[ uiProfileId ].ProfilId = -1; + } + + for( uiProfileId = 0; uiProfileId < 40; uiProfileId++ ) + { + gProfilesAIM[ uiProfileId ].ProfilId = uiProfileId; + } + + for( uiProfileId = 40; uiProfileId < 51; uiProfileId++ ) + { + gProfilesMERC[ uiProfileId ].ProfilId = uiProfileId; + } + + for( uiProfileId = FIRST_RPC; uiProfileId < FIRST_NPC; uiProfileId++ ) + { + gProfilesRPC[ uiProfileId ].ProfilId = uiProfileId; + } + + for( uiProfileId = FIRST_NPC; uiProfileId < 160; uiProfileId++ ) + { + gProfilesNPC[ uiProfileId ].ProfilId = uiProfileId; + } + + //IMP + gProfilesIMP[ 51 ].ProfilId = 51; //IMP Male + gProfilesIMP[ 52 ].ProfilId = 52; //IMP Male + gProfilesIMP[ 53 ].ProfilId = 53; //IMP Male + gProfilesIMP[ 54 ].ProfilId = 54; //IMP Female + gProfilesIMP[ 55 ].ProfilId = 55; //IMP Female + gProfilesIMP[ 56 ].ProfilId = 56; //IMP Female + + //Vehicle + gProfilesVehicle[ 160 ].ProfilId = 160; //Hummer + gProfilesVehicle[ 161 ].ProfilId = 161; //El Dorado + gProfilesVehicle[ 162 ].ProfilId = 162; //Truck + gProfilesVehicle[ 163 ].ProfilId = 163; //HELICOPTER + gProfilesVehicle[ 164 ].ProfilId = 164; //TANK_CAR + + //NPC + gProfilesNPC[ 169 ].ProfilId = 169; //none + + //MERC + gProfilesMERC[ 165 ].ProfilId = 165; //Gaston + gProfilesMERC[ 166 ].ProfilId = 166; //Stogie + gProfilesMERC[ 167 ].ProfilId = 167; //Tex + gProfilesMERC[ 168 ].ProfilId = 168; //Beggins + + for(uiLoop=0; uiLoop < 40; uiLoop++) + { + if ( gProfilesAIM[uiLoop].ProfilId == uiLoop ) + { + AimMercArray[ i ] = uiLoop; + } + i++; + } + + MAX_NUMBER_MERCS = 40; + START_MERC = 0; + + if ( gGameExternalOptions.fReadProfileDataFromXML == TRUE ) + { + for( uiProfileId = 0; uiProfileId < NUM_PROFILES; uiProfileId++ ) + { + gProfilesAIM[ uiProfileId ].ProfilId = -1; + gProfilesMERC[ uiProfileId ].ProfilId = -1; + gProfilesNPC[ uiProfileId ].ProfilId = -1; + gProfilesRPC[ uiProfileId ].ProfilId = -1; + gProfilesVehicle[ uiProfileId ].ProfilId = -1; + gProfilesIMP[ uiProfileId ].ProfilId = -1; + } + } + + //------------------------------------------------------------------------ +} + +BOOLEAN SaveNewSystemMercsToSaveGameFile( HWFILE hFile ) +{ + UINT32 uiNumBytesWritten; + + FileWrite( hFile, &gProfilesAIM, sizeof( gProfilesAIM), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gProfilesAIM ) ) + { + return( FALSE ); + } + + FileWrite( hFile, &gProfilesMERC, sizeof( gProfilesMERC), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gProfilesMERC ) ) + { + return( FALSE ); + } + + FileWrite( hFile, &gProfilesNPC, sizeof( gProfilesNPC), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gProfilesNPC ) ) + { + return( FALSE ); + } + + FileWrite( hFile, &gProfilesRPC, sizeof( gProfilesRPC), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gProfilesRPC ) ) + { + return( FALSE ); + } + + FileWrite( hFile, &gProfilesVehicle, sizeof( gProfilesVehicle), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gProfilesVehicle ) ) + { + return( FALSE ); + } + + FileWrite( hFile, &gProfilesIMP, sizeof( gProfilesIMP), &uiNumBytesWritten ); + if( uiNumBytesWritten != sizeof( gProfilesIMP ) ) + { + return( FALSE ); + } + return( TRUE ); +} + +BOOLEAN LoadNewSystemMercsToSaveGameFile( HWFILE hFile ) +{ + UINT32 uiNumBytesRead; + + FileRead( hFile, &gProfilesAIM, sizeof( gProfilesAIM), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gProfilesAIM ) ) + { + return( FALSE ); + } + + FileRead( hFile, &gProfilesMERC, sizeof( gProfilesMERC), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gProfilesMERC ) ) + { + return( FALSE ); + } + + FileRead( hFile, &gProfilesNPC, sizeof( gProfilesNPC), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gProfilesNPC ) ) + { + return( FALSE ); + } + + FileRead( hFile, &gProfilesRPC, sizeof( gProfilesRPC), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gProfilesRPC ) ) + { + return( FALSE ); + } + + FileRead( hFile, &gProfilesVehicle, sizeof( gProfilesVehicle), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gProfilesVehicle ) ) + { + return( FALSE ); + } + + FileRead( hFile, &gProfilesIMP, sizeof( gProfilesIMP), &uiNumBytesRead ); + if( uiNumBytesRead != sizeof( gProfilesIMP ) ) + { + return( FALSE ); + } + + return( TRUE ); +} + +//Random stats +void RandomStats () +{ +UINT32 cnt; +INT8 bBaseAttribute = 0; +MERCPROFILESTRUCT * pProfile; + + for ( cnt = 0; cnt < NUM_PROFILES; cnt++ ) + { + if ( gRandomStatsValue[cnt].Enabled == TRUE ) + { + bBaseAttribute = gRandomStatsValue[cnt].BaseAttribute + ( 4 * gRandomStatsValue[cnt].ExpLevel ); + pProfile = &(gMercProfiles[cnt]); + + pProfile->bExpLevel = gRandomStatsValue[cnt].ExpLevel; + + if ( gRandomStatsValue[cnt].RandomLife == TRUE ) + { + pProfile->bLifeMax = (bBaseAttribute + Random( 9 ) + Random( 8 )); + pProfile->bLife = pProfile->bLifeMax; + } + + if ( gRandomStatsValue[cnt].RandomAgility == TRUE ) + { + pProfile->bAgility = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomLeadership == TRUE ) + { + pProfile->bLeadership = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomDexterity == TRUE ) + { + pProfile->bDexterity = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomWisdom == TRUE ) + { + pProfile->bWisdom = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomMarksmanship == TRUE ) + { + pProfile->bMarksmanship = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomMedical == TRUE ) + { + pProfile->bMedical = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomMechanical == TRUE ) + { + pProfile->bMechanical = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomExplosive == TRUE ) + { + pProfile->bExplosive = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + + if ( gRandomStatsValue[cnt].RandomStrength == TRUE ) + { + pProfile->bStrength = (bBaseAttribute + Random( 9 ) + Random( 8 )); + } + } + } +} // WANNE - BMP: DONE! BOOLEAN LoadMercProfiles(void) @@ -245,6 +512,10 @@ BOOLEAN LoadMercProfiles(void) UINT32 uiLoop, uiLoop2;//, uiLoop3; UINT16 usItem;//, usNewGun, usAmmo, usNewAmmo; + + // ----- WANNE.PROFILE: New Profile Loading - BEGIN + //InitNewProfiles(); + // ----- WANNE.PROFILE: New Profile Loading - END if (gGameExternalOptions.fUseDifficultyBasedProfDat == TRUE) { @@ -291,18 +562,43 @@ BOOLEAN LoadMercProfiles(void) return(FALSE); } + // Reset + for( int uiProfileId = 0; uiProfileId < NUM_PROFILES; uiProfileId++ ) + { + gProfilesAIM[ uiProfileId ].ProfilId = -1; + gProfilesMERC[ uiProfileId ].ProfilId = -1; + gProfilesNPC[ uiProfileId ].ProfilId = -1; + gProfilesRPC[ uiProfileId ].ProfilId = -1; + gProfilesVehicle[ uiProfileId ].ProfilId = -1; + gProfilesIMP[ uiProfileId ].ProfilId = -1; + } + + int profileIndex = -1; + for(uiLoop=0; uiLoop< NUM_PROFILES; uiLoop++) { + profileIndex++; + // Changed by ADB, rev 1513 //if( !gMercProfiles[uiLoop].Load(fptr, true)) - if( !gMercProfiles[uiLoop].Load(fptr, true, true, true)) + //if( !gMercProfiles[uiLoop].Load(fptr, true, true, true)) + if( uiLoop < 170 && !gMercProfiles[uiLoop].Load(fptr, true, true, true)) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("FAILED to Read Merc Profiles from File %d %s",uiLoop, pFileName) ); FileClose( fptr ); return(FALSE); } + + // WANNE: For the new WF merc, there is no entry in prof.dat, so we have to reset some flags manually! + if (uiLoop >= 170) + { + gMercProfiles[uiLoop].ubMiscFlags = 0; + gMercProfiles[uiLoop].ubMiscFlags2 = 0; + gMercProfiles[uiLoop].ubMiscFlags3 = 0; + + gMercProfiles[uiLoop].uiTotalCostToDate = 0; + } - // WANNE - BMP: NEED TESTING! // WANNE - BMP: DONE! // convert old MERCPROFILESTRUCT to new MERCPROFILESTRUCT gMercProfiles[uiLoop].sGridNo = gMercProfiles[uiLoop]._old_sGridNo; @@ -310,25 +606,28 @@ BOOLEAN LoadMercProfiles(void) // /* CHRISL: For now, we should only overwrite prof.dat in the new inventory system. Old system should still use - prof.dat until we're sure we want to replace it with the xml file.*/ - if(UsingNewInventorySystem() == true){ + prof.dat until we're sure we want to replace it with the xml file. + Because the new WF mercs don't have entries in the prof*.dat files, we need to always load their equipment from + MercStaringGear.xml, regardless of the inventory system we're going to use.*/ + if(UsingNewInventorySystem() == true || uiLoop >= 170 ) + { // Start by resetting all profile inventory values to 0 gMercProfiles[uiLoop].clearInventory(); gMercProfiles[uiLoop].ubInvUndroppable = 0; // Next, go through and assign everything but lbe gear for(uiLoop2=INV_START_POS; uiLoop2 5) - gMercProfiles[uiLoop].bInvNumber[uiLoop2] = gMercProfileGear[uiLoop].iNumber[uiLoop2]; + gMercProfiles[uiLoop].bInvNumber[uiLoop2] = gMercProfileGear[uiLoop][0].iNumber[uiLoop2]; else gMercProfiles[uiLoop].bInvNumber[uiLoop2] = 1; } //CHRISL: Moved outside first condition we we set ubInvUndroppable regardless of having an item - if(gMercProfileGear[uiLoop].iDrop[uiLoop2] == 0 && uiLoop > 56){ + if(gMercProfileGear[uiLoop][0].iDrop[uiLoop2] == 0 && uiLoop > 56){ gMercProfiles[uiLoop].ubInvUndroppable |= gubItemDroppableFlag[uiLoop2]; } } @@ -338,9 +637,9 @@ BOOLEAN LoadMercProfiles(void) for(uiLoop2=0; uiLoop2<5; uiLoop2++) { UINT32 uiLoop3 = uiLoop2 + VESTPOCKPOS; - if(gMercProfileGear[uiLoop].lbe[uiLoop2] != NONE){ - gMercProfiles[uiLoop].inv[uiLoop3] = gMercProfileGear[uiLoop].lbe[uiLoop2]; - gMercProfiles[uiLoop].bInvStatus[uiLoop3] = gMercProfileGear[uiLoop].lStatus[uiLoop2]; + if(gMercProfileGear[uiLoop][0].lbe[uiLoop2] != NONE){ + gMercProfiles[uiLoop].inv[uiLoop3] = gMercProfileGear[uiLoop][0].lbe[uiLoop2]; + gMercProfiles[uiLoop].bInvStatus[uiLoop3] = gMercProfileGear[uiLoop][0].lStatus[uiLoop2]; gMercProfiles[uiLoop].bInvNumber[uiLoop3] = 1; } } @@ -367,43 +666,7 @@ BOOLEAN LoadMercProfiles(void) // Setup face index value // Default is the ubCharNum gMercProfiles[uiLoop].ubFaceIndex = (UINT8)uiLoop; -/* - if ( !gGameOptions.fGunNut ) - { - // CJC: replace guns in profile if they aren't available - for ( uiLoop2 = 0; uiLoop2 < gMercProfiles[uiLoop].inv.size(); uiLoop2++ ) - { - usItem = gMercProfiles[uiLoop].inv[ uiLoop2 ]; - - if ( ( Item[ usItem ].usItemClass & IC_GUN ) && ExtendedGunListGun( usItem ) ) - { - usNewGun = StandardGunListReplacement( usItem ); - if ( usNewGun != NOTHING ) - { - gMercProfiles[uiLoop].inv[ uiLoop2 ] = usNewGun; - - // must search through inventory and replace ammo accordingly - for ( uiLoop3 = 0; uiLoop3 < gMercProfiles[ uiLoop ].inv.size(); uiLoop3++ ) - { - usAmmo = gMercProfiles[ uiLoop ].inv[ uiLoop3 ]; - if ( (Item[ usAmmo ].usItemClass & IC_AMMO) ) - { - usNewAmmo = FindReplacementMagazineIfNecessary( usItem, usAmmo, usNewGun ); - if (usNewAmmo != NOTHING ) - { - // found a new magazine, replace... - gMercProfiles[ uiLoop ].inv[ uiLoop3 ] = usNewAmmo; - } - } - } - } - } - - } - - } // end of if not gun nut -*/ //ATE: Calculate some inital attractiveness values for buddy's inital equipment... // Look for gun and armour gMercProfiles[uiLoop].bMainGunAttractiveness = -1; @@ -427,24 +690,7 @@ BOOLEAN LoadMercProfiles(void) gMercProfiles[uiLoop].bArmourAttractiveness = min(128,Armour[ Item[ usItem ].ubClassIndex ].ubProtection); } } - } - - - // OK, if we are a created slot, this will get overriden at some time.. - - //add up the items the merc has for the usOptionalGearCost - gMercProfiles[ uiLoop ].usOptionalGearCost = 0; - for ( uiLoop2 = 0; uiLoop2< gMercProfiles[ uiLoop ].inv.size(); uiLoop2++ ) - { - if ( gMercProfiles[ uiLoop ].inv[ uiLoop2 ] != NOTHING ) - { - //get the item - usItem = gMercProfiles[ uiLoop ].inv[ uiLoop2 ]; - - //add the cost - gMercProfiles[ uiLoop ].usOptionalGearCost += Item[ usItem ].usPrice; - } - } + } //These variables to get loaded in gMercProfiles[ uiLoop ].fUseProfileInsertionInfo = FALSE; @@ -462,12 +708,168 @@ BOOLEAN LoadMercProfiles(void) OverwriteMercProfileWithXMLData( uiLoop ); OverwriteMercOpinionsWithXMLData( uiLoop ); } + + + //tais: moved initial price calculation down to this spot because PROFEX overwrites my gearkit prices + //with old binary file optional gear prices which got ported into MercProfiles.xml + gMercProfiles[ uiLoop ].usOptionalGearCost = 0; + UINT16 tempGearCost = 0; + for ( uiLoop2 = 0; uiLoop2< gMercProfiles[ uiLoop ].inv.size(); uiLoop2++ ) + { + if ( gMercProfiles[ uiLoop ].inv[ uiLoop2 ] != NOTHING ) + { + //get the item + usItem = gMercProfiles[ uiLoop ].inv[ uiLoop2 ]; + + //add the cost + tempGearCost += Item[ usItem ].usPrice; + } + } + //tais: added optional price modifier for gearkits, reads the xml tag mPriceMod from MercStartingGear.xml + if(gMercProfileGear[uiLoop][0].PriceModifier != 0 && + gMercProfileGear[uiLoop][0].PriceModifier <= 200 && + gMercProfileGear[uiLoop][0].PriceModifier >= -100) + { + FLOAT mod; + mod = (FLOAT) (gMercProfileGear[uiLoop][0].PriceModifier + 100) / 100.0f; + gMercProfiles[ uiLoop ].usOptionalGearCost = (UINT16)(tempGearCost * mod); + } + else + { + gMercProfiles[ uiLoop ].usOptionalGearCost = tempGearCost; + } + + // ----- WANNE.PROFILE: New Profile Loading - BEGIN + if ( gGameExternalOptions.fReadProfileDataFromXML == FALSE ) + { + // AIM und MERC ( 0 - 51 ) + if (uiLoop < 51) + { + // AIM + if (uiLoop < 40) + { + gProfilesAIM[uiLoop].ProfilId = uiLoop; + } + // MERC + else + { + gProfilesMERC[uiLoop].ProfilId = uiLoop; + } + } + // IMP (51 - 56) + else if (uiLoop >= 51 && uiLoop < FIRST_RPC) + { + gProfilesIMP[uiLoop].ProfilId = uiLoop; + } + else + { + // Vehicle, MERC (default 1.13) or RPC? + if (uiLoop >= 165 && uiLoop <= 168) + { + switch (gMercProfiles[ uiLoop ].ubBodyType) + { + // MERC + case REGMALE: + case BIGMALE: + case REGFEMALE: + gProfilesMERC[uiLoop].ProfilId = uiLoop; + break; + // Vehicle + case HUMVEE: + case TANK_NW: + case TANK_NE: + case ELDORADO: + case ICECREAMTRUCK: + case JEEP: + gProfilesVehicle[uiLoop].ProfilId = uiLoop; + break; + // Make it an RPC + default: + gProfilesRPC[uiLoop].ProfilId = uiLoop; + break; + } + } + else + { + // Last Index -> NPC + if (uiLoop == 169) + { + gProfilesNPC[uiLoop].ProfilId = uiLoop; + } + // NPC, RPC or Vehicle + else + { + switch (gMercProfiles[ uiLoop ].ubBodyType) + { + // Vehicle + case HUMVEE: + case TANK_NW: + case TANK_NE: + case ELDORADO: + case ICECREAMTRUCK: + case JEEP: + gProfilesVehicle[uiLoop].ProfilId = uiLoop; + break; + // RPC or NPC + default: + // RPC + if (uiLoop >= FIRST_RPC && uiLoop < FIRST_NPC) + { + gProfilesRPC[uiLoop].ProfilId = uiLoop; + } + // NPC + else + { + gProfilesNPC[uiLoop].ProfilId = uiLoop; + } + break; + } + } + } + } + } } + + // ----- WANNE.PROFILE: New Profile Loading - END // SET SOME DEFAULT LOCATIONS FOR STARTING NPCS + + // Reset + for (int i = 0; i < NUM_PROFILES; i++) + { + AimMercArray[i] = -1; + } FileClose( fptr ); + // --------------- + + UINT16 maxAIMProfiles = 0; + if (!gGameExternalOptions.fReadProfileDataFromXML) + maxAIMProfiles = 40; + else + maxAIMProfiles = NUM_PROFILES; + + UINT32 x = 0; + UINT32 i = 0; + MAX_NUMBER_MERCS = 0; + START_MERC = 0; + + // Find all AIM merc and add them in the AimMercArray which is used for the AIM webpage + for (i = 0; i < maxAIMProfiles; i++) + { + if (gAimAvailability[i].ProfilId != 255) + { + AimMercArray[ x ] = gAimAvailability[i].ProfilId; + x++; + MAX_NUMBER_MERCS++; + } + } + + // --------------- + + RandomStats (); //random stats by Jazz + // decide which terrorists are active DecideActiveTerrorists(); @@ -545,17 +947,19 @@ void DecideActiveTerrorists( void ) ///////////////////////////////////////////////////// // Added so with ENABLE_ALL_TERRORISTS you really get all of them (5 + Charlie) - if ( gGameExternalOptions.fEnableAllTerrorists ) + if ( gGameOptions.fEnableAllTerrorists ) ubNumAdditionalTerrorists = 5; ///////////////////////////////////////////////////// // ifdefs added by CJC #ifdef JA2TESTVERSION - ubNumAdditionalTerrorists = 4; + ubNumAdditionalTerrorists = 5; #endif - while ( ubNumTerroristsAdded < ubNumAdditionalTerrorists ) - { + // silversurfer: this was causing an infinite loop at game start when someone manually placed terrorists using ProEdit and thus + // causing them to become invalid for random location choosing +// while ( ubNumTerroristsAdded < ubNumAdditionalTerrorists ) +// { ubLoop = 1; // start at beginning of array (well, after Elgin) @@ -566,7 +970,7 @@ void DecideActiveTerrorists( void ) ubTerrorist = gubTerrorists[ ubLoop ]; // random 40% chance of adding this terrorist if not yet placed - if ( ( gMercProfiles[ ubTerrorist ].sSectorX == 0 ) && (( Random( 100 ) < 40 ) || gGameExternalOptions.fEnableAllTerrorists ) ) // also added the check because it makes no sense to choose randomly which terrorist will be in game, all of them should + if ( ( gMercProfiles[ ubTerrorist ].sSectorX == 0 ) && (( Random( 100 ) < 40 ) || gGameOptions.fEnableAllTerrorists ) ) // also added the check because it makes no sense to choose randomly which terrorist will be in game, all of them should { //fFoundSpot = FALSE; // Since there are 5 spots per terrorist and a maximum of 5 terrorists, we @@ -609,13 +1013,16 @@ void DecideActiveTerrorists( void ) } // start over if necessary - } +// } // set total terrorists outstanding in Carmen's info byte - gMercProfiles[ 78 ].bNPCData = 1 + ubNumAdditionalTerrorists; + gMercProfiles[ 78 ].bNPCData = 1 + ubNumTerroristsAdded; //ubNumAdditionalTerrorists; + // silversurfer: only use the number of terrorist assigned through this function + // ubNumTerroristsAdded and ubNumAdditionalTerrorists will be the same if all terrorist were randomly placed but if + // someone places terrorists with ProEdit we don't know if those are valid placements // store total terrorists - gubNumTerrorists = 1 + ubNumAdditionalTerrorists; + gubNumTerrorists = 1 + ubNumTerroristsAdded; //ubNumAdditionalTerrorists; } void MakeRemainingTerroristsTougher( void ) @@ -845,8 +1252,11 @@ void StartSomeMercsOnAssignment(void) UINT32 uiChance; // some randomly picked A.I.M. mercs will start off "on assignment" at the beginning of each new game - for( uiCnt = 0; uiCnt < AIM_AND_MERC_MERCS; uiCnt++) + for( uiCnt = 0; uiCnt < NUM_PROFILES; uiCnt++) // AIM_AND_MERC_MERCS { + //new profiles by Jazz + if ( gProfilesAIM[ uiCnt ].ProfilId == (UINT8)uiCnt || gProfilesMERC[ uiCnt ].ProfilId == (UINT8)uiCnt ) + { if( !IsProfileIdAnAimOrMERCMerc( (UINT8)uiCnt ) ) { continue; @@ -857,7 +1267,8 @@ void StartSomeMercsOnAssignment(void) // calc chance to start on assignment uiChance = 5 * pProfile->bExpLevel; - if (Random(100) < uiChance) + // tais: disable mercs being on assignment (this check is just for at the start of the campaign) + if (Random(100) < uiChance && gGameExternalOptions.fMercsOnAssignment < 1) { pProfile->bMercStatus = MERC_WORKING_ELSEWHERE; pProfile->uiDayBecomesAvailable = 1 + Random(6 + (pProfile->bExpLevel / 2) ); // 1-(6 to 11) days @@ -870,6 +1281,7 @@ void StartSomeMercsOnAssignment(void) pProfile->uiPrecedentQuoteSaid = 0; pProfile->ubDaysOfMoraleHangover = 0; + } } } @@ -907,7 +1319,12 @@ UINT16 CalcCompetence( MERCPROFILESTRUCT * pProfile ) // count how many he has, don't care what they are - uiSpecialSkills = ((pProfile->bSkillTrait != 0) ? 1 : 0) + ((pProfile->bSkillTrait2 != 0) ? 1 : 0); + uiSpecialSkills = 0; + for ( INT8 bCnt = 0; bCnt < 30; bCnt++ ) + { + if ( pProfile->bSkillTraits[bCnt] != 0 ) + uiSpecialSkills++; + } usCompetence = (UINT16) ((pow((double)pProfile->bExpLevel, 0.2) * uiStats * uiSkills * (uiActionPoints - 6) * (1 + (0.05 * (FLOAT)uiSpecialSkills))) / 1000); @@ -1027,6 +1444,8 @@ SOLDIERTYPE *ChangeSoldierTeam( SOLDIERTYPE *pSoldier, UINT8 ubTeam ) pNewSoldier->stats.bScientific = pSoldier->stats.bScientific; pNewSoldier->bLastRenderVisibleValue = pSoldier->bLastRenderVisibleValue; pNewSoldier->bVisible = pSoldier->bVisible; + // added by SANDRO - insta-healable injury zero on soldier creation + pNewSoldier->iHealableInjury = pSoldier->iHealableInjury; // WANNE: Fix a vanilla bug: When a soldier changed team (e.g. getting hostile), he lost his camouflage. // Fixed by Tron (Stracciatella): Revision: 7055 @@ -1186,6 +1605,12 @@ BOOLEAN RecruitRPC( UINT8 ubCharNum ) { EndQuest( QUEST_FREE_DYNAMO, pSoldier->sSectorX, pSoldier->sSectorY ); } + // SANDRO - give exp and records quest point, if finally recruiting Miguel + else if ( ubCharNum == MIGUEL ) + { + GiveQuestRewardPoint( pSoldier->sSectorX, pSoldier->sSectorY, 6, MIGUEL ); + } + // handle town loyalty adjustment HandleTownLoyaltyForNPCRecruitment( pNewSoldier ); @@ -1448,14 +1873,18 @@ void UpdateSoldierPointerDataIntoProfile( BOOLEAN fPlayerMercs ) // If we are above player mercs if ( fPlayerMercs ) { - if ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON ) + //if ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON ) + //new profiles by Jazz + if ( gProfilesIMP[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesAIM[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesMERC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile) { fDoCopy = TRUE; } } else { - if ( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < GASTON ) + //if ( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < GASTON ) + //new profiles by Jazz + if ( gProfilesRPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesNPC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesVehicle[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile ) { fDoCopy = TRUE; } @@ -1517,15 +1946,36 @@ BOOLEAN DoesMercHaveABuddyOnTheTeam( UINT8 ubMercID ) BOOLEAN MercIsHot( SOLDIERTYPE * pSoldier ) { - if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == HEAT_INTOLERANT ) + // SANDRO - added argument + if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bDisability == HEAT_INTOLERANT && !pSoldier->MercInWater()) { - if ( SectorTemperature( GetWorldMinutesInDay(), pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 0 ) + if ((pSoldier->bSectorZ > 0) || (guiEnvWeather & ( WEATHER_FORECAST_SHOWERS | WEATHER_FORECAST_THUNDERSHOWERS ))) + { + // cool underground or raining + return( FALSE ); + } + else if ( IsSectorDesert( pSoldier->sSectorX, pSoldier->sSectorY ) ) // is desert + //if ( SectorTemperature( GetWorldMinutesInDay(), pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 1 ) + { + return( TRUE ); + } + else if ( IsSectorTropical( pSoldier->sSectorX, pSoldier->sSectorY ) ) // is tropical { return( TRUE ); } } return( FALSE ); } +// SANDRO - added function here +BOOLEAN MercIsInTropicalSector( SOLDIERTYPE * pSoldier ) +{ + if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->bSectorZ <= 0 && IsSectorTropical(pSoldier->sSectorX, pSoldier->sSectorY) ) + { + return( TRUE ); + } + else + return( FALSE ); +} SOLDIERTYPE * SwapLarrysProfiles( SOLDIERTYPE * pSoldier ) { @@ -1554,12 +2004,50 @@ SOLDIERTYPE * SwapLarrysProfiles( SOLDIERTYPE * pSoldier ) pNewProfile->sSectorX = gMercProfiles[ ubSrcProfile ].sSectorX; pNewProfile->sSectorY = gMercProfiles[ ubSrcProfile ].sSectorY; pNewProfile->uiDayBecomesAvailable = gMercProfiles[ ubSrcProfile ].uiDayBecomesAvailable; - pNewProfile->usKills = gMercProfiles[ ubSrcProfile ].usKills; - pNewProfile->usAssists = gMercProfiles[ ubSrcProfile ].usAssists; - pNewProfile->usShotsFired = gMercProfiles[ ubSrcProfile ].usShotsFired; - pNewProfile->usShotsHit = gMercProfiles[ ubSrcProfile ].usShotsHit; - pNewProfile->usBattlesFought = gMercProfiles[ ubSrcProfile ].usBattlesFought; - pNewProfile->usTimesWounded = gMercProfiles[ ubSrcProfile ].usTimesWounded; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - experimental - more specific statistics of mercs + pNewProfile->records.usKillsElites = gMercProfiles[ ubSrcProfile ].records.usKillsElites; + pNewProfile->records.usKillsRegulars = gMercProfiles[ ubSrcProfile ].records.usKillsRegulars; + pNewProfile->records.usKillsAdmins = gMercProfiles[ ubSrcProfile ].records.usKillsAdmins; + pNewProfile->records.usKillsCreatures = gMercProfiles[ ubSrcProfile ].records.usKillsCreatures; + pNewProfile->records.usKillsTanks = gMercProfiles[ ubSrcProfile ].records.usKillsTanks; + pNewProfile->records.usKillsOthers = gMercProfiles[ ubSrcProfile ].records.usKillsOthers; + pNewProfile->records.usAssistsMercs = gMercProfiles[ ubSrcProfile ].records.usAssistsMercs; + pNewProfile->records.usAssistsMilitia = gMercProfiles[ ubSrcProfile ].records.usAssistsMilitia; + pNewProfile->records.usAssistsOthers = gMercProfiles[ ubSrcProfile ].records.usAssistsOthers; + pNewProfile->records.usShotsFired = gMercProfiles[ ubSrcProfile ].records.usShotsFired; + pNewProfile->records.usMissilesLaunched = gMercProfiles[ ubSrcProfile ].records.usMissilesLaunched; + pNewProfile->records.usGrenadesThrown = gMercProfiles[ ubSrcProfile ].records.usGrenadesThrown; + pNewProfile->records.usKnivesThrown = gMercProfiles[ ubSrcProfile ].records.usKnivesThrown; + pNewProfile->records.usBladeAttacks = gMercProfiles[ ubSrcProfile ].records.usBladeAttacks; + pNewProfile->records.usHtHAttacks = gMercProfiles[ ubSrcProfile ].records.usHtHAttacks; + pNewProfile->records.usShotsHit = gMercProfiles[ ubSrcProfile ].records.usShotsHit; + pNewProfile->records.usBattlesTactical = gMercProfiles[ ubSrcProfile ].records.usBattlesTactical; + pNewProfile->records.usBattlesAutoresolve = gMercProfiles[ ubSrcProfile ].records.usBattlesAutoresolve; + pNewProfile->records.usBattlesRetreated = gMercProfiles[ ubSrcProfile ].records.usBattlesRetreated; + pNewProfile->records.usAmbushesExperienced = gMercProfiles[ ubSrcProfile ].records.usAmbushesExperienced; + pNewProfile->records.usLargestBattleFought = gMercProfiles[ ubSrcProfile ].records.usLargestBattleFought; + pNewProfile->records.usTimesWoundedShot = gMercProfiles[ ubSrcProfile ].records.usTimesWoundedShot; + pNewProfile->records.usTimesWoundedStabbed = gMercProfiles[ ubSrcProfile ].records.usTimesWoundedStabbed; + pNewProfile->records.usTimesWoundedPunched = gMercProfiles[ ubSrcProfile ].records.usTimesWoundedPunched; + pNewProfile->records.usTimesWoundedBlasted = gMercProfiles[ ubSrcProfile ].records.usTimesWoundedBlasted; + pNewProfile->records.usTimesStatDamaged = gMercProfiles[ ubSrcProfile ].records.usTimesStatDamaged; + pNewProfile->records.usFacilityAccidents = gMercProfiles[ ubSrcProfile ].records.usFacilityAccidents; + pNewProfile->records.usLocksPicked = gMercProfiles[ ubSrcProfile ].records.usLocksPicked; + pNewProfile->records.usLocksBreached = gMercProfiles[ ubSrcProfile ].records.usLocksBreached; + pNewProfile->records.usTrapsRemoved = gMercProfiles[ ubSrcProfile ].records.usTrapsRemoved; + pNewProfile->records.usExpDetonated = gMercProfiles[ ubSrcProfile ].records.usExpDetonated; + pNewProfile->records.usItemsRepaired = gMercProfiles[ ubSrcProfile ].records.usItemsRepaired; + pNewProfile->records.usItemsCombined = gMercProfiles[ ubSrcProfile ].records.usItemsCombined; + pNewProfile->records.usItemsCombined = gMercProfiles[ ubSrcProfile ].records.usItemsStolen; + pNewProfile->records.usMercsBandaged = gMercProfiles[ ubSrcProfile ].records.usMercsBandaged; + pNewProfile->records.usSurgeriesMade = gMercProfiles[ ubSrcProfile ].records.usSurgeriesMade; + pNewProfile->records.usNPCsDiscovered = gMercProfiles[ ubSrcProfile ].records.usNPCsDiscovered; + pNewProfile->records.usSectorsDiscovered = gMercProfiles[ ubSrcProfile ].records.usSectorsDiscovered; + pNewProfile->records.usMilitiaTrained = gMercProfiles[ ubSrcProfile ].records.usMilitiaTrained; + pNewProfile->records.ubQuestsHandled = gMercProfiles[ ubSrcProfile ].records.ubQuestsHandled; + + ///////////////////////////////////////////////////////////////////////////////////// pNewProfile->usTotalDaysServed = gMercProfiles[ ubSrcProfile ].usTotalDaysServed; pNewProfile->bResigned = gMercProfiles[ ubSrcProfile ].bResigned; pNewProfile->bActive = gMercProfiles[ ubSrcProfile ].bActive; @@ -1685,9 +2173,8 @@ BOOLEAN DoesNPCOwnBuilding( SOLDIERTYPE *pSoldier, INT32 sGridNo ) BOOLEAN IsProfileIdAnAimOrMERCMerc( UINT8 ubProfileID ) { - if( ubProfileID < BIFF || - ( ubProfileID >= BIFF && ubProfileID <= BUBBA ) || - ubProfileID >= GASTON ) + //if( ubProfileID < BIFF || ( ubProfileID >= BIFF && ubProfileID <= BUBBA ) || ubProfileID >= GASTON ) + if( gProfilesAIM[ ubProfileID ].ProfilId == ubProfileID || gProfilesMERC[ ubProfileID ].ProfilId == ubProfileID ) { return( TRUE ); } @@ -1706,6 +2193,7 @@ void OverwriteMercProfileWithXMLData( UINT32 uiLoop ) // new data from XML. This allows making PROEDIT obsolete. // ////////////////////////////////////////////////////////////////////////////////// + wcscpy(gMercProfiles[ uiLoop ].zName, tempProfiles[ uiLoop ].zName) ; wcscpy(gMercProfiles[ uiLoop ].zNickname, tempProfiles[ uiLoop ].zNickname) ; @@ -1728,8 +2216,28 @@ void OverwriteMercProfileWithXMLData( UINT32 uiLoop ) gMercProfiles[ uiLoop ].ubBodyType = tempProfiles[ uiLoop ].ubBodyType ; gMercProfiles[ uiLoop ].uiBodyTypeSubFlags = tempProfiles[ uiLoop ].uiBodyTypeSubFlags ; - gMercProfiles[ uiLoop ].bAttitude = tempProfiles[ uiLoop ].bAttitude ; - gMercProfiles[ uiLoop ].bPersonalityTrait = tempProfiles[ uiLoop ].bPersonalityTrait ; + /////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if (gGameOptions.fNewTraitSystem) + { + if (tempProfiles[ uiLoop ].bCharacterTrait >= NUM_CHAR_TRAITS || tempProfiles[ uiLoop ].bCharacterTrait < CHAR_TRAIT_NORMAL ) + gMercProfiles[ uiLoop ].bCharacterTrait = CHAR_TRAIT_NORMAL; + else + gMercProfiles[ uiLoop ].bCharacterTrait = tempProfiles[ uiLoop ].bCharacterTrait ; + } + else + { + if (tempProfiles[ uiLoop ].bAttitude >= NUM_ATTITUDES || tempProfiles[ uiLoop ].bAttitude < ATT_NORMAL ) + gMercProfiles[ uiLoop ].bAttitude = ATT_NORMAL; + else + gMercProfiles[ uiLoop ].bAttitude = tempProfiles[ uiLoop ].bAttitude ; + } + + if (tempProfiles[ uiLoop ].bDisability >= NUM_DISABILITIES || tempProfiles[ uiLoop ].bDisability < NO_DISABILITY ) + gMercProfiles[ uiLoop ].bDisability = NO_DISABILITY; + else + gMercProfiles[ uiLoop ].bDisability = tempProfiles[ uiLoop ].bDisability ; + /////////////////////////////////////////////////////////////////////////////////////////// gMercProfiles[ uiLoop ].ubNeedForSleep = tempProfiles[ uiLoop ].ubNeedForSleep ; gMercProfiles[ uiLoop ].bReputationTolerance = tempProfiles[ uiLoop ].bReputationTolerance ; @@ -1749,8 +2257,73 @@ void OverwriteMercProfileWithXMLData( UINT32 uiLoop ) gMercProfiles[ uiLoop ].bExpLevel = tempProfiles[ uiLoop ].bExpLevel ; gMercProfiles[ uiLoop ].bEvolution = tempProfiles[ uiLoop ].bEvolution ; - gMercProfiles[ uiLoop ].bSkillTrait = tempProfiles[ uiLoop ].bSkillTrait ; - gMercProfiles[ uiLoop ].bSkillTrait2 = tempProfiles[ uiLoop ].bSkillTrait2 ; + ////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Check old/new traits and repair possible errors + if (gGameOptions.fNewTraitSystem) + { + gMercProfiles[ uiLoop ].bSkillTraits[0] = tempProfiles[ uiLoop ].bNewSkillTrait1; + gMercProfiles[ uiLoop ].bSkillTraits[1] = tempProfiles[ uiLoop ].bNewSkillTrait2; + gMercProfiles[ uiLoop ].bSkillTraits[2] = tempProfiles[ uiLoop ].bNewSkillTrait3; + gMercProfiles[ uiLoop ].bSkillTraits[3] = tempProfiles[ uiLoop ].bNewSkillTrait4; + gMercProfiles[ uiLoop ].bSkillTraits[4] = tempProfiles[ uiLoop ].bNewSkillTrait5; + gMercProfiles[ uiLoop ].bSkillTraits[5] = tempProfiles[ uiLoop ].bNewSkillTrait6; + gMercProfiles[ uiLoop ].bSkillTraits[6] = tempProfiles[ uiLoop ].bNewSkillTrait7; + gMercProfiles[ uiLoop ].bSkillTraits[7] = tempProfiles[ uiLoop ].bNewSkillTrait8; + gMercProfiles[ uiLoop ].bSkillTraits[8] = tempProfiles[ uiLoop ].bNewSkillTrait9; + gMercProfiles[ uiLoop ].bSkillTraits[9] = tempProfiles[ uiLoop ].bNewSkillTrait10; + gMercProfiles[ uiLoop ].bSkillTraits[10] = tempProfiles[ uiLoop ].bNewSkillTrait11; + gMercProfiles[ uiLoop ].bSkillTraits[11] = tempProfiles[ uiLoop ].bNewSkillTrait12; + gMercProfiles[ uiLoop ].bSkillTraits[12] = tempProfiles[ uiLoop ].bNewSkillTrait13; + gMercProfiles[ uiLoop ].bSkillTraits[13] = tempProfiles[ uiLoop ].bNewSkillTrait14; + gMercProfiles[ uiLoop ].bSkillTraits[14] = tempProfiles[ uiLoop ].bNewSkillTrait15; + gMercProfiles[ uiLoop ].bSkillTraits[15] = tempProfiles[ uiLoop ].bNewSkillTrait16; + gMercProfiles[ uiLoop ].bSkillTraits[16] = tempProfiles[ uiLoop ].bNewSkillTrait17; + gMercProfiles[ uiLoop ].bSkillTraits[17] = tempProfiles[ uiLoop ].bNewSkillTrait18; + gMercProfiles[ uiLoop ].bSkillTraits[18] = tempProfiles[ uiLoop ].bNewSkillTrait19; + gMercProfiles[ uiLoop ].bSkillTraits[19] = tempProfiles[ uiLoop ].bNewSkillTrait20; + gMercProfiles[ uiLoop ].bSkillTraits[20] = tempProfiles[ uiLoop ].bNewSkillTrait21; + gMercProfiles[ uiLoop ].bSkillTraits[21] = tempProfiles[ uiLoop ].bNewSkillTrait22; + gMercProfiles[ uiLoop ].bSkillTraits[22] = tempProfiles[ uiLoop ].bNewSkillTrait23; + gMercProfiles[ uiLoop ].bSkillTraits[23] = tempProfiles[ uiLoop ].bNewSkillTrait24; + gMercProfiles[ uiLoop ].bSkillTraits[24] = tempProfiles[ uiLoop ].bNewSkillTrait25; + gMercProfiles[ uiLoop ].bSkillTraits[25] = tempProfiles[ uiLoop ].bNewSkillTrait26; + gMercProfiles[ uiLoop ].bSkillTraits[26] = tempProfiles[ uiLoop ].bNewSkillTrait27; + gMercProfiles[ uiLoop ].bSkillTraits[27] = tempProfiles[ uiLoop ].bNewSkillTrait28; + gMercProfiles[ uiLoop ].bSkillTraits[28] = tempProfiles[ uiLoop ].bNewSkillTrait29; + gMercProfiles[ uiLoop ].bSkillTraits[29] = tempProfiles[ uiLoop ].bNewSkillTrait30; + + // if we are out of skill number, make it no trait, otherwise set our trait right + for ( INT8 bCnt = 0; bCnt < 30; bCnt++ ) + { + if ( gMercProfiles[ uiLoop ].bSkillTraits[ bCnt ] >= NUM_SKILLTRAITS_NT || gMercProfiles[ uiLoop ].bSkillTraits[ bCnt ] < NO_SKILLTRAIT_NT ) + { + gMercProfiles[ uiLoop ].bSkillTraits[ bCnt ] = 0 ; + } + } + } + else + { + gMercProfiles[ uiLoop ].bSkillTraits[0] = tempProfiles[ uiLoop ].bOldSkillTrait; + gMercProfiles[ uiLoop ].bSkillTraits[1] = tempProfiles[ uiLoop ].bOldSkillTrait2; + + // if we have two same traits and cannot aquire expert level, ignore the second one + if( ( gMercProfiles[ uiLoop ].bSkillTraits[0] == ELECTRONICS_OT && gMercProfiles[ uiLoop ].bSkillTraits[1] == ELECTRONICS_OT ) || + ( gMercProfiles[ uiLoop ].bSkillTraits[0] == AMBIDEXT_OT && gMercProfiles[ uiLoop ].bSkillTraits[1] == AMBIDEXT_OT ) || + ( gMercProfiles[ uiLoop ].bSkillTraits[0] == CAMOUFLAGED_OT && gMercProfiles[ uiLoop ].bSkillTraits[1] == CAMOUFLAGED_OT ) ) + { + gMercProfiles[ uiLoop ].bSkillTraits[1] = 0 ; + } + + // if we are out of skill number, make it no trait, otherwise set our trait right + for ( INT8 bCnt = 0; bCnt < 30; bCnt++ ) + { + if ( gMercProfiles[ uiLoop ].bSkillTraits[ bCnt ] >= NUM_SKILLTRAITS_OT || gMercProfiles[ uiLoop ].bSkillTraits[ bCnt ] < NO_SKILLTRAIT_OT ) + { + gMercProfiles[ uiLoop ].bSkillTraits[ bCnt ] = 0 ; + } + } + } + ////////////////////////////////////////////////////////////////////////////////////// memcpy( &(gMercProfiles[ uiLoop ].bBuddy), &(tempProfiles[ uiLoop ].bBuddy), 5 * sizeof (INT8)); gMercProfiles[ uiLoop ].bLearnToLike = tempProfiles[ uiLoop ].bLearnToLike ; @@ -1776,6 +2349,82 @@ void OverwriteMercProfileWithXMLData( UINT32 uiLoop ) { gMercProfiles[ uiLoop ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_GOODGUY; } + + gMercProfiles[ uiLoop ].sSectorX = tempProfiles[uiLoop].sSectorX; + gMercProfiles[ uiLoop ].sSectorY = tempProfiles[uiLoop].sSectorY; + gMercProfiles[ uiLoop ].bSectorZ = tempProfiles[uiLoop].bSectorZ; + gMercProfiles[ uiLoop ].ubCivilianGroup = tempProfiles[uiLoop].ubCivilianGroup; + gMercProfiles[ uiLoop ].bTown = tempProfiles[uiLoop].bTown; + gMercProfiles[ uiLoop ].bTownAttachment = tempProfiles[uiLoop].bTownAttachment; + + //None + if ( tempProfiles[uiLoop].Type == 0 ) + { + //Reset + gMercProfiles[ uiLoop ].sSectorX = 0; + gMercProfiles[ uiLoop ].sSectorY = 0; + gMercProfiles[ uiLoop ].bSectorZ = 0; + gMercProfiles[ uiLoop ].bTown = 0; + gMercProfiles[ uiLoop ].bTownAttachment = 0; + } + + //AIM + if ( tempProfiles[uiLoop].Type == 1 ) + { + gProfilesAIM[ uiLoop ].ProfilId = uiLoop; + + //Reset + gMercProfiles[ uiLoop ].sSectorX = 0; + gMercProfiles[ uiLoop ].sSectorY = 0; + gMercProfiles[ uiLoop ].bSectorZ = 0; + gMercProfiles[ uiLoop ].bTown = 0; + gMercProfiles[ uiLoop ].bTownAttachment = 0; + } + + //MERC + if ( tempProfiles[uiLoop].Type == 2 ) + { + gProfilesMERC[ uiLoop ].ProfilId = uiLoop; + + //Reset + gMercProfiles[ uiLoop ].sSectorX = 0; + gMercProfiles[ uiLoop ].sSectorY = 0; + gMercProfiles[ uiLoop ].bSectorZ = 0; + gMercProfiles[ uiLoop ].bTown = 0; + gMercProfiles[ uiLoop ].bTownAttachment = 0; + } + + //RPC + if ( tempProfiles[uiLoop].Type == 3 ) + { + gProfilesRPC[ uiLoop ].ProfilId = uiLoop; + } + + //NPC + if ( tempProfiles[uiLoop].Type == 4 ) + { + gProfilesNPC[ uiLoop ].ProfilId = uiLoop; + } + + //Vehicle + if ( tempProfiles[uiLoop].Type == 5 ) + { + gProfilesVehicle[ uiLoop ].ProfilId = uiLoop; + } + + //IMP + if ( tempProfiles[uiLoop].Type == 6 ) + { + gProfilesIMP[ uiLoop ].ProfilId = uiLoop; + + //Reset + gMercProfiles[ uiLoop ].sSectorX = 0; + gMercProfiles[ uiLoop ].sSectorY = 0; + gMercProfiles[ uiLoop ].bSectorZ = 0; + gMercProfiles[ uiLoop ].bTown = 0; + gMercProfiles[ uiLoop ].bTownAttachment = 0; + } + } void OverwriteMercOpinionsWithXMLData( UINT32 uiLoop ) @@ -1787,3 +2436,165 @@ void OverwriteMercOpinionsWithXMLData( UINT32 uiLoop ) gMercProfiles[ uiLoop ].bMercOpinion[cnt] = tempProfiles[ uiLoop ].bMercOpinion[cnt] ; } } + +// SANDRO - added function +INT8 CheckMercsNearForCharTraits( UINT8 ubProfileID, INT8 bCharTraitID ) +{ + INT8 bNumber = 0; + UINT32 uiLoop; + SOLDIERTYPE * pSoldier; + SOLDIERTYPE * pTeammate; + BOOLEAN fOnlyOneException = FALSE; + + pSoldier = FindSoldierByProfileID( ubProfileID, FALSE ); + if (!pSoldier) + { + return( -1 ); + } + if( !(pSoldier->bActive) || !(pSoldier->bInSector) ) + { + return( -1 ); + } + + for ( uiLoop = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID; uiLoop < gTacticalStatus.Team[ pSoldier->bTeam ].bLastID; uiLoop++) + { + pTeammate = MercPtrs[ uiLoop ]; + if ( pTeammate == NULL ) + { + continue; + } + // Are we actually here? + if ( !(pTeammate->bActive) || !(pTeammate->bInSector) || ( pTeammate->flags.uiStatusFlags & SOLDIER_VEHICLE ) || (pTeammate->bAssignment == VEHICLE ) ) + { + // is nowhere around! + continue; + } + if ( pTeammate == pSoldier ) + { + continue; + } + // Are we from our team an dalive? + if ( pTeammate->bTeam == pSoldier->bTeam && pTeammate->stats.bLife >= OKLIFE ) + { + // Are we close enough? + if (PythSpacesAway( pSoldier->sGridNo, pTeammate->sGridNo ) <= 20) + { + switch ( bCharTraitID ) + { + // Sociable - we are OK with everyone except those wicked malicious guys + case CHAR_TRAIT_SOCIABLE: + if( gMercProfiles[ pTeammate->ubProfile ].bCharacterTrait != CHAR_TRAIT_MALICIOUS ) + bNumber++; + break; + // Loner can tolerate one other loner around + case CHAR_TRAIT_LONER: + if ( gMercProfiles[ pTeammate->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER && !fOnlyOneException ) + { + fOnlyOneException = TRUE; + } + else + { + bNumber++; + } + break; + // Show-off, depends on gender and appearance of others + case CHAR_TRAIT_SHOWOFF: + // If we are male + if ( gMercProfiles[ pSoldier->ubProfile ].ubBodyType <= STOCKYMALE ) + { + if ( gMercProfiles[ pTeammate->ubProfile ].ubBodyType == REGFEMALE ) + { + // Count as two if babe around! + if ( gMercProfiles[ pTeammate->ubProfile ].bAppearance == APPEARANCE_BABE ) + bNumber += 2; + // However remove one if ugly one + else if ( gMercProfiles[ pTeammate->ubProfile ].bAppearance == APPEARANCE_UGLY ) + bNumber--; + else + bNumber++; + } + } + // If we are female + else if ( gMercProfiles[ pSoldier->ubProfile ].ubBodyType == REGFEMALE ) + { + if ( gMercProfiles[ pTeammate->ubProfile ].ubBodyType <= STOCKYMALE ) + { + // Count as two if babe around! + if ( gMercProfiles[ pTeammate->ubProfile ].bAppearance == APPEARANCE_BABE ) + bNumber += 2; + // However remove one if ugly one + else if ( gMercProfiles[ pTeammate->ubProfile ].bAppearance == APPEARANCE_UGLY ) + bNumber--; + else + bNumber++; + } + } + break; + default: + bNumber++; + break; + } + } + } + } + + return( bNumber ); +} + +INT8 ProfileHasSkillTrait( INT32 ubProfileID, INT8 bSkillTrait ) +{ + INT8 bNumTraits = 0; + INT8 bNumMajorTraitsCounted = 0; + + // check old/new traits + if (gGameOptions.fNewTraitSystem) + { + for ( INT8 bCnt = 0; bCnt < gSkillTraitValues.ubMaxNumberOfTraits; bCnt++ ) + { + if ( bSkillTrait > 0 && bSkillTrait <= NUM_MAJOR_TRAITS ) + { + if ( gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] == bSkillTrait ) + { + bNumTraits++; + bNumMajorTraitsCounted++; + } + else if ( gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] > 0 && gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS ) + { + bNumMajorTraitsCounted++; + } + // if we exceeded the allowed number of major traits, ignore the rest of them + if ( bNumMajorTraitsCounted >= gSkillTraitValues.ubNumberOfMajorTraitsAllowed ) + { + break; + } + } + else + { + if ( gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] == bSkillTrait ) + { + bNumTraits++; + } + } + } + // cannot have more than 1 rade of minor traits or 2 grades of a major traits + if( bSkillTrait > NUM_MAJOR_TRAITS ) + return ( min(1, bNumTraits) ); + else + return ( min(2, bNumTraits) ); + } + else + { + if (gMercProfiles[ubProfileID].bSkillTraits[ 0 ] == bSkillTrait) + bNumTraits++; + if (gMercProfiles[ubProfileID].bSkillTraits[ 1 ] == bSkillTrait) + bNumTraits++; + + // Electronics, Ambidextrous and Camouflaged can only be of one grade + if( bSkillTrait == ELECTRONICS_OT || + bSkillTrait == AMBIDEXT_OT || + bSkillTrait == CAMOUFLAGED_OT ) + return ( min(1, bNumTraits) ); + else + return ( bNumTraits ); + } +} \ No newline at end of file diff --git a/Tactical/Soldier Profile.h b/Tactical/Soldier Profile.h index bd30c9c7..4f8fdad5 100644 --- a/Tactical/Soldier Profile.h +++ b/Tactical/Soldier Profile.h @@ -5,13 +5,36 @@ #include "Soldier Profile Type.h" #include "Merc Hiring.h" -extern INT8 gbSkillTraitBonus[NUM_SKILLTRAITS]; +typedef struct +{ + UINT16 uiIndex; + BOOLEAN Enabled; + INT8 BaseAttribute; + INT8 ExpLevel; + BOOLEAN RandomLife; + BOOLEAN RandomAgility; + BOOLEAN RandomLeadership; + BOOLEAN RandomDexterity; + BOOLEAN RandomWisdom; + BOOLEAN RandomMarksmanship; + BOOLEAN RandomMedical; + BOOLEAN RandomMechanical; + BOOLEAN RandomExplosive; + BOOLEAN RandomScientific; + BOOLEAN RandomStrength; + +} RANDOM_STATS_VALUES; + +extern RANDOM_STATS_VALUES gRandomStatsValue[NUM_PROFILES]; +extern void RandomStats (); + +extern INT8 gbSkillTraitBonus[NUM_SKILLTRAITS_OT]; extern UINT8 gubTerrorists[]; extern INT16 gsTerroristSector[][5][2]; extern BOOLEAN gfPotentialTeamChangeDuringDeath; extern MERCPROFILESTRUCT gMercProfiles[ NUM_PROFILES ]; -extern MERCPROFILEGEAR gMercProfileGear[ NUM_PROFILES ]; +extern MERCPROFILEGEAR gMercProfileGear[ NUM_PROFILES ][ NUM_MERCSTARTINGGEAR_KITS ]; #define AIM_AND_MERC_MERCS 51 // A.I.M. is 0-39, M.E.R.C.s are 40-50 @@ -19,6 +42,49 @@ extern MERCPROFILEGEAR gMercProfileGear[ NUM_PROFILES ]; //use this to sort out the above define BOOLEAN IsProfileIdAnAimOrMERCMerc( UINT8 ubProfileID ); //enums for the mercs + +//new profiles by Jazz------------------------------- +typedef struct +{ + UINT8 ProfilId; +} AIM_PROFIL; + +typedef struct +{ + UINT8 ProfilId; +} MERC_PROFIL; + +typedef struct +{ + UINT8 ProfilId; +} NPC_PROFIL; + +typedef struct +{ + UINT8 ProfilId; +} RPC_PROFIL; + +typedef struct +{ + UINT8 ProfilId; +} VEHICLE_PROFIL; + +typedef struct +{ + UINT8 ProfilId; +} IMP_PROFIL; + +extern AIM_PROFIL gProfilesAIM[ NUM_PROFILES ]; +extern MERC_PROFIL gProfilesMERC[ NUM_PROFILES ]; +extern NPC_PROFIL gProfilesNPC[ NUM_PROFILES ]; +extern RPC_PROFIL gProfilesRPC[ NUM_PROFILES ]; +extern VEHICLE_PROFIL gProfilesVehicle[ NUM_PROFILES ]; +extern IMP_PROFIL gProfilesIMP[NUM_PROFILES]; + +extern BOOLEAN SaveNewSystemMercsToSaveGameFile( HWFILE hFile ); +extern BOOLEAN LoadNewSystemMercsToSaveGameFile( HWFILE hFile ); +//--------------------------------------------------- + enum NPCIDs { BIFF = 40, @@ -158,6 +224,7 @@ enum NPCIDs TEX, BIGGENS, NPC169, + NPC170 = NPC169 + 84, } ; BOOLEAN LoadMercProfiles(void); @@ -184,6 +251,8 @@ void UpdateSoldierPointerDataIntoProfile( BOOLEAN fPlayerMercs ); // Returns true if a buddy of the merc is on team BOOLEAN DoesMercHaveABuddyOnTheTeam( UINT8 ubMercID ); +BOOLEAN MercIsHot( SOLDIERTYPE * pSoldier ); // added by SANDRO +BOOLEAN MercIsInTropicalSector( SOLDIERTYPE * pSoldier ); // added by SANDRO void StartSomeMercsOnAssignment( void ); @@ -221,7 +290,8 @@ typedef struct UINT32 uiBodyTypeSubFlags; INT8 bAttitude; - INT8 bPersonalityTrait; + INT8 bCharacterTrait; // added by SANDRO + INT8 bDisability; UINT8 ubNeedForSleep; INT8 bReputationTolerance; @@ -242,8 +312,40 @@ typedef struct INT8 bExpLevel; INT8 bEvolution; - INT8 bSkillTrait; - INT8 bSkillTrait2; + // changed by SANDRO + INT8 bOldSkillTrait; + INT8 bOldSkillTrait2; + // added by SANDRO + INT8 bNewSkillTrait1; + INT8 bNewSkillTrait2; + INT8 bNewSkillTrait3; + INT8 bNewSkillTrait4; + INT8 bNewSkillTrait5; + INT8 bNewSkillTrait6; + INT8 bNewSkillTrait7; + INT8 bNewSkillTrait8; + INT8 bNewSkillTrait9; + INT8 bNewSkillTrait10; + INT8 bNewSkillTrait11; + INT8 bNewSkillTrait12; + INT8 bNewSkillTrait13; + INT8 bNewSkillTrait14; + INT8 bNewSkillTrait15; + INT8 bNewSkillTrait16; + INT8 bNewSkillTrait17; + INT8 bNewSkillTrait18; + INT8 bNewSkillTrait19; + INT8 bNewSkillTrait20; + INT8 bNewSkillTrait21; + INT8 bNewSkillTrait22; + INT8 bNewSkillTrait23; + INT8 bNewSkillTrait24; + INT8 bNewSkillTrait25; + INT8 bNewSkillTrait26; + INT8 bNewSkillTrait27; + INT8 bNewSkillTrait28; + INT8 bNewSkillTrait29; + INT8 bNewSkillTrait30; INT8 bBuddy[5]; INT8 bLearnToLike; @@ -271,6 +373,15 @@ typedef struct UINT16 usApproachFactor[4]; INT8 bMercOpinion[75]; + + UINT32 Type; + + UINT16 sSectorX; + UINT16 sSectorY; + INT8 bSectorZ; + UINT8 ubCivilianGroup; + INT8 bTown; + INT8 bTownAttachment; } TEMPPROFILETYPE; @@ -282,4 +393,8 @@ extern BOOLEAN WriteMercOpinions(); void OverwriteMercProfileWithXMLData( UINT32 uiLoop ); void OverwriteMercOpinionsWithXMLData( UINT32 uiLoop ); +// SANDRO - added functions +INT8 CheckMercsNearForCharTraits( UINT8 ubProfileID, INT8 bCharTraitID ); +INT8 ProfileHasSkillTrait( INT32 ubProfileID, INT8 bSkillTrait ); + #endif diff --git a/Tactical/SoldierTooltips.cpp b/Tactical/SoldierTooltips.cpp index 6f3bde11..434d8a3a 100644 --- a/Tactical/SoldierTooltips.cpp +++ b/Tactical/SoldierTooltips.cpp @@ -21,6 +21,9 @@ #include "vsurface.h" #include "line.h" #include "los.h" +// added by SANDRO +#include "SkillCheck.h" +#include "soldier profile type.h" #endif //forward declarations of common classes to eliminate includes @@ -90,17 +93,19 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier ) } //SCORE: If UDT range, we work it out as half actual LOS - if ( gGameExternalOptions.gfAllowUDTRange ) + // SANDRO - don't use this if detail set to debug! + if ( gGameExternalOptions.gfAllowUDTRange && gGameExternalOptions.ubSoldierTooltipDetailLevel != DL_Debug && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS) ) { uiMaxTooltipDistance = (UINT32)( MercPtrs[ gusSelectedSoldier ]->GetMaxDistanceVisible(MercPtrs[ gusUIFullTargetID ]->sGridNo, 0, CALC_FROM_WANTED_DIR) * (gGameExternalOptions.ubUDTModifier)); uiMaxTooltipDistance /= 100; } //SCORE: Otherwise if we're using dynamics then do this - else if ( gGameExternalOptions.fEnableDynamicSoldierTooltips ) + // SANDRO - don't use this if detail set to debug! + else if ( gGameExternalOptions.fEnableDynamicSoldierTooltips && gGameExternalOptions.ubSoldierTooltipDetailLevel != DL_Debug && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS) ) { OBJECTTYPE* pObject = &(MercPtrs[gusSelectedSoldier]->inv[HANDPOS]); for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) { - if ( Item[iter->usItem].visionrangebonus > 0 ) + if ( Item[iter->usItem].visionrangebonus > 0 && iter->exists()) { fMercIsUsingScope = TRUE; break; @@ -120,7 +125,7 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier ) if (gGameExternalOptions.fEnableDynamicSoldierTooltips && fMercIsUsingScope == 0 && !gGameExternalOptions.gfAllowUDTRange) { // add 10% to max tooltip viewing distance per level of the merc - uiMaxTooltipDistance *= 1 + (MercPtrs[ gusSelectedSoldier ]->stats.bExpLevel / 10); + uiMaxTooltipDistance *= 1 + (EffectiveExpLevel(MercPtrs[ gusSelectedSoldier ])/ 10); // SANDRO - changed to effective level calc if ( gGameExternalOptions.gfAllowLimitedVision ) uiMaxTooltipDistance *= 1 - (gGameExternalOptions.ubVisDistDecreasePerRainIntensity / 100); @@ -134,7 +139,8 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier ) } } //SCORE: Dynamic detail, otherwise do what we usually do - if ( gGameExternalOptions.gfAllowUDTDetail ) + // SANDRO - don't use this if detail set to debug! + if ( gGameExternalOptions.gfAllowUDTDetail && gGameExternalOptions.ubSoldierTooltipDetailLevel != DL_Debug && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS) ) { //Check range. Less than a third? Full. Less than 2 thirds? Basic. Otherwise Limited. if ( iRangeToTarget <= (INT32)(uiMaxTooltipDistance / 3) ) @@ -212,6 +218,52 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier ) swprintf( pStrInfo, gzTooltipStrings[STR_TT_CAT_CURRENT_APS], pStrInfo, pSoldier->bActionPoints ); if ( gGameExternalOptions.fEnableSoldierTooltipHealth ) swprintf( pStrInfo, gzTooltipStrings[STR_TT_CAT_CURRENT_HEALTH], pStrInfo, pSoldier->stats.bLife ); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Added by SANDRO - show enemy skills + if ( gGameExternalOptions.fEnableSoldierTooltipTraits ) + { + if ( gGameOptions.fNewTraitSystem ) + { + if (( pSoldier->stats.ubSkillTraits[0] == pSoldier->stats.ubSkillTraits[1] ) && pSoldier->stats.ubSkillTraits[0] != 0 ) + { + CHAR16 pStrAux[50]; + swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]]); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1] + 19] ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2]] ); + //swprintf( pStrInfo, L"%s\n", pStrInfo ); + } + else if (( pSoldier->stats.ubSkillTraits[1] == pSoldier->stats.ubSkillTraits[2] ) && pSoldier->stats.ubSkillTraits[1] != 0 ) + { + CHAR16 pStrAux[50]; + swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]]); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + 19] ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]] ); + } + else if (( pSoldier->stats.ubSkillTraits[0] == pSoldier->stats.ubSkillTraits[2] ) && pSoldier->stats.ubSkillTraits[0] != 0 ) + { + CHAR16 pStrAux[50]; + swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]]); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + 19] ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]] ); + } + else + { + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]] ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]] ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2]] ); + } + } + else + { + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, gzMercSkillText[pSoldier->stats.ubSkillTraits[0]] ); + swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillText[pSoldier->stats.ubSkillTraits[1]] ); + } + } + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } // armor info code block start @@ -453,28 +505,30 @@ void DisplayWeaponInfo( SOLDIERTYPE* pSoldier, CHAR16* pStrInfo, UINT8 ubSlot, U { // display weapon attachments for (attachmentList::iterator iter = pSoldier->inv[ubSlot][0]->attachments.begin(); iter != pSoldier->inv[ubSlot][0]->attachments.end(); ++iter) { - if ( ubTooltipDetailLevel == DL_Basic ) - { - // display only externally-visible weapon attachments - if ( !Item[iter->usItem].hiddenattachment ) + if(iter->exists()){ + if ( ubTooltipDetailLevel == DL_Basic ) { - fDisplayAttachment = TRUE; + // display only externally-visible weapon attachments + if ( !Item[iter->usItem].hiddenattachment ) + { + fDisplayAttachment = TRUE; + } } - } - else - { - // display all weapon attachments - fDisplayAttachment = TRUE; - } - if ( fDisplayAttachment ) - { - iNumAttachments++; - if ( iNumAttachments == 1 ) - wcscat( pStrInfo, L"\n[" ); else - wcscat( pStrInfo, L", " ); - wcscat( pStrInfo, ItemNames[ iter->usItem ] ); - fDisplayAttachment = FALSE; // clear flag for next loop iteration + { + // display all weapon attachments + fDisplayAttachment = TRUE; + } + if ( fDisplayAttachment ) + { + iNumAttachments++; + if ( iNumAttachments == 1 ) + wcscat( pStrInfo, L"\n[" ); + else + wcscat( pStrInfo, L", " ); + wcscat( pStrInfo, ItemNames[ iter->usItem ] ); + fDisplayAttachment = FALSE; // clear flag for next loop iteration + } } } // for if ( iNumAttachments > 0 ) diff --git a/Tactical/Structure Wrap.cpp b/Tactical/Structure Wrap.cpp index d14e12fb..84adb941 100644 --- a/Tactical/Structure Wrap.cpp +++ b/Tactical/Structure Wrap.cpp @@ -19,6 +19,88 @@ extern BOOLEAN DoesSAMExistHere( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, +//----------------legion by Jazz + +BOOLEAN IsJumpableWindowPresentAtGridNo( INT32 sGridNo, INT8 direction2 ) +{ + STRUCTURE * pStructure; + + pStructure = FindStructure( sGridNo, STRUCTURE_WALLNWINDOW ); + + if ( pStructure ) + { + + if ( ( direction2 == SOUTH || direction2 == NORTH ) && (pStructure->ubWallOrientation == OUTSIDE_TOP_LEFT || pStructure->ubWallOrientation == INSIDE_TOP_LEFT ) && pStructure->fFlags & STRUCTURE_WALLNWINDOW && !(pStructure->fFlags & STRUCTURE_SPECIAL) && ( pStructure->fFlags & STRUCTURE_OPEN ) ) + { + return( TRUE ); + } + + if ( ( direction2 == EAST || direction2 == WEST ) && ( pStructure->ubWallOrientation == OUTSIDE_TOP_RIGHT || pStructure->ubWallOrientation == INSIDE_TOP_RIGHT ) && pStructure->fFlags & STRUCTURE_WALLNWINDOW && !(pStructure->fFlags & STRUCTURE_SPECIAL) && ( pStructure->fFlags & STRUCTURE_OPEN ) ) + { + return( TRUE ); + } + } + + return( FALSE ); +} + + +BOOLEAN IsOknoFencePresentAtGridno( INT32 sGridNo ) +{ + + STRUCTURE * pStructure; + + pStructure = FindStructure( sGridNo, STRUCTURE_WALLNWINDOW ); + + if ( pStructure ) + { + if ( pStructure->fFlags & STRUCTURE_WALLNWINDOW && !(pStructure->fFlags & STRUCTURE_SPECIAL) && ( pStructure->fFlags & STRUCTURE_OPEN ) ) + { + return( TRUE ); + } + } + +/* STRUCTURE * pStructure; + STRUCTURE * pStructure2; + + pStructure = FindStructure( sGridNo, STRUCTURE_WALLNWINDOW ); + + if ( pStructure ) + { + // pStructure2 = FindStructure( sGridNo, STRUCTURE_WALL ); + // if ( !pStructure2 ) + // { + if ( pStructure->fFlags & STRUCTURE_WALLNWINDOW && !(pStructure->fFlags & STRUCTURE_SPECIAL) && ( pStructure->fFlags & STRUCTURE_OPEN )) + { + return( TRUE ); + } + + // } + + } + + */ + return( FALSE ); +} + +BOOLEAN IsLegionFencePresentAtGridno( INT32 sGridNo ) +{ + STRUCTURE * pStructure; + + pStructure = FindStructure( sGridNo, STRUCTURE_FENCE ); + + if ( pStructure ) + { + + if ( pStructure->fFlags & STRUCTURE_FENCE ) // && (pStructure->fFlags & STRUCTURE_SPECIAL))//&& !(pStructure->fFlags & STRUCTURE_SPECIAL) && ( pStructure->fFlags & STRUCTURE_OPEN )) + { + return( TRUE ); + } + } + return( FALSE ); +} +//------------------------------------------------------------------------------------- + BOOLEAN IsFencePresentAtGridNo( INT32 sGridNo ) { if ( FindStructure( sGridNo, STRUCTURE_ANYFENCE ) != NULL ) @@ -567,4 +649,4 @@ BOOLEAN SetOpenableStructureToClosed( INT32 sGridNo, UINT8 ubLevel ) } // else leave it as is! return( TRUE ); -} +} \ No newline at end of file diff --git a/Tactical/Structure Wrap.h b/Tactical/Structure Wrap.h index c527bf46..fd540b5b 100644 --- a/Tactical/Structure Wrap.h +++ b/Tactical/Structure Wrap.h @@ -48,4 +48,8 @@ BOOLEAN IsCorpseAtGridNo( INT32 sGridNo, UINT8 ubLevel ); BOOLEAN SetOpenableStructureToClosed( INT32 sGridNo, UINT8 ubLevel ); -#endif +//Legion by Jazz +BOOLEAN IsJumpableWindowPresentAtGridNo( INT32 sGridNo , INT8 direction2 ); //legion 2 Windows +BOOLEAN IsLegionFencePresentAtGridno( INT32 sGridNo ); //legion 2 Fence + +#endif \ No newline at end of file diff --git a/Tactical/Tactical Save.cpp b/Tactical/Tactical Save.cpp index 2f81036d..c67a4171 100644 --- a/Tactical/Tactical Save.cpp +++ b/Tactical/Tactical Save.cpp @@ -48,7 +48,7 @@ #include "Map Screen Interface Map Inventory.h" #endif -#include "VFS/vfs.h" +#include BOOLEAN gfWasInMeanwhile = FALSE; @@ -2299,7 +2299,9 @@ BOOLEAN InitTempNpcQuoteInfoForNPCFromTempFile() //loop through all the npc accounts and write the temp array to disk - for( usCnt1=0; usCnt1< ( GASTON-FIRST_RPC ); usCnt1++) + //for( usCnt1=0; usCnt1< ( GASTON-FIRST_RPC ); usCnt1++) + //new profiles by Jazz + for( usCnt1=0; usCnt1< NUM_PROFILES; usCnt1++) { memset( TempNpcQuote, 0, uiSizeOfTempArray ); @@ -2686,6 +2688,16 @@ BOOLEAN SetSectorFlag( INT16 sMapX, INT16 sMapY, UINT8 bMapZ, UINT32 uiFlagToSet // visited enough to count as an active day UpdateLastDayOfPlayerActivity( (UINT16) GetWorldDay() ); } + + for ( UINT8 i = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; i <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; i++ ) + { + if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->stats.bLife && !(MercPtrs[ i ]->flags.uiStatusFlags & SOLDIER_VEHICLE) && MercPtrs[ i ]->ubProfile != NO_PROFILE && + MercPtrs[ i ]->sSectorX == sMapX && MercPtrs[ i ]->sSectorY == sMapY && MercPtrs[ i ]->bSectorZ == bMapZ && !MercPtrs[ i ]->flags.fBetweenSectors && + MercPtrs[ i ]->bAssignment != IN_TRANSIT && MercPtrs[ i ]->bAssignment != ASSIGNMENT_DEAD ) + { + gMercProfiles[ MercPtrs[ i ]->ubProfile ].records.usSectorsDiscovered++; + } + } } } diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj new file mode 100644 index 00000000..2b212b48 --- /dev/null +++ b/Tactical/Tactical_VS2005.vcproj @@ -0,0 +1,1135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index 106bb7cc..251a8fce 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -1,7 +1,7 @@ @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -995,10 +995,18 @@ RelativePath="XML_Attachments.cpp" > + + + + @@ -1027,6 +1035,14 @@ RelativePath="XML_EnemyMiscDrops.cpp" > + + + + @@ -1039,6 +1055,10 @@ RelativePath="XML_Explosive.cpp" > + + @@ -1079,10 +1099,26 @@ RelativePath=".\XML_Profiles.cpp" > + + + + + + + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj new file mode 100644 index 00000000..8ca6690a --- /dev/null +++ b/Tactical/Tactical_VS2010.vcxproj @@ -0,0 +1,409 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {433FBCC4-F612-489C-AA28-CCD6CF27D80C} + Win32Proj + Tactical + Tactical + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters new file mode 100644 index 00000000..0bf039a5 --- /dev/null +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -0,0 +1,603 @@ + + + + + {b76e83a9-042b-4267-96e0-ffd42052b5d5} + + + {c1880088-a976-405e-919e-9f1e97ad6701} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Tactical/TeamTurns.cpp b/Tactical/TeamTurns.cpp index 73002e9e..2c5fe004 100644 --- a/Tactical/TeamTurns.cpp +++ b/Tactical/TeamTurns.cpp @@ -56,7 +56,6 @@ class OBJECTTYPE; class SOLDIERTYPE; #include "connect.h" -//#include "test_space.h" extern INT8 STRAIGHT; //extern UINT8 gubSpeedUpAnimationFactor; @@ -1023,9 +1022,12 @@ void EndInterrupt( BOOLEAN fMarkInterruptOccurred ) // resume interrupted interrupt //hayden - if (!is_networked) { + if (!is_networked) + { StartInterrupt(); - } else { + } + else + { UINT8 nubFirstInterrupter; INT8 nbTeam; SOLDIERTYPE * npSoldier; @@ -1043,22 +1045,23 @@ void EndInterrupt( BOOLEAN fMarkInterruptOccurred ) } else if(is_server && gTacticalStatus.ubCurrentTeam == 1)// against ai { - //hayden - send_interrupt( npSoldier ); // - if(nbTeam !=0)intAI(npSoldier); - else StartInterrupt();// - //requestAIint( npSoldier ); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"AI is interrupted"); + send_interrupt( npSoldier ); + + if(nbTeam !=0) + intAI(npSoldier); + else + StartInterrupt(); + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"AI is interrupted"); } else { - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for another team"); //may need more work. + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for another team"); //may need more work. //ClearIntList(); //hayden StartInterrupt(); send_interrupt( npSoldier ); // - } } @@ -1565,7 +1568,7 @@ BOOLEAN StandardInterruptConditionsMet( SOLDIERTYPE * pSoldier, UINT8 ubOpponent // if the soldier isn't currently crouching if (!PTR_CROUCHED) { - ubMinPtsNeeded = APBPConstants[AP_CROUCH]; + ubMinPtsNeeded = GetAPsCrouch(pSoldier, TRUE); // Changed from APBPConstants[AP_CROUCH] - SANDRO } else { @@ -1685,7 +1688,7 @@ INT8 CalcInterruptDuelPts( SOLDIERTYPE * pSoldier, UINT8 ubOpponentID, BOOLEAN f { if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) )) { - iPoints=(iPoints+WEAPON_READIED_BONUS); + iPoints=(iPoints + cWeaponReadyBonus); } } @@ -1734,13 +1737,33 @@ INT8 CalcInterruptDuelPts( SOLDIERTYPE * pSoldier, UINT8 ubOpponentID, BOOLEAN f iPoints -= 2; } - if ( HAS_SKILL_TRAIT( pSoldier, NIGHTOPS ) ) + if (gGameOptions.fNewTraitSystem) // new/old traits check - SANDRO { - bLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel); - if (bLightLevel > NORMAL_LIGHTLEVEL_DAY + 3) + if ( HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT ) ) { - // it's dark, give a bonus for interrupts - iPoints += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS ); + bLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel); + if (bLightLevel > NORMAL_LIGHTLEVEL_DAY + 3) + { + // it's dark, give a bonus for interrupts + iPoints += gSkillTraitValues.ubNOIterruptsBonusInDark; + } + } + // Phlegmatics get a small penalty to interrupts + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_PHLEGMATIC ) + { + iPoints -= 1; + } + } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT ) ) + { + bLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel); + if (bLightLevel > NORMAL_LIGHTLEVEL_DAY + 3) + { + // it's dark, give a bonus for interrupts + iPoints += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT ); + } } } @@ -2059,9 +2082,12 @@ void DoneAddingToIntList( SOLDIERTYPE * pSoldier, BOOLEAN fChange, UINT8 ubInter } else { - if (!is_networked) { + if (!is_networked) + { StartInterrupt(); - } else { + } + else + { UINT8 nubFirstInterrupter; INT8 nbTeam; SOLDIERTYPE * npSoldier; @@ -2072,34 +2098,41 @@ void DoneAddingToIntList( SOLDIERTYPE * pSoldier, BOOLEAN fChange, UINT8 ubInter // INTERRUPT is calculated on the server if ((nbTeam > 0) && (nbTeam <6 ) && is_server) //is for AI and are server - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for AI team"); - - // Only display the top message if we (the server) got interrupted - if (pSoldier->bTeam == 0) - AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, TeamTurnString[ nbTeam ] ); + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for AI team"); + + // Only display the top message if we (the server) got interrupted + if (pSoldier->bTeam == 0) + AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, TeamTurnString[ nbTeam ] ); - send_interrupt( npSoldier ); - StartInterrupt(); + send_interrupt( npSoldier ); + StartInterrupt(); - } + } // INTERRUPT is calculated on the server else if(is_server && gTacticalStatus.ubCurrentTeam == 1)// against ai - { - - //hayden - send_interrupt( npSoldier ); // - if(nbTeam !=0)intAI(npSoldier); - else StartInterrupt();// - //requestAIint( npSoldier ); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"AI is interrupted"); - } + { + //hayden + send_interrupt( npSoldier ); // + if(nbTeam !=0) + intAI(npSoldier); + else + StartInterrupt();// + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"AI is interrupted"); + } // INTERRUPT is calculated on the pure client else if(gTacticalStatus.ubCurrentTeam == 0)//its our turn (we are moving) { +#ifdef BETAVERSION + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for another team - pure client - skipping problematic interrupt"); +#endif + + /* // Only send interrupt if we (the client) got interrupted send_interrupt( npSoldier ); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for another team"); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"interrupt for another team - PROBLEMATIC"); SOLDIERTYPE* pMerc = MercPtrs[ gusSelectedSoldier ]; //AdjustNoAPToFinishMove( pMerc, TRUE ); @@ -2110,6 +2143,7 @@ void DoneAddingToIntList( SOLDIERTYPE * pSoldier, BOOLEAN fChange, UINT8 ubInter fInterfacePanelDirty = DIRTYLEVEL2; AddTopMessage( COMPUTER_INTERRUPT_MESSAGE, TeamTurnString[ nbTeam ] ); gTacticalStatus.fInterruptOccurred = TRUE; + */ } else { diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp index 98bda533..52909be5 100644 --- a/Tactical/Turn Based Input.cpp +++ b/Tactical/Turn Based Input.cpp @@ -134,6 +134,9 @@ extern SOLDIERTYPE *gpSMCurrentMerc; extern INT32 gsOverItemsGridNo; extern INT16 gsOverItemsLevel; extern BOOLEAN gfUIShowExitSouth; +extern BOOLEAN fMiddleButtonDown; +extern BOOLEAN fX1ButtonDown; +extern BOOLEAN fX2ButtonDown; extern INT32 giStartingMemValue; @@ -149,7 +152,7 @@ extern UINT32 guiVObjectSize; extern UINT32 guiVSurfaceSize; extern BOOLEAN gfNextShotKills; - +BOOLEAN fAutofireBulletsMode = FALSE; // HEADROCK HAM 4: Track whether we're adjusting aim or number of bullets UINT32 guiSoldierFlags; UINT32 guiUITargetSoldierId = NOBODY; @@ -185,7 +188,7 @@ SOLDIERTYPE *gpExchangeSoldier2; BOOLEAN ConfirmActionCancel( INT32 usMapPos, INT32 usOldMapPos ); BOOLEAN gfNextFireJam = FALSE; - +INT16 brstmode = 0; //dddd extern INT16 ITEMDESC_START_X; extern INT16 ITEMDESC_START_Y; #include "fresh_header.h" @@ -249,10 +252,19 @@ extern void DetermineWhichMilitiaControlMenusCanBeShown( void ); //lalien // The_Bob - real time sneaking, 01-06-09 extern BOOLEAN WeSeeNoOne(void); // Needed to control entering turn-based with ctrl-x +void QueryTBMButton( UINT32 *puiNewEvent ); +void QueryTBWheel( UINT32 *puiNewEvent ); +void QueryTBX1Button( UINT32 *puiNewEvent ); +void QueryTBX2Button( UINT32 *puiNewEvent ); + void GetTBMouseButtonInput( UINT32 *puiNewEvent ) { QueryTBLeftButton( puiNewEvent ); QueryTBRightButton( puiNewEvent ); + QueryTBWheel( puiNewEvent ); + QueryTBMButton( puiNewEvent ); + QueryTBX1Button( puiNewEvent ); + QueryTBX2Button( puiNewEvent ); } void QueryTBLeftButton( UINT32 *puiNewEvent ) @@ -636,6 +648,8 @@ void QueryTBLeftButton( UINT32 *puiNewEvent ) { // ATE: Reset refine aim.. pSoldier->aiData.bShownAimTime = 0; + // HEADROCK HAM 4: Reset Autofire Bullets mode. + fAutofireBulletsMode = FALSE; if ( gsCurrentActionPoints == 0 ) { @@ -655,6 +669,13 @@ void QueryTBLeftButton( UINT32 *puiNewEvent ) case CONFIRM_ACTION_MODE: + // HEADROCK HAM 4: If in Autofire Mode, first click puts us in bullet adjust mode. + if (UsingNewCTHSystem() == true && GetSoldier( &pSoldier, gusSelectedSoldier )) + if (pSoldier->bDoAutofire && !fAutofireBulletsMode) + fAutofireBulletsMode = TRUE; + else + *puiNewEvent = CA_MERC_SHOOT; + else *puiNewEvent = CA_MERC_SHOOT; break; @@ -1104,6 +1125,8 @@ void GetTBMousePositionInput( UINT32 *puiNewEvent ) if ( MercPtrs[ gusUIFullTargetID ]->bTeam != gbPlayerNum ) { fOnValidGuy = TRUE; + //ddd , \ ( ) + brstmode = 0; } else { @@ -1380,31 +1403,30 @@ void GetPolledKeyboardInput( UINT32 *puiNewEvent ) } - if( _KeyDown( DEL ) ) + if( _KeyDown( DEL ) && !fDeleteDown) { - DisplayCover(TRUE); + SwitchToEnemyView(); fDeleteDown = TRUE; } if( !_KeyDown( DEL ) && fDeleteDown ) { - //EMPTY + SwitchViewOff(); fDeleteDown = FALSE; } - if( _KeyDown( END ) ) + if( _KeyDown( END ) && !fEndDown) { - //EMPTY + SwitchToMercView(); fEndDown = TRUE; } if( !_KeyDown( END ) && fEndDown ) { - //EMPTY - SwitchCoverDrawMode(); + SwitchViewOff(); fEndDown = FALSE; } @@ -1607,23 +1629,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } } } - - - - if ((InputEvent.usEvent == KEY_DOWN )&& ( InputEvent.usParam == '0') ) - { - //if( InputEvent.usKeyState & ALT_DOWN ) - { - if ( !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) ) - { - test_func2(); - } - } - } - - - if ((InputEvent.usEvent == KEY_DOWN )&& ( InputEvent.usParam == 'e') ) { @@ -2306,18 +2312,10 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) case '9': ChangeCurrentSquad( 8 ); - - if (is_networked) - cheat_func(); - break; - + case '0': ChangeCurrentSquad( 9 ); - - if (is_networked) - //test_func2(); - break; - + case 'x': if ( !fCtrl && !fAlt ) @@ -2370,7 +2368,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) if (!is_networked) { // ctrl-x: enter turn based while sneaking - check if RT sneak is on, iw we're not already in combat and if we actually see any enemies - if (gGameExternalOptions.fAllowRealTimeSneak) + if (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK]) // changed by SANDRO { BOOLEAN fSneakingInRealTime = true; @@ -2400,9 +2398,10 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) { if (!is_networked) { - if (gGameExternalOptions.fAllowRealTimeSneak) + // SANDRO - changed the real time sneak switch to be in the preferences + if (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK]) { - gGameExternalOptions.fAllowRealTimeSneak = false; + gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] = false; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_RTM_SNEAKING_OFF]); if( !WeSeeNoOne() ) // if we're sneaking up on someone, enter turn-based @@ -2410,7 +2409,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } else { - gGameExternalOptions.fAllowRealTimeSneak = true; + gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] = true; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_RTM_SNEAKING_ON]); } } @@ -2579,10 +2578,28 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } } break; - + case 'J': case 'j': + if ( fShift ) + { + INT8 bDirection; - if( fAlt ) + if (gGameExternalOptions.fCanJumpThroughWindows == TRUE ) + { + SOLDIERTYPE *lSoldier; + + if ( GetSoldier( &lSoldier, gusSelectedSoldier ) ) + { + if ( FindWindowJumpDirection( lSoldier, lSoldier->sGridNo, lSoldier->ubDirection, &bDirection ) ) + { + lSoldier->BeginSoldierClimbWindow( ); + } + + } + + } + } + else if( fAlt ) { if ( CHEATER_CHEAT_LEVEL( ) ) { @@ -2598,6 +2615,47 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } #endif } + //ddd{ . +// else if(_KeyDown( SHIFT )) +// { +//INT16 sGridNo; +//STRUCTURE * pStructure; + +//GetMouseMapPos( &sGridNo ); +//ScreenMsg( FONT_MCOLOR_LTYELLOW,0, L"gubMerkCanSeeThisTile=%d,gubWorldTileInLight=%d,los=%d",gubMerkCanSeeThisTile[sGridNo],gubWorldTileInLight[sGridNo],gGameSettings.ubSizeOfLOS); +// + + // SOLDIERTYPE *pjSoldier; + // BOOLEAN fNearHeigherLevel; + // BOOLEAN fNearLowerLevel; + // INT8 bDirection; + + // if ( GetSoldier( &pjSoldier, gusSelectedSoldier ) ) + // { + // // CHRISL: Turn off manual jumping while wearing a backpack + // if(UsingNewInventorySystem() == true && pjSoldier->inv[BPACKPOCKPOS].exists() == true) + // break; + + // // Make sure the merc is not collapsed! + // if (!IsValidStance(pjSoldier, ANIM_CROUCH) ) + // { + // if ( pjSoldier->bCollapsed && pjSoldier->bBreath < OKBREATH ) + // { + // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pjSoldier->name ); + // } + + // break; + // } + // GetMercOknoDirection( pjSoldier->ubID, &fNearLowerLevel, &fNearHeigherLevel ); + // if ( FindOknoDirection( pjSoldier, pjSoldier->sGridNo, pjSoldier->ubDirection, &bDirection ) ) + // { + // BeginSoldierOkno( pjSoldier ); + // } + + + // } + + //}//ddd} else { SOLDIERTYPE *pjSoldier; @@ -2637,6 +2695,14 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) { pjSoldier->BeginSoldierClimbFence( ); } + + if (gGameExternalOptions.fCanClimbOnWalls == TRUE ) + { + if ( FindFenceDirection( pjSoldier, pjSoldier->sGridNo, pjSoldier->ubDirection, &bDirection ) ) + { + pjSoldier->BeginSoldierFence( ); + } + } } } break; @@ -2735,6 +2801,9 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } break; + case 'C': + ToggleEnemyView(); + break; case 'd': if( gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT ) { @@ -2911,16 +2980,27 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) break; case 'D': - if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) + // SANDRO - changed from drop all to enable soldier tooltips + if ( gGameSettings.fOptions[ TOPTION_ALLOW_SOLDIER_TOOLTIPS ] ) { - gGameSettings.fOptions[TOPTION_DROP_ALL] = FALSE; - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_DROP_ALL_OFF ] ); + gGameSettings.fOptions[ TOPTION_ALLOW_SOLDIER_TOOLTIPS ] = FALSE; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_SOLDIER_TOOLTIPS_OFF ] ); } else { - gGameSettings.fOptions[TOPTION_DROP_ALL] = TRUE; - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_DROP_ALL_ON ] ); + gGameSettings.fOptions[ TOPTION_ALLOW_SOLDIER_TOOLTIPS ] = TRUE; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_SOLDIER_TOOLTIPS_ON ] ); } + // if ( gGameSettings.fOptions[TOPTION_DROP_ALL] ) + // { + // gGameSettings.fOptions[TOPTION_DROP_ALL] = FALSE; + // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_DROP_ALL_OFF ] ); + // } + // else + // { + // gGameSettings.fOptions[TOPTION_DROP_ALL] = TRUE; + // ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_DROP_ALL_ON ] ); + // } break; case 'q': if ( gGameSettings.fOptions[TOPTION_GL_HIGH_ANGLE] ) @@ -3593,6 +3673,11 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } } } + //CHRISL: if not enough ammo in sector, reload using ammo carried in inventory + if ( (*pGun)[0]->data.gun.ubGunShotsLeft < GetMagSize( pGun ) ) + { + AutoReload( pTeamSoldier ); + } } } } @@ -3872,6 +3957,8 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) // Get life back pSoldier->stats.bLife = pSoldier->stats.bLifeMax; pSoldier->bBleeding = 0; + // SANDRO - erase insta-healable injury + pSoldier->iHealableInjury = 0; fInterfacePanelDirty = DIRTYLEVEL2; } @@ -3906,9 +3993,13 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) DisplayGameSettings( ); break; + + case 'V': + ToggleMercView(); + break; + case 'w': case 'W': - if( fAlt ) { if ( CHEATER_CHEAT_LEVEL( ) ) @@ -5099,7 +5190,7 @@ void HandleHandCursorClick( INT32 usMapPos, UINT32 *puiNewEvent ) } // Steal! - sAPCost = GetAPsToStealItem( pSoldier, sActionGridNo ); + sAPCost = GetAPsToStealItem( pSoldier, MercPtrs[ gusUIFullTargetID ], sActionGridNo ); // SANDRO - added target variable if ( EnoughPoints( pSoldier, sAPCost, 0, TRUE ) ) { @@ -5699,35 +5790,40 @@ void PopupMilitiaControlMenu( SOLDIERTYPE *pSoldier ) INT32 PickPocket(MERCPROFILESTRUCT *pProfile, UINT8 ppStart, UINT8 ppStop, UINT16 usItem, UINT8 iNumber, UINT8 * cap); -bool BadGoggles(SOLDIERTYPE *pTeamSoldier) { +bool BadGoggles(SOLDIERTYPE *pTeamSoldier) +{ // WDS - Smart goggle switching // NOTE: Investigate using GetItemVisionRangeBonus from Items.cpp??? - if (!gGameExternalOptions.smartGoggleSwitch) { + if (!gGameExternalOptions.smartGoggleSwitch) return false; - } else { + else + { // Look through the head slots and find any sort of goggle. Check if it is bad for this time of day. - for (int headSlot = HEAD1POS; headSlot <= HEAD2POS; ++headSlot) { - if ( (Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus > 0) && !DayTime() ) { - return true; - } else if ( (Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus > 0) && DayTime() ) { - return true; + // silversurfer: also check if we are underground, sun goggles and night vision bonus are useless underground + for (int headSlot = HEAD1POS; headSlot <= HEAD2POS; ++headSlot) + { + // check if we are below ground + if ( pTeamSoldier->bSectorZ > 0 ) + { + // we don't want a cave vision penalty + if ( Item[pTeamSoldier->inv[headSlot].usItem].cavevisionrangebonus < 0 ) + return true; } - } - - // Find the best goggles for the current time of day anywhere in inventory - OBJECTTYPE * pGoggles = 0; - if (DayTime()) { - pGoggles = FindSunGogglesInInv( pTeamSoldier, TRUE ); - } else { - pGoggles = FindNightGogglesInInv( pTeamSoldier, TRUE ); - } - - if (pGoggles) { - // Check that the player is actually wearing them - for (int headSlot = HEAD1POS; headSlot <= HEAD2POS; ++headSlot) { - if (!(pTeamSoldier->inv[headSlot] == *pGoggles)) { -// return true; + + // if we are above ground + else + { + // at night we don't want a night vision penalty + if ( NightTime() ) + { + if ( Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus < 0 ) + return true; } + // at daytime we don't want a day vision penalty + // also if we have a bright light penalty make sure that is doesn't exceed the day vision bonus + else if ( Item[pTeamSoldier->inv[headSlot].usItem].dayvisionrangebonus < 0 || + ( Item[pTeamSoldier->inv[headSlot].usItem].dayvisionrangebonus + Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus ) < 0 ) + return true; } } } @@ -5745,12 +5841,22 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) for (int headSlot = HEAD1POS; headSlot <= HEAD2POS; ++headSlot) { - if ( (Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus > 0) ) + if ( (Item[pTeamSoldier->inv[headSlot].usItem].brightlightvisionrangebonus != 0) ) { slotToUse = headSlot; break; } - else if ( (Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus > 0) ) + if ( (Item[pTeamSoldier->inv[headSlot].usItem].dayvisionrangebonus != 0) ) + { + slotToUse = headSlot; + break; + } + else if ( (Item[pTeamSoldier->inv[headSlot].usItem].nightvisionrangebonus != 0) ) + { + slotToUse = headSlot; + break; + } + else if ( (Item[pTeamSoldier->inv[headSlot].usItem].cavevisionrangebonus != 0) ) { slotToUse = headSlot; break; @@ -5768,8 +5874,9 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) } // Find the best goggles for the current time of day anywhere in inventory + // silversurfer: also check if underground OBJECTTYPE * pGoggles = 0; - if (DayTime()) + if (DayTime() && pTeamSoldier->bSectorZ == 0) { pGoggles = FindSunGogglesInInv( pTeamSoldier, TRUE ); } @@ -5795,8 +5902,8 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) // No goggles to equip, should the current ones be unequiped? if (pTeamSoldier->inv[slotToUse].exists()) { - if ((DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].nightvisionrangebonus > 0)) || - (!DayTime() && (Item[pTeamSoldier->inv[slotToUse].usItem].brightlightvisionrangebonus > 0))) + if ((DayTime() && Item[pTeamSoldier->inv[slotToUse].usItem].nightvisionrangebonus > 0 && pTeamSoldier->bSectorZ == 0) || + ((!DayTime() || pTeamSoldier->bSectorZ > 0) && (Item[pTeamSoldier->inv[slotToUse].usItem].brightlightvisionrangebonus > 0))) { // It's day and we're wearing night goggles (or vice-versa), find a place to stash them if (pTeamSoldier->inv[ HELMETPOS ].exists()) @@ -5807,32 +5914,36 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) } else { + /* //If we're here we already know we can't attach, don't we? // Try dumping it anywhere in inventory because it doesn't attach to the helmet - if (ValidAttachment( pTeamSoldier->inv[slotToUse].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && + if (NASValidAttachment( pTeamSoldier->inv[slotToUse].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && pTeamSoldier->inv[slotToUse][0]->attachments.size() < MAX_ATTACHMENTS) { pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE, 0 ); } else - { + */ + //{ // Remove sungoggles. PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE); - } + //} } } else { + /* //again useless? // Try dumping it anywhere in inventory given there's no helemt - if (ValidAttachment( pTeamSoldier->inv[slotToUse].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && + if (NASValidAttachment( pTeamSoldier->inv[slotToUse].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && pTeamSoldier->inv[slotToUse][0]->attachments.size() < MAX_ATTACHMENTS) { pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE, 0 ); } else - { + */ + //{ // Remove sungoggles. PlaceInAnyPocket(pTeamSoldier, &pTeamSoldier->inv[slotToUse], FALSE); - } + //} } } } @@ -5877,7 +5988,7 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) pObj = &(pTeamSoldier->inv[gear]); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE ) + if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists()) { pGoggles = &(*iter); bestBonus = Item[ iter->usItem ].nightvisionrangebonus; @@ -5893,11 +6004,12 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) // wearing, to avoid situations where a character refuses to remove the wrong set of goggles and // thus suffers a penalty. else - { - if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && - pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + { //WarmSteel - This has become more complicated to check, it's better to just try and see if it works. + //if (NASValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && + // pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS ) + if (pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ) ) { - pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ); + //pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ); break; } else @@ -5941,11 +6053,11 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) // wearing, to avoid situations where a character refuses to remove the wrong set of goggles and // thus suffers a penalty. else - { - if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && - pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + { //WarmSteel - Again, better to just try and see if it works. + //if (NASValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && + // pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + if (pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 )) { - pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ); break; } else @@ -5966,6 +6078,7 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) pObj = &(pTeamSoldier->inv[gear]); for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { + if(iter->exists()){ if(DayTime() == TRUE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE) { pGoggles = &(*iter); @@ -5976,6 +6089,7 @@ void SwapGoggles(SOLDIERTYPE *pTeamSoldier) pGoggles = &(*iter); bestBonus = Item[iter->usItem].nightvisionrangebonus; } + } } if(pGoggles) { @@ -6057,7 +6171,7 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision) pObj = &(pTeamSoldier->inv[gear]); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE ) + if ( Item[ iter->usItem ].nightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists()) { pGoggles = &(*iter); bestBonus = Item[ iter->usItem ].nightvisionrangebonus; @@ -6070,11 +6184,11 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision) break; } else if (Item[pTeamSoldier->inv[bSlot1].usItem].nightvisionrangebonus <= 0) - { - if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && - pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + { //WarmSteel - just try and see if it works + //if (NASValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && + // pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + if ( pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ) ) { - pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ); break; } else @@ -6105,7 +6219,7 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision) pObj = &(pTeamSoldier->inv[gear]); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE ) + if ( Item[ iter->usItem ].brightlightvisionrangebonus > bestBonus && Item[ iter->usItem ].usItemClass == IC_FACE && iter->exists()) { pGoggles = &(*iter); bestBonus = Item[ iter->usItem ].brightlightvisionrangebonus; @@ -6118,11 +6232,11 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision) break; } else if (Item[pTeamSoldier->inv[bSlot1].usItem].brightlightvisionrangebonus <= 0) - { - if (ValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && - pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + { //WarmSteel - try + //if (NASValidAttachment( pTeamSoldier->inv[bSlot1].usItem, pTeamSoldier->inv[HELMETPOS].usItem ) && + // pTeamSoldier->inv[bSlot1][0]->attachments.size() < MAX_ATTACHMENTS) + if ( pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ) ) { - pTeamSoldier->inv[HELMETPOS].AttachObject( pTeamSoldier, &pTeamSoldier->inv[bSlot1], FALSE, 0 ); break; } else @@ -6144,15 +6258,17 @@ void SwapGogglesUniformly(SOLDIERTYPE *pTeamSoldier, BOOLEAN fToNightVision) pObj = &(pTeamSoldier->inv[gear]); for(attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if(fToNightVision == FALSE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE) - { - pGoggles = &(*iter); - bestBonus = Item[iter->usItem].brightlightvisionrangebonus; - } - else if(fToNightVision == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE) - { - pGoggles = &(*iter); - bestBonus = Item[iter->usItem].nightvisionrangebonus; + if(iter->exists()){ + if(fToNightVision == FALSE && Item[iter->usItem].brightlightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE) + { + pGoggles = &(*iter); + bestBonus = Item[iter->usItem].brightlightvisionrangebonus; + } + else if(fToNightVision == TRUE && Item[iter->usItem].nightvisionrangebonus > bestBonus && Item[iter->usItem].usItemClass == IC_FACE) + { + pGoggles = &(*iter); + bestBonus = Item[iter->usItem].nightvisionrangebonus; + } } } if(pGoggles) @@ -6214,6 +6330,9 @@ void SeperateItems() } //remove attachments + //WarmSteel - This causes a crash when unloading attachments, then sorting, then selling all items in the sector in the map screen. + //It is likely to be caused here because when i accidentally broke this part the bug didn't occur. + //TODO : fix this. if ( gGameExternalOptions.gfShiftFRemoveAttachments == TRUE ) { //CHRISL: We run into a problem here because GetFreeWorldItemIndex, which gets called @@ -6227,6 +6346,8 @@ void SeperateItems() while(gWorldItems[uiLoop].object[x]->attachments.size() != cnt) { gTempObject = *gWorldItems[uiLoop].object[x]->GetAttachmentAtIndex(cnt); + + //WarmSteel - This actually still works with NAS, be it by accident if (gWorldItems[ uiLoop ].object.RemoveAttachment(&gTempObject,0,x)) { AddItemToPool( gWorldItems[ uiLoop ].sGridNo, &gTempObject, 1, gWorldItems[ uiLoop ].ubLevel, WORLD_ITEM_REACHABLE , -1 ); @@ -6236,6 +6357,7 @@ void SeperateItems() { cnt++; } + uiLoopCnt ++; if(uiLoopCnt > 100) break; @@ -6327,4 +6449,309 @@ void StackAndSort( BOOLEAN fRestrictToAmmo ) //HandleAllReachAbleItemsInTheSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pImpButtonText[11] ); } -} \ No newline at end of file +} + + + +void QueryTBMButton( UINT32 *puiNewEvent ) +{ + INT32 sMapPos; + + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + + if (gViewportRegion.ButtonState & MSYS_MIDDLE_BUTTON) // MID MOUSE BUTTON + { + if ( !fMiddleButtonDown ) + { + fMiddleButtonDown = TRUE; + //RESETCOUNTER( RMOUSECLICK_DELAY_COUNTER ); + } + } + else if ( fMiddleButtonDown ) + { + if ( _KeyDown( ALT ) ) + { + // + if ( ( gpItemPointer == NULL ) && + ( ( gsCurInterfacePanel != SM_PANEL ) || ( ButtonList[ iSMPanelButtons[ BURSTMODE_BUTTON ] ]->uiFlags & BUTTON_ENABLED ) ) ) + SetBurstMode(); + } + else + {//*puiNewEvent = LC_LOOK; + if(gCurrentUIMode == CONFIRM_ACTION_MODE) + brstmode=(brstmode==1)?0:1; + else{ + ErasePath( TRUE ); + *puiNewEvent = LC_ON_TERRAIN; + } + } + + fMiddleButtonDown = FALSE; + // Reset counter + //RESETCOUNTER( RMOUSECLICK_DELAY_COUNTER ); + } + } +}//void QueryTBMButton( UINT32 *puiNewEvent ) + +void QueryTBWheel( UINT32 *puiNewEvent ) +{ + SOLDIERTYPE *pSoldier; + INT32 usMapPos=0; + UINT8 bID; + + // stub + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if ( gViewportRegion.WheelState != 0 ) + { + //printf("wheel %d\n", gViewportRegion.WheelState); + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"wheel %d", gViewportRegion.WheelState); + if ( gpItemPointer == NULL ) + { + // ATE: + if ( gusSelectedSoldier != NOBODY ) + { + // Switch on UI mode + switch( gCurrentUIMode ) + { + + case MOVE_MODE: + case CONFIRM_MOVE_MODE: + + if ( !( gTacticalStatus.uiFlags & ENGAGED_IN_CONV ) && + ( ( gsCurInterfacePanel != SM_PANEL ) || ( ButtonList[ iSMPanelButtons[ NEXTMERC_BUTTON ] ]->uiFlags & BUTTON_ENABLED ) ) ) + { + if ( gViewportRegion.WheelState > 0 ) + { + //change stance ->DOWN + if ( _KeyDown( ALT ) ) + { if ( (gusSelectedSoldier != NOBODY) && ( gpItemPointer == NULL ) ) + GotoLowerStance(MercPtrs[ gusSelectedSoldier ]); + break; + } + if ( gusSelectedSoldier != NOBODY ) + { + bID = FindPrevActiveAndAliveMerc( MercPtrs[ gusSelectedSoldier ], TRUE, TRUE ); + HandleLocateSelectMerc( bID, LOCATEANDSELECT_MERC ); + // Center to guy.... + LocateSoldier( gusSelectedSoldier, SETLOCATOR ); + } + } + else + { + + //change stance ->UP + if ( _KeyDown( ALT ) ) + { if ( (gusSelectedSoldier != NOBODY) && ( gpItemPointer == NULL ) ) + GotoHeigherStance( MercPtrs[ gusSelectedSoldier ] ); + break; + } + + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"wheel %d", gViewportRegion.WheelState); + if ( gusSelectedSoldier != NOBODY ) + { //Select next merc + bID = FindNextMercInTeamPanel( MercPtrs[ gusSelectedSoldier ], FALSE, FALSE ); + HandleLocateSelectMerc( bID, LOCATEANDSELECT_MERC ); + // Center to guy.... + LocateSoldier( gusSelectedSoldier, SETLOCATOR ); + } + } + //*puiNewEvent = M_ON_TERRAIN; ???????????????? + } + + case IDLE_MODE: + case ACTION_MODE: + case LOCKOURTURN_UI_MODE: + case LOOKCURSOR_MODE: + case LOCKUI_MODE: + case TALKCURSOR_MODE: + case MENU_MODE: + case HANDCURSOR_MODE: + + break; + + case CONFIRM_ACTION_MODE: + + if ( GetSoldier( &pSoldier, gusSelectedSoldier ) ) + { + if( gGameExternalOptions.bAimedBurstEnabled ) + HandleWheelAdjustCursor( pSoldier, usMapPos, -gViewportRegion.WheelState,brstmode ); + else + HandleWheelAdjustCursorWOAB( pSoldier, usMapPos, -gViewportRegion.WheelState); + } + break; + } + } + } + ResetWheelState( &gViewportRegion ); + } + } +} + +void QueryTBX1Button( UINT32 *puiNewEvent ) +{ + INT32 sMapPos; + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + + if (gViewportRegion.ButtonState & MSYS_X1_BUTTON) // MID MOUSE BUTTON + { + if ( !fX1ButtonDown ) + { + fX1ButtonDown = TRUE; + //RESETCOUNTER( RMOUSECLICK_DELAY_COUNTER ); + } + } + else if ( fX1ButtonDown ) + { + //*puiNewEvent = LC_LOOK; + fX1ButtonDown = FALSE; + if ( !_KeyDown( ALT ) && !_KeyDown( SHIFT )) + UIHandleChangeLevel( NULL ); + else if( _KeyDown( SHIFT ) ) + { + SOLDIERTYPE *pjSoldier; + BOOLEAN fNearHeigherLevel; + BOOLEAN fNearLowerLevel; + INT8 bDirection; + + if ( GetSoldier( &pjSoldier, gusSelectedSoldier ) ) + { + // CHRISL: Turn off manual jumping while wearing a backpack + if(UsingNewInventorySystem() == true && pjSoldier->inv[BPACKPOCKPOS].exists() == true) + return; + + // Make sure the merc is not collapsed! + if (!IsValidStance(pjSoldier, ANIM_CROUCH) ) + { + if ( pjSoldier->bCollapsed && pjSoldier->bBreath < OKBREATH ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pjSoldier->name ); + } + + return; + } + GetMercOknoDirection( pjSoldier->ubID, &fNearLowerLevel, &fNearHeigherLevel ); + if ( FindWindowJumpDirection( pjSoldier, pjSoldier->sGridNo, pjSoldier->ubDirection, &bDirection ) ) + { + pjSoldier->BeginSoldierClimbWindow(); + } + + + } + } + else if (_KeyDown( ALT ) ) + { + SOLDIERTYPE *pjSoldier; + if ( GetSoldier( &pjSoldier, gusSelectedSoldier ) ) + { + BOOLEAN fNearHeigherLevel; + BOOLEAN fNearLowerLevel; + INT8 bDirection; + // CHRISL: Turn off manual jumping while wearing a backpack + if(UsingNewInventorySystem() == true && pjSoldier->inv[BPACKPOCKPOS].exists() == true) + return; + + // Make sure the merc is not collapsed! + if (!IsValidStance(pjSoldier, ANIM_CROUCH) ) + { + if ( pjSoldier->bCollapsed && pjSoldier->bBreath < OKBREATH ) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 4 ], pjSoldier->name ); + return; + } + + GetMercClimbDirection( pjSoldier->ubID, &fNearLowerLevel, &fNearHeigherLevel ); + + if ( fNearLowerLevel ) + pjSoldier->BeginSoldierClimbDownRoof( ); + + if ( fNearHeigherLevel ) + pjSoldier->BeginSoldierClimbUpRoof( ); + + if ( FindFenceJumpDirection( pjSoldier, pjSoldier->sGridNo, pjSoldier->ubDirection, &bDirection ) ) + pjSoldier->BeginSoldierClimbFence( ); + } + + }//else + + } + } +} +void QueryTBX2Button( UINT32 *puiNewEvent ) +{ + INT32 sMapPos; + if ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) + { + if (!GetMouseMapPos( &sMapPos ) ) + return; + + if (gViewportRegion.ButtonState & MSYS_X2_BUTTON) // MID MOUSE BUTTON + { + if ( !fX2ButtonDown ) + { + fX2ButtonDown = TRUE; + //RESETCOUNTER( RMOUSECLICK_DELAY_COUNTER ); + } + } + else if ( fX2ButtonDown ) + { + fX2ButtonDown = FALSE; + + if ( _KeyDown( ALT ) ) + AutoReload( MercPtrs[ gusSelectedSoldier ] ); + else + // Toggle squad's stealth mode..... + // For each guy on squad... + { + SOLDIERTYPE *pTeamSoldier; + INT8 bLoop; + BOOLEAN fStealthOn = FALSE; + + // Check if at least one guy is on stealth.... + for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++) + { + if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) ) + { + if ( pTeamSoldier->bStealthMode ) + { + fStealthOn = TRUE; + } + } + } + + fStealthOn = !fStealthOn; + + for (bLoop=gTacticalStatus.Team[gbPlayerNum].bFirstID, pTeamSoldier=MercPtrs[bLoop]; bLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; bLoop++, pTeamSoldier++) + { + if ( OK_CONTROLLABLE_MERC( pTeamSoldier ) && pTeamSoldier->bAssignment == CurrentSquad( ) && !AM_A_ROBOT( pTeamSoldier ) ) + { + if ( gpSMCurrentMerc != NULL && bLoop == gpSMCurrentMerc->ubID ) + { + gfUIStanceDifferent = TRUE; + } + + pTeamSoldier->bStealthMode = fStealthOn; + } + } + + fInterfacePanelDirty = DIRTYLEVEL2; + + // OK, display message + if ( fStealthOn ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_SQUAD_ON_STEALTHMODE ] ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMessageStrings[ MSG_SQUAD_OFF_STEALTHMODE ] ); + } + } + } + + } +} diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp index 0479d085..a7da93ab 100644 --- a/Tactical/UI Cursors.cpp +++ b/Tactical/UI Cursors.cpp @@ -29,6 +29,8 @@ #include "GameSettings.h" #include "Interactive Tiles.h" #include "PATHAI.H" + #include "SkillCheck.h" // added by SANDRO + #include "message.H" //ddd #endif //forward declarations of common classes to eliminate includes @@ -334,7 +336,8 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA UINT16 reverse = 0; - UINT8 maxAimLevels = AllowedAimingLevels(pSoldier); + // HEADROCK HAM 4: Required for new Aiming Level Limit function + UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, usMapPos); usInHand = pSoldier->inv[ HANDPOS ].usItem; @@ -579,26 +582,83 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA // and also a Targetted Bodypart indicator. if(pSoldier->bDoAutofire == 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ]) { - if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) + if(UsingNewCTHSystem() == true) { - // Burst mode only - OBJECTTYPE * pInHand; - pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); - // Burst size - gbCtHBurstCount = GetShotsPerBurst(pInHand); - UINT8 i, saveDoBurst; - // Save original burst value (should be 1 always, before the burst has been fired, but - // this is just a failsafe - saveDoBurst = pSoldier->bDoBurst; + //AXP 29.03.2007: Rooftop CtH fix. See below. + INT8 bTempTargetLevel = pSoldier->bTargetLevel; + pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; - // For each bullet in the burst - for (i=0;iaiData.bShownAimTime, pSoldier->bAimShotLocation ); + // HEADROCK HAM B2.7: CTH approximation? + if (gGameExternalOptions.fApproximateCTH) + { + uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); + } + gfUICtHBar = TRUE; + gCTHDisplay.MuzzleSwayPercentage = (gCTHDisplay.MuzzleSwayPercentage + uiHitChance)/2; + gCTHDisplay.iShooterGridNo = pSoldier->sGridNo; + gCTHDisplay.iTargetGridNo = usMapPos; + + // Calculate distance to target + FLOAT dDeltaX = (FLOAT)(CenterX( pSoldier->sGridNo ) - CenterX( usMapPos )); + FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos )); + FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY)); + + CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime ); + + pSoldier->bTargetLevel = bTempTargetLevel; + } + else + { + if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) + { + // Burst mode only + OBJECTTYPE * pInHand; + pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); + // Burst size + gbCtHBurstCount = GetShotsPerBurst(pInHand); + UINT8 i, saveDoBurst; + // Save original burst value (should be 1 always, before the burst has been fired, but + // this is just a failsafe + saveDoBurst = pSoldier->bDoBurst; + + // For each bullet in the burst + for (i=0;ibTargetLevel; + pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; + + // Calculate hit chance (using the current bDoBurst for burst-penalty calculations) + UINT32 uiHitChance; + uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); + // HEADROCK HAM B2.7: CTH approximation? + if (gGameExternalOptions.fApproximateCTH) + { + uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); + } + + pSoldier->bTargetLevel = bTempTargetLevel; + + // Put result (burst CTH) into the array + gbCtH[i] = (gbCtH[i]+uiHitChance)/2; + + // Increase burst size, so that the next time we run CalcChanceToHitGun we'll get a lower + // result, based on our Burst Penalty + pSoldier->bDoBurst++; + } + // Reset original burst status + pSoldier->bDoBurst = saveDoBurst; + // Activate CTH bar display + gfUICtHBar = TRUE; + } + else // One "BASE CTH" bar, JA2 1.13 vanilla { //AXP 29.03.2007: Rooftop CtH fix. See below. INT8 bTempTargetLevel = pSoldier->bTargetLevel; pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; - // Calculate hit chance (using the current bDoBurst for burst-penalty calculations) UINT32 uiHitChance; uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); // HEADROCK HAM B2.7: CTH approximation? @@ -609,37 +669,10 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA pSoldier->bTargetLevel = bTempTargetLevel; - // Put result (burst CTH) into the array - gbCtH[i] = (gbCtH[i]+uiHitChance)/2; - - // Increase burst size, so that the next time we run CalcChanceToHitGun we'll get a lower - // result, based on our Burst Penalty - pSoldier->bDoBurst++; + gfUICtHBar = TRUE; + gbCtH[0] = (gbCtH[0]+uiHitChance)/2; + gbCtHBurstCount = 1; } - // Reset original burst status - pSoldier->bDoBurst = saveDoBurst; - // Activate CTH bar display - gfUICtHBar = TRUE; - } - else // One "BASE CTH" bar, JA2 1.13 vanilla - { - //AXP 29.03.2007: Rooftop CtH fix. See below. - INT8 bTempTargetLevel = pSoldier->bTargetLevel; - pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; - - UINT32 uiHitChance; - uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); - // HEADROCK HAM B2.7: CTH approximation? - if (gGameExternalOptions.fApproximateCTH) - { - uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); - } - - pSoldier->bTargetLevel = bTempTargetLevel; - - gfUICtHBar = TRUE; - gbCtH[0] = (gbCtH[0]+uiHitChance)/2; - gbCtHBurstCount = 1; } } @@ -648,17 +681,15 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA else if(pSoldier->bDoAutofire > 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ]) { - if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) + if(UsingNewCTHSystem() == true) { - gbCtHBurstCount = 1; - //AXP 29.03.2007: Rooftop CtH fix. See below. INT8 bTempTargetLevel = pSoldier->bTargetLevel; pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; - + UINT32 uiHitChance; // Calculate CTH for the first bullet - uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); + uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, pSoldier->aiData.bShownAimTime, pSoldier->bAimShotLocation ); // HEADROCK HAM B2.7: CTH approximation? if (gGameExternalOptions.fApproximateCTH) { @@ -666,31 +697,68 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA } // CTH for the first bullet is entered into this array, and later displayed - gbCtH[0] = (gbCtH[0]+uiHitChance)/2; + gCTHDisplay.MuzzleSwayPercentage = (gCTHDisplay.MuzzleSwayPercentage + uiHitChance)/2; + gCTHDisplay.iShooterGridNo = pSoldier->sGridNo; + gCTHDisplay.iTargetGridNo = usMapPos; - // Fool the CTH formula into thinking we're already firing the last bullet in the volley, - // by artificially altering bDoBurst (which tracks actual burst progression). The CTH formula - // calculates Auto Penalty based on bDoBurst - (Autopen * (bDoBurst-1), basically). - UINT8 saveDoBurst = pSoldier->bDoBurst; - pSoldier->bDoBurst = pSoldier->bDoAutofire; - - uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); - // HEADROCK HAM B2.7: CTH approximation? - if (gGameExternalOptions.fApproximateCTH) - { - uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); - } + // Flag to tell the program to draw two CTH bars. + gfUICtHBar = TRUE; + + // Calculate distance to target + FLOAT dDeltaX = (FLOAT)(CenterX( pSoldier->sGridNo ) - CenterX( usMapPos )); + FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos )); + FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY)); + + CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime ); pSoldier->bTargetLevel = bTempTargetLevel; - // Return Burst State to original value - pSoldier->bDoBurst = saveDoBurst; + } + else + { + if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) + { + gbCtHBurstCount = 1; - // CTH for the last bullet is entered into this array and later displayed. - gbCtH[1] = (gbCtH[1]+uiHitChance)/2; - - // Flag to tell the program to draw two CTH bars. - gbCtHAutoFire = TRUE; - gfUICtHBar = TRUE; + //AXP 29.03.2007: Rooftop CtH fix. See below. + INT8 bTempTargetLevel = pSoldier->bTargetLevel; + pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; + + UINT32 uiHitChance; + // Calculate CTH for the first bullet + uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); + // HEADROCK HAM B2.7: CTH approximation? + if (gGameExternalOptions.fApproximateCTH) + { + uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); + } + + // CTH for the first bullet is entered into this array, and later displayed + gbCtH[0] = (gbCtH[0]+uiHitChance)/2; + + // Fool the CTH formula into thinking we're already firing the last bullet in the volley, + // by artificially altering bDoBurst (which tracks actual burst progression). The CTH formula + // calculates Auto Penalty based on bDoBurst - (Autopen * (bDoBurst-1), basically). + UINT8 saveDoBurst = pSoldier->bDoBurst; + pSoldier->bDoBurst = pSoldier->bDoAutofire; + + uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, 0, pSoldier->bAimShotLocation ); + // HEADROCK HAM B2.7: CTH approximation? + if (gGameExternalOptions.fApproximateCTH) + { + uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); + } + + pSoldier->bTargetLevel = bTempTargetLevel; + // Return Burst State to original value + pSoldier->bDoBurst = saveDoBurst; + + // CTH for the last bullet is entered into this array and later displayed. + gbCtH[1] = (gbCtH[1]+uiHitChance)/2; + + // Flag to tell the program to draw two CTH bars. + gbCtHAutoFire = TRUE; + gfUICtHBar = TRUE; + } } } } @@ -706,20 +774,54 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA pSoldier->bTargetLevel = (INT8) gsInterfaceLevel; UINT32 uiHitChance; - uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation ); + // SANDRO - precise calculation for throwing knives added + if(UsingNewCTHSystem() == true) + { + uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation ); + } + else + { + if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE ) + { + uiHitChance = CalcThrownChanceToHit( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation ); + } + else + { + uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation ); + } + } // HEADROCK HAM B2.7: CTH approximation? if (gGameExternalOptions.fApproximateCTH) { uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance ); } + if(UsingNewCTHSystem() == true) + { + gfUICtHBar = TRUE; + + // CTH for the first bullet is entered into this array, and later displayed + gCTHDisplay.MuzzleSwayPercentage = (gCTHDisplay.MuzzleSwayPercentage + uiHitChance)/2; + gCTHDisplay.iShooterGridNo = pSoldier->sGridNo; + gCTHDisplay.iTargetGridNo = usMapPos; + + // Calculate distance to target + FLOAT dDeltaX = (FLOAT)(CenterX( pSoldier->sGridNo ) - CenterX( usMapPos )); + FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos )); + FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY)); + + CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime ); + } + pSoldier->bTargetLevel = bTempTargetLevel; - gfUICtHBar = TRUE; - gbCtHBurstCount = 1; - gbCtH[0] = (gbCtH[0]+uiHitChance)/2; + if(UsingNewCTHSystem() == false) + { + gfUICtHBar = TRUE; + gbCtHBurstCount = 1; + gbCtH[0] = (gbCtH[0]+uiHitChance)/2; + } } - switchVal = pSoldier->aiData.bShownAimTime; switch( switchVal ) @@ -1512,7 +1614,8 @@ UINT8 HandleKnifeCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivate } } - bFutureAim = (INT8)( REFINE_KNIFE_2 ); + // SANDRO - changed this + bFutureAim = (INT8)( gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : REFINE_KNIFE_2 ); sAPCosts = CalcTotalAPsToAttack( pSoldier, sGridNo, TRUE, (INT8)(bFutureAim / 2) ); @@ -1545,46 +1648,45 @@ UINT8 HandleKnifeCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivate } - switch( pSoldier->aiData.bShownAimTime ) + ////////////////////////////////////////////////////////////// + // SANDRO - slightly changed the formula here + if( pSoldier->aiData.bShownAimTime == REFINE_KNIFE_1 ) { - case REFINE_KNIFE_1: - - if ( gfDisplayFullCountRing ) - { - return( KNIFE_YELLOW_AIM1_UICURSOR ); - } - else if ( fEnoughPoints ) - { - return( KNIFE_HIT_AIM1_UICURSOR ); - } - else - { - return( KNIFE_NOGO_AIM1_UICURSOR ); - } - break; - - case REFINE_KNIFE_2: - - if ( gfDisplayFullCountRing ) - { - return( KNIFE_YELLOW_AIM2_UICURSOR ); - } - else if ( fEnoughPoints ) - { - return( KNIFE_HIT_AIM2_UICURSOR ); - } - else - { - return( KNIFE_NOGO_AIM2_UICURSOR ); - } - break; - - default: - Assert( FALSE ); - // no return value! - return(0); - break; + if ( gfDisplayFullCountRing ) + { + return( KNIFE_YELLOW_AIM1_UICURSOR ); + } + else if ( fEnoughPoints ) + { + return( KNIFE_HIT_AIM1_UICURSOR ); + } + else + { + return( KNIFE_NOGO_AIM1_UICURSOR ); + } } + else if( pSoldier->aiData.bShownAimTime == ( gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : REFINE_KNIFE_2 ) ) + { + if ( gfDisplayFullCountRing ) + { + return( KNIFE_YELLOW_AIM2_UICURSOR ); + } + else if ( fEnoughPoints ) + { + return( KNIFE_HIT_AIM2_UICURSOR ); + } + else + { + return( KNIFE_NOGO_AIM2_UICURSOR ); + } + } + else + { + Assert( FALSE ); + // no return value! + return(0); + } + ////////////////////////////////////////////////////////////// } else { @@ -1666,52 +1768,52 @@ UINT8 HandlePunchCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivate PlayJA2Sample( TARG_REFINE_BEEP, RATE_11025, MIDVOLUME, 1, MIDDLEPAN ); } - pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2; + // SANDRO - make aimed punch less expensive for APS + pSoldier->aiData.bShownAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : REFINE_PUNCH_2); } } } - switch( pSoldier->aiData.bShownAimTime ) + ////////////////////////////////////////////////////////////// + // SANDRO - slightly changed the formula here + if( pSoldier->aiData.bShownAimTime == REFINE_PUNCH_1) { - case REFINE_PUNCH_1: - - if ( gfDisplayFullCountRing ) - { - return( ACTION_PUNCH_YELLOW_AIM1_UICURSOR ); - } - else if ( fEnoughPoints ) - { - return( ACTION_PUNCH_RED_AIM1_UICURSOR ); - } - else - { - return( ACTION_PUNCH_NOGO_AIM1_UICURSOR ); - } - break; - - case REFINE_PUNCH_2: - - if ( gfDisplayFullCountRing ) - { - return( ACTION_PUNCH_YELLOW_AIM2_UICURSOR ); - } - else if ( fEnoughPoints ) - { - return( ACTION_PUNCH_RED_AIM2_UICURSOR ); - } - else - { - return( ACTION_PUNCH_NOGO_AIM2_UICURSOR ); - } - break; - - default: - Assert( FALSE ); - // no return value! - return(0); - break; + if ( gfDisplayFullCountRing ) + { + return( ACTION_PUNCH_YELLOW_AIM1_UICURSOR ); + } + else if ( fEnoughPoints ) + { + return( ACTION_PUNCH_RED_AIM1_UICURSOR ); + } + else + { + return( ACTION_PUNCH_NOGO_AIM1_UICURSOR ); + } } + else if ( pSoldier->aiData.bShownAimTime == (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : REFINE_PUNCH_2) ) + { + if ( gfDisplayFullCountRing ) + { + return( ACTION_PUNCH_YELLOW_AIM2_UICURSOR ); + } + else if ( fEnoughPoints ) + { + return( ACTION_PUNCH_RED_AIM2_UICURSOR ); + } + else + { + return( ACTION_PUNCH_NOGO_AIM2_UICURSOR ); + } + } + else + { + Assert( FALSE ); + // no return value! + return(0); + } + ////////////////////////////////////////////////////////////// } else { @@ -1859,7 +1961,7 @@ UINT8 HandleNonActivatedTossCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEA // Do we have a launcable? pObj = &(pSoldier->inv[HANDPOS]); for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV ) + if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV && iter->exists()) { pObject = &(*iter); break; @@ -2087,11 +2189,15 @@ void HandleLeftClickCursor( SOLDIERTYPE *pSoldier ) if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) ) { pSoldier->aiData.bShownAimTime = REFINE_AIM_1; + // HEADROCK HAM 4: Reset Bullet Count for Autofire + fAutofireBulletsMode = FALSE; pSoldier->flags.fPauseAim = FALSE; } else { pSoldier->aiData.bShownAimTime = REFINE_AIM_1; + // HEADROCK HAM 4: Reset Bullet Count for Autofire + fAutofireBulletsMode = FALSE; pSoldier->flags.fPauseAim = FALSE; } // Reset counter @@ -2156,15 +2262,19 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) INT8 bFutureAim; UINT8 ubCursor; SOLDIERTYPE *pTSoldier; - INT32 sGridNo; + INT32 sGridNo; INT8 bTargetLevel; + // SANDRO - added these two + INT8 bAimTimeAddedForPunch = 2; + INT8 bAimTimeAddedForKnife = 2; usInHand = pSoldier->inv[HANDPOS].usItem; ubCursor = GetActionModeCursor( pSoldier ); - UINT8 maxAimLevels = AllowedAimingLevels(pSoldier); + // HEADROCK HAM 4: Required for new Aiming Level Limit function + UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, usMapPos); // 'snap' cursor to target tile.... if ( gfUIFullTargetFound ) @@ -2298,20 +2408,23 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) case PUNCHCURS: - bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + REFINE_PUNCH_2 ); + // SANDRO - changed the formula here to make aimed punch less expensive for APS + bAimTimeAddedForPunch = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : REFINE_PUNCH_2); - if ( bFutureAim <= REFINE_PUNCH_2 ) + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + bAimTimeAddedForPunch ); + + if ( bFutureAim <= bAimTimeAddedForPunch ) { sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) ); // Determine if we can afford! if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) { - pSoldier->aiData.bShownAimTime+= REFINE_PUNCH_2; + pSoldier->aiData.bShownAimTime+= bAimTimeAddedForPunch; - if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 ) + if ( pSoldier->aiData.bShownAimTime > bAimTimeAddedForPunch ) { - pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2; + pSoldier->aiData.bShownAimTime = bAimTimeAddedForPunch; } } // Else - goto first level! @@ -2345,20 +2458,23 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) case KNIFECURS: - bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + REFINE_KNIFE_2 ); + // SANDRO - changed the formula here to make aimed blade attack less expensive for APS + bAimTimeAddedForKnife = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : REFINE_KNIFE_2); - if ( bFutureAim <= REFINE_KNIFE_2 ) + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + bAimTimeAddedForKnife ); + + if ( bFutureAim <= bAimTimeAddedForKnife ) { sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) ); // Determine if we can afford! if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) { - pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2; + pSoldier->aiData.bShownAimTime+= bAimTimeAddedForKnife; - if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 ) + if ( pSoldier->aiData.bShownAimTime > bAimTimeAddedForKnife ) { - pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2; + pSoldier->aiData.bShownAimTime = bAimTimeAddedForKnife; } } // Else - goto first level! @@ -2524,12 +2640,194 @@ void HandleUICursorRTFeedback( SOLDIERTYPE *pSoldier ) } } + + +/* good code from lesh +BOOLEAN CanSoldierAffordAimTime( SOLDIERTYPE *pSoldier, INT16 usMapPos, INT8 bAimTime ) +{ + INT8 maxAimLevels; + INT16 sAPCosts; + + maxAimLevels = AllowedAimingLevels(pSoldier); + + if ( bAimTime < REFINE_AIM_1 || bAimTime > maxAimLevels ) + return FALSE; + + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bAimTime ); + + if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + return FALSE; + + return TRUE; +} + +BOOLEAN CanSoldierAffordPunching( SOLDIERTYPE *pSoldier, INT16 usMapPos, INT8 bRefineTime ) +{ + INT16 sAPCosts; + + if ( bRefineTime < REFINE_PUNCH_1 || bRefineTime > REFINE_PUNCH_2 ) + return FALSE; + + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bRefineTime ); + + if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + return FALSE; + + return TRUE; +} + +BOOLEAN CanSoldierAffordKnifing( SOLDIERTYPE *pSoldier, INT16 usMapPos, INT8 bRefineTime ) +{ + INT16 sAPCosts; + + if ( bRefineTime < REFINE_KNIFE_1 || bRefineTime > REFINE_KNIFE_2 ) + return FALSE; + + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bRefineTime ); + + if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + return FALSE; + + return TRUE; +} + +BOOLEAN CanSoldierAffordBurstBullets( SOLDIERTYPE *pSoldier, INT16 usMapPos ) +{ + INT16 sAPCosts; + INT8 bSaveDoAutofire; + + if ( pSoldier->bDoAutofire < 1 ) + { + pSoldier->bDoAutofire = 1; + return FALSE; + } + + if ( pSoldier->bDoAutofire > pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft ) + { + pSoldier->bDoAutofire = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + return FALSE; + } + + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, 0); + + if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + return FALSE; + + return TRUE; +} + + +void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, INT16 sDelta ) +{ + UINT8 ubCursor; + INT8 bFutureAim; + + ubCursor = GetActionModeCursor( pSoldier ); + + // 'snap' cursor to target tile.... + if ( gfUIFullTargetFound ) + { + sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo; + } + + switch( ubCursor ) + { + case TARGETCURS: + // warn if bad chance to get through + if ( gfUIFullTargetFound && + !HandleCheckForBadChangeToGetThrough( pSoldier, MercPtrs[ gusUIFullTargetID ], + MercPtrs[ gusUIFullTargetID ]->sGridNo , MercPtrs[ gusUIFullTargetID ]->pathing.bLevel ) ) + { + return; + } + + if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire ) + { + } + else if( pSoldier->bDoAutofire ) + { + // AUTOFIRE section + INT16 sCurAPCosts, sFutureAPCost; + + if(pSoldier->flags.autofireLastStep) + { + pSoldier->flags.autofireLastStep = FALSE; + } + + // change burst length until AP difference is shown + sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + do + { + pSoldier->bDoAutofire += sDelta; + sFutureAPCost = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } while ( CanSoldierAffordBurstBullets( pSoldier, sMapPos ) && (sFutureAPCost - sCurAPCosts) == 0 ); + + // complement burst by adding bullets, until next bullet produce AP difference + sFutureAPCost = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + while ( CanSoldierAffordBurstBullets( pSoldier, sMapPos ) && (sFutureAPCost - sCurAPCosts) == 0 ) + { + pSoldier->bDoAutofire += 1; // now it goes as future burst length + sFutureAPCost = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + + // display red numbers, if it is last possible burst ap spenditure + pSoldier->flags.autofireLastStep = !CanSoldierAffordBurstBullets( pSoldier, sMapPos ); + + // restore last iteration bullet count (before ap difference) + pSoldier->bDoAutofire--; + } + else + { + // SINGLE SHOT section + bFutureAim = pSoldier->aiData.bShownAimTime + sDelta; + + if ( CanSoldierAffordAimTime( pSoldier, sMapPos, bFutureAim) ) + { + pSoldier->aiData.bShownAimTime += sDelta; + // display yellow circle, if it is last possible aim level + gfDisplayFullCountRing = !CanSoldierAffordAimTime( pSoldier, sMapPos, bFutureAim + 1); + + } + } + break; + + case PUNCHCURS: + // PUNCHING section + bFutureAim = pSoldier->aiData.bShownAimTime + sDelta * REFINE_PUNCH_2; // possibly dirty hack + + if ( CanSoldierAffordPunching( pSoldier, sMapPos, bFutureAim) ) + { + pSoldier->aiData.bShownAimTime += sDelta * REFINE_PUNCH_2; + // display yellow circle, if it is last possible aim level + gfDisplayFullCountRing = !CanSoldierAffordPunching( pSoldier, sMapPos, bFutureAim + 1); + } + break; + + case KNIFECURS: + // KNIFING section + bFutureAim = pSoldier->aiData.bShownAimTime + sDelta * REFINE_KNIFE_2; // possibly dirty hack + + if ( CanSoldierAffordKnifing( pSoldier, sMapPos, bFutureAim) ) + { + pSoldier->aiData.bShownAimTime += sDelta * REFINE_KNIFE_2; + // display yellow circle, if it is last possible aim level + gfDisplayFullCountRing = !CanSoldierAffordKnifing( pSoldier, sMapPos, bFutureAim + 1); + } + break; + + }; +} + + + + +*/ // HEADROCK HAM B2.7: This function gives us an "approximate" CTH bar, that doesn't show the exact value of // CTH unless the character is well-trained. The worse trained a character is, the wilder the speculation. UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance ) { - UINT16 bExpLevel = pSoldier->stats.bExpLevel; + UINT16 bExpLevelValue = EffectiveExpLevel(pSoldier); // SANDRO - changed to effective level calc UINT16 bMarksmanship = pSoldier->stats.bMarksmanship; UINT16 bWisdom = pSoldier->stats.bWisdom; UINT16 iNumStages, iNumStagesBase, StageSize, SubStageSize; @@ -2539,7 +2837,10 @@ UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance ) if ( pSoldier->ubProfile != NO_PROFILE ) { - iSniper = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER ); + if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO + iSniper = NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); + else + iSniper = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT ); } else { @@ -2561,7 +2862,7 @@ UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance ) } uiNewChance = uiChance; - iNumStagesBase = __min(165,__max(0, ((bExpLevel * 10) - 30) + (bMarksmanship - 25) + (bWisdom - 50))); + iNumStagesBase = __min(165,__max(0, ((bExpLevelValue * 10) - 30) + (bMarksmanship - 25) + (bWisdom - 50))); //iNumStagesBase = __max(255, iNumStagesBase); iNumStagesBase = __min(165, iNumStagesBase + (10 * iSniper)); @@ -2601,3 +2902,642 @@ UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance ) // Something went wrong. Return 50, as in "God Knows" return (50); } + + +/* // . +void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, INT16 sDelta ) +{ + UINT16 usInHand; + INT16 sAPCosts; + INT8 bFutureAim; + UINT8 ubCursor; + SOLDIERTYPE *pTSoldier; + INT16 sGridNo; + INT8 bTargetLevel; + + + usInHand = pSoldier->inv[HANDPOS].usItem; + + ubCursor = GetActionModeCursor( pSoldier ); + + UINT8 maxAimLevels = AllowedAimingLevels(pSoldier); + + // 'snap' cursor to target tile.... + if ( gfUIFullTargetFound ) + { + sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo; + } + + + switch( ubCursor ) + { + case TARGETCURS: + + // CHECK IF GUY HAS IN HAND A WEAPON + if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire) + { + // Do nothing! + // pSoldier->aiData.bShownAimTime = REFINE_AIM_BURST; + } + else if(pSoldier->bDoAutofire) + { + INT16 sCurAPCosts; + + if(pSoldier->bDoAutofire==1 && sDelta<0) return; + + if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire ) + { + //Calculate how many bullets we need to fire to add at least one more AP + sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP + { + pSoldier->bDoAutofire++; + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + + //we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets + + sCurAPCosts = sAPCosts; + + do + { + pSoldier->bDoAutofire+=sDelta; + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + pSoldier->bDoAutofire--; + + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + + if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets + { + pSoldier->flags.autofireLastStep = TRUE; + pSoldier->bDoAutofire--; + } + else + pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false + } + else + { + if(sDelta<0) + { + pSoldier->flags.autofireLastStep = FALSE; + pSoldier->bDoAutofire--; + } + else + pSoldier->flags.autofireLastStep = TRUE; + } + } + else //single shoot + { + sGridNo = sMapPos; + bTargetLevel = (INT8)gsInterfaceLevel; + + // Look for a target here... + if ( gfUIFullTargetFound ) + { + // Get target soldier, if one exists + pTSoldier = MercPtrs[ gusUIFullTargetID ]; + sGridNo = pTSoldier->sGridNo; + bTargetLevel = pSoldier->pathing.bLevel; + + if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) ) + return; + } + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + sDelta ); + if(bFutureAim <0)return; + + if ( bFutureAim <= maxAimLevels ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim ) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= sDelta; + if ( pSoldier->aiData.bShownAimTime > maxAimLevels ) + pSoldier->aiData.bShownAimTime = maxAimLevels; + gfDisplayFullCountRing = FALSE; + } + + else // Else - goto first level! + gfDisplayFullCountRing = TRUE; + } + else + gfDisplayFullCountRing = TRUE; + + } + break; + + + case PUNCHCURS: + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + REFINE_PUNCH_2 ); + + if ( bFutureAim <= REFINE_PUNCH_2 ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= (sDelta*REFINE_PUNCH_2); + + if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 ) + { + pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2; + } + } + // Else - goto first level! + else + { + if ( !gfDisplayFullCountRing ) + { + gfDisplayFullCountRing = TRUE; + } + else + { + pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1; + gfDisplayFullCountRing = FALSE; + } + } + } + else + { + if ( !gfDisplayFullCountRing ) + { + gfDisplayFullCountRing = TRUE; + } + else + { + pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1; + gfDisplayFullCountRing = FALSE; + } + } + break; + + + case KNIFECURS: + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_KNIFE_2) ); + + if ( bFutureAim <= REFINE_KNIFE_2 ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2; + + if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 ) + { + pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2; + } + } + // Else - goto first level! + else + { + if ( !gfDisplayFullCountRing ) + { + gfDisplayFullCountRing = TRUE; + } + else + { + pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1; + gfDisplayFullCountRing = FALSE; + } + } + } + else + { + if ( !gfDisplayFullCountRing ) + { + gfDisplayFullCountRing = TRUE; + } + else + { + pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1; + gfDisplayFullCountRing = FALSE; + } + } + break; + + case TOSSCURS: + + //IncrementAimCubeUI( ); + break; + + default: + + ErasePath( TRUE ); + + } +} +*/ + + + +void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta, INT16 brstmode ) +{ + UINT16 usInHand; + INT16 sAPCosts; + INT8 bFutureAim; + UINT8 ubCursor; + SOLDIERTYPE *pTSoldier; + INT32 sGridNo; + INT8 bTargetLevel; + + + usInHand = pSoldier->inv[HANDPOS].usItem; + + ubCursor = GetActionModeCursor( pSoldier ); + + UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, sMapPos); + + // 'snap' cursor to target tile.... + if ( gfUIFullTargetFound ) + sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo; + + int aimlevelchange = 1; + int maxAimCanAfford = 0; + int oldAim = pSoldier->aiData.bShownAimTime; + int hitChance = 0; + int maxCtH = 0; //maximum chance to hit + int minAimForCtH = 0; //minimum AP needed to get maximum CtH + switch( ubCursor ) + { + case TARGETCURS: + +//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"cbef=%d",CalcChanceToHitGun( pSoldier, sMapPos, pSoldier->aiData.bShownAimTime, pSoldier->bAimShotLocation ) ); + if(pSoldier->bDoAutofire && (gfKeyState[18] || brstmode) ) // - + { + INT16 sCurAPCosts; + + if(pSoldier->bDoAutofire==1 && sDelta<0) return; + + if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire ) + { + //Calculate how many bullets we need to fire to add at least one more AP + sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP + { + pSoldier->bDoAutofire++; + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + + //we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets + + sCurAPCosts = sAPCosts; + + do + { + pSoldier->bDoAutofire+=sDelta; + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + pSoldier->bDoAutofire--; + + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + + if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets + { + pSoldier->flags.autofireLastStep = TRUE; + pSoldier->bDoAutofire--; + } + else + pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false + } + else + { + if(sDelta<0) + { + pSoldier->flags.autofireLastStep = FALSE; + pSoldier->bDoAutofire--; + } + else + pSoldier->flags.autofireLastStep = TRUE; + } + return; + } +/////////////////////////////// + sGridNo = sMapPos; + bTargetLevel = (INT8)gsInterfaceLevel; + + // Look for a target here... + if ( gfUIFullTargetFound ) + { + // Get target soldier, if one exists + pTSoldier = MercPtrs[ gusUIFullTargetID ]; + sGridNo = pTSoldier->sGridNo; + bTargetLevel = pSoldier->pathing.bLevel; + + if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) ) + { + return; + } + } + + + bFutureAim = maxAimLevels; + + //Find the actual maximum aim that can be done. + while( bFutureAim > 0 ){ + //Can afford this many? + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, bFutureAim ); + if( !maxAimCanAfford && EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ){ + maxAimCanAfford = bFutureAim; + } + //Find the least amount of aiming needed to get maximum CtH + //Give some slack, but don't let the slack accumulate. + //dd???{ + //hitChance = CalcChanceToHitGun( pSoldier, sMapPos, bFutureAim, pSoldier->bAimShotLocation ); + //if( hitChance >= maxCtH - 3){ + // minAimForCtH = bFutureAim; + // if(hitChance >= maxCtH) maxCtH = hitChance; + //} + //ddd???} + //Loop to 0. + --bFutureAim; + } + + bFutureAim = oldAim + sDelta; + if( bFutureAim < REFINE_AIM_1 ) return; + + + //Do it. + if( bFutureAim < REFINE_AIM_1 ){ + //Went too low. Set to max aim. + bFutureAim = maxAimCanAfford; + gfDisplayFullCountRing = TRUE; + }else if( bFutureAim <= maxAimCanAfford ){ + //Aim level is doable. No modification needed. + gfDisplayFullCountRing = FALSE; + }else{ + //Aim too high. Give indicator that is is maxed, then reset aim refinement. + if ( gfDisplayFullCountRing ) + return; + else{ + //Display ring to indicate maximum aim reached. + bFutureAim = oldAim; + gfDisplayFullCountRing = TRUE; + } + } + //Apply. + pSoldier->aiData.bShownAimTime = bFutureAim; + +//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"caft=%d",CalcChanceToHitGun( pSoldier, sMapPos, pSoldier->aiData.bShownAimTime, pSoldier->bAimShotLocation ) ); + break; + + + case PUNCHCURS: + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_PUNCH_2) ); +if(bFutureAim<0) return; + if ( bFutureAim <= REFINE_PUNCH_2 ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= (sDelta*REFINE_PUNCH_2); + if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 ) + pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2; + gfDisplayFullCountRing = FALSE; + } + else + gfDisplayFullCountRing = TRUE; + } + else + gfDisplayFullCountRing = TRUE; + + break; + + + + case KNIFECURS: + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_KNIFE_2) ); +if(bFutureAim<0) return; + if ( bFutureAim <= REFINE_KNIFE_2 ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2; + if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 ) + pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2; + gfDisplayFullCountRing = FALSE; + } + else + gfDisplayFullCountRing = TRUE; + } + else + gfDisplayFullCountRing = TRUE; + + break; + + case TOSSCURS: + + //IncrementAimCubeUI( ); + break; + + default: + + ErasePath( TRUE ); + + } + +} + +// if . +void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta ) +{ + UINT16 usInHand; + INT16 sAPCosts; + INT8 bFutureAim; + UINT8 ubCursor; + SOLDIERTYPE *pTSoldier; + INT32 sGridNo; + INT8 bTargetLevel; + + + usInHand = pSoldier->inv[HANDPOS].usItem; + + ubCursor = GetActionModeCursor( pSoldier ); + + UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, sMapPos); + + // 'snap' cursor to target tile.... + if ( gfUIFullTargetFound ) + { + sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo; + } + + + switch( ubCursor ) + { + case TARGETCURS: + + // CHECK IF GUY HAS IN HAND A WEAPON + if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire) + { + // Do nothing! + // pSoldier->aiData.bShownAimTime = REFINE_AIM_BURST; + } + else if(pSoldier->bDoAutofire) + { + INT16 sCurAPCosts; + + if(pSoldier->bDoAutofire==1 && sDelta<0) return; + + if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire ) + { + //Calculate how many bullets we need to fire to add at least one more AP + sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP + { + pSoldier->bDoAutofire++; + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + + //we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets + + sCurAPCosts = sAPCosts; + + do + { + pSoldier->bDoAutofire+=sDelta; + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + } + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + pSoldier->bDoAutofire--; + + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0); + + if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets + { + pSoldier->flags.autofireLastStep = TRUE; + pSoldier->bDoAutofire--; + } + else + pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false + } + else + { + if(sDelta<0) + { + pSoldier->flags.autofireLastStep = FALSE; + pSoldier->bDoAutofire--; + } + else + pSoldier->flags.autofireLastStep = TRUE; + } + } + else //single shoot + { + sGridNo = sMapPos; + bTargetLevel = (INT8)gsInterfaceLevel; + + // Look for a target here... + if ( gfUIFullTargetFound ) + { + // Get target soldier, if one exists + pTSoldier = MercPtrs[ gusUIFullTargetID ]; + sGridNo = pTSoldier->sGridNo; + bTargetLevel = pSoldier->pathing.bLevel; + + if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) ) + return; + } + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + sDelta ); + if(bFutureAim <0)return; + + if ( bFutureAim <= maxAimLevels ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim ) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= sDelta; + if ( pSoldier->aiData.bShownAimTime > maxAimLevels ) + pSoldier->aiData.bShownAimTime = maxAimLevels; + gfDisplayFullCountRing = FALSE; + } + + else // Else - goto first level! + gfDisplayFullCountRing = TRUE; + } + else + gfDisplayFullCountRing = TRUE; + + } + break; + + case PUNCHCURS: + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_PUNCH_2) ); +if(bFutureAim<0) return; + if ( bFutureAim <= REFINE_PUNCH_2 ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= (sDelta*REFINE_PUNCH_2); + if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 ) + pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2; + gfDisplayFullCountRing = FALSE; + } + else + gfDisplayFullCountRing = TRUE; + } + else + gfDisplayFullCountRing = TRUE; + + break; + + + + case KNIFECURS: + + bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_KNIFE_2) ); +if(bFutureAim<0) return; + if ( bFutureAim <= REFINE_KNIFE_2 ) + { + sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) ); + + // Determine if we can afford! + if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) + { + pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2; + if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 ) + pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2; + gfDisplayFullCountRing = FALSE; + } + else + gfDisplayFullCountRing = TRUE; + } + else + gfDisplayFullCountRing = TRUE; + + break; + + case TOSSCURS: + + //IncrementAimCubeUI( ); + break; + + default: + + ErasePath( TRUE ); + + } +} \ No newline at end of file diff --git a/Tactical/UI Cursors.h b/Tactical/UI Cursors.h index fb1c9437..7f74a4d1 100644 --- a/Tactical/UI Cursors.h +++ b/Tactical/UI Cursors.h @@ -14,6 +14,8 @@ void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN f void HandleLeftClickCursor( SOLDIERTYPE *pSoldier ); void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ); +void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, INT32 sDelta, INT16 brstmode ); +void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta ); UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier ); diff --git a/Tactical/Vehicles.cpp b/Tactical/Vehicles.cpp index a5a40c89..101868eb 100644 --- a/Tactical/Vehicles.cpp +++ b/Tactical/Vehicles.cpp @@ -39,6 +39,7 @@ #include "opplist.h" #include "Soldier ani.h" #include "GameSettings.h" + #include "Queen Command.h" #endif //INT8 gubVehicleMovementGroups[ MAX_VEHICLES ]; @@ -618,14 +619,44 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) } -void SetSoldierExitVehicleInsertionData( SOLDIERTYPE *pSoldier, INT32 iId ) +void SetSoldierExitVehicleInsertionData( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 iOldGroupID ) { + GROUP *pGroup; + if ( iId == iHelicopterVehicleId && !pSoldier->bInSector ) { if( pSoldier->sSectorX != BOBBYR_SHIPPING_DEST_SECTOR_X || pSoldier->sSectorY != BOBBYR_SHIPPING_DEST_SECTOR_Y || pSoldier->bSectorZ != BOBBYR_SHIPPING_DEST_SECTOR_Z ) { - // Not anything different here - just use center gridno...... - pSoldier->ubStrategicInsertionCode = INSERTION_CODE_CENTER; + if( NumHostilesInSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 0 && iOldGroupID != 0 && gGameExternalOptions.ubSkyriderHotLZ == 2 ) + { + pGroup = GetGroup( iOldGroupID ); + if( pGroup->ubSectorX < pGroup->ubPrevX ) + { + pSoldier->ubStrategicInsertionCode = INSERTION_CODE_EAST; + } + else if( pGroup->ubSectorX > pGroup->ubPrevX ) + { + pSoldier->ubStrategicInsertionCode = INSERTION_CODE_WEST; + } + else if( pGroup->ubSectorY < pGroup->ubPrevY ) + { + pSoldier->ubStrategicInsertionCode = INSERTION_CODE_SOUTH; + } + else if( pGroup->ubSectorY > pGroup->ubPrevY ) + { + pSoldier->ubStrategicInsertionCode = INSERTION_CODE_NORTH; + } + else + { + Assert(0); + return; + } + } + else + { + // Not anything different here - just use center gridno...... + pSoldier->ubStrategicInsertionCode = INSERTION_CODE_CENTER; + } } else { @@ -643,6 +674,7 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) BOOLEAN fSoldierLeft = FALSE; BOOLEAN fSoldierFound = FALSE; SOLDIERTYPE *pVehicleSoldier; + UINT8 iOldGroupID=0; if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) ) @@ -663,6 +695,7 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) { fSoldierFound = TRUE; + iOldGroupID = pVehicleList[ iId ].pPassengers[ iCounter ]->ubGroupID; pVehicleList[ iId ].pPassengers[ iCounter ]->ubGroupID = 0; pVehicleList[ iId ].pPassengers[ iCounter ]->sSectorY = pVehicleList[ iId ].sSectorY; pVehicleList[ iId ].pPassengers[ iCounter ]->sSectorX = pVehicleList[ iId ].sSectorX; @@ -772,7 +805,7 @@ BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId ) SetSectorFlag( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, SF_ALREADY_VISITED ); } - SetSoldierExitVehicleInsertionData( pSoldier, iId ); + SetSoldierExitVehicleInsertionData( pSoldier, iId, iOldGroupID ); // Update in sector if this is the current sector..... if ( pSoldier->sSectorX == gWorldSectorX && pSoldier->sSectorY == gWorldSectorY && pSoldier->bSectorZ == gbWorldSectorZ ) diff --git a/Tactical/Vehicles.h b/Tactical/Vehicles.h index 650ef12e..7cc2cebe 100644 --- a/Tactical/Vehicles.h +++ b/Tactical/Vehicles.h @@ -232,7 +232,7 @@ SOLDIERTYPE* PickRandomPassengerFromVehicle( SOLDIERTYPE *pSoldier ); BOOLEAN DoesVehicleHaveAnyPassengers( INT32 iVehicleID ); BOOLEAN DoesVehicleGroupHaveAnyPassengers( GROUP *pGroup ); -void SetSoldierExitVehicleInsertionData( SOLDIERTYPE *pSoldier, INT32 iId ); +void SetSoldierExitVehicleInsertionData( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 iOldGroupID ); void InitAVehicle(int index, int x, int y); diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index e6436c08..cfb91533 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -46,6 +46,9 @@ #include "SmokeEffects.h" #include "lighting.h" #include "Auto Resolve.h" + #include "Soldier Functions.h" // added by SANDRO + #include "Drugs And Alcohol.h" // HEADROCK HAM 4: Get drunk level + #include "LOS.h" // HEADROCK HAM 4: Required for new shooting mechanism. Alternately, maybe move the functions to LOS.h. #endif //forward declarations of common classes to eliminate includes @@ -97,6 +100,7 @@ extern BOOLEAN gfNextFireJam; BOOLEAN WillExplosiveWeaponFail( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ); BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ); +BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ); BOOLEAN UseBlade( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ); BOOLEAN UseThrown( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ); BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ); @@ -326,6 +330,9 @@ AMMOTYPE AmmoTypes[MAXITEMS]; // used to determine whether the bullet will go through someone UINT8 BodyImpactReduction[4] = { 0, 15, 30, 23 }; +bool gbForceWeaponNotReady = false; +bool gbForceWeaponReady = false; + @@ -389,6 +396,7 @@ weaponStartElementHandle(void *userData, const XML_Char *name, const XML_Char ** strcmp(name, "ubImpact") == 0 || strcmp(name, "ubDeadliness") == 0 || strcmp(name, "bAccuracy") == 0 || + strcmp(name, "nAccuracy") == 0 || strcmp(name, "ubMagSize") == 0 || strcmp(name, "usRange") == 0 || strcmp(name, "usReloadDelay") == 0 || @@ -405,12 +413,16 @@ weaponStartElementHandle(void *userData, const XML_Char *name, const XML_Char ** strcmp(name, "SwapClips") == 0 || strcmp(name, "AutoPenalty") == 0 || strcmp(name, "NoSemiAuto") == 0 || + strcmp(name, "EasyUnjam") == 0 || strcmp(name, "MaxDistForMessyDeath") == 0 || strcmp(name, "SilencedSound") == 0 || // Lesh: add new field (OR operand) strcmp(name, "BurstAniDelay") == 0 || // Lesh: add new field (field itself) strcmp(name, "APsToReloadManually") == 0 || - strcmp(name, "ManualReloadSound") == 0) - ) + strcmp(name, "ManualReloadSound") == 0 || + strcmp(name, "ubAimLevels") == 0 ||// HEADROCK HAM 4: Allowed aiming levels for this gun. + strcmp(name, "bRecoilX") == 0 || // HEADROCK HAM 4: + strcmp(name, "bRecoilY") == 0 || // HEADROCK HAM 4: + strcmp(name, "ubRecoilDelay") == 0)) // HEADROCK HAM 4: { pData->curElement = WEAPON_ELEMENT_WEAPON_PROPERY; @@ -530,6 +542,11 @@ weaponEndElementHandle(void *userData, const XML_Char *name) pData->curElement = WEAPON_ELEMENT_WEAPON; pData->curWeapon.bAccuracy = (INT8) atol(pData->szCharData); } + else if(strcmp(name, "nAccuracy") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.nAccuracy = (INT8) atol(pData->szCharData); + } else if(strcmp(name, "ubMagSize") == 0) { pData->curElement = WEAPON_ELEMENT_WEAPON; @@ -640,6 +657,31 @@ weaponEndElementHandle(void *userData, const XML_Char *name) pData->curElement = WEAPON_ELEMENT_WEAPON; pData->curWeapon.ManualReloadSound = (UINT16) atol(pData->szCharData); } + else if(strcmp(name, "EasyUnjam") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.EasyUnjam = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "ubAimLevels") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.ubAimLevels = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "bRecoilX") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.bRecoilX = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "bRecoilY") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.bRecoilY = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "ubRecoilDelay") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.ubRecoilDelay = (INT8) atol(pData->szCharData); + } pData->maxReadDepth--; } @@ -710,7 +752,7 @@ BOOLEAN ReadInWeaponStats(STR fileName) //Debug code; make sure that what we got from the file is the same as what's there // Open a new file hFile = FileOpen( "TABLEDATA\\~Weapons out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); - THROWIFFALSE(hFile, BuildString().add(L"Couls not open/create file : ").add(L"TABLEDATA\\~Weapons out.xml").get()); + SGP_THROW_IFFALSE(hFile, _BS(L"Couls not open/create file : ") << L"TABLEDATA\\~Weapons out.xml" << _BS::wget); //if ( !hFile ) // return( FALSE ); @@ -781,6 +823,7 @@ BOOLEAN ReadInWeaponStats(STR fileName) FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubImpact); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubDeadliness); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].bAccuracy); + FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].nAccuracy); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubMagSize); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].usRange); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].usReloadDelay); @@ -795,6 +838,10 @@ BOOLEAN ReadInWeaponStats(STR fileName) FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].bAutofireShotsPerFiveAP); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].APsToReloadManually); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ManualReloadSound); + FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubAimLevels); + FilePrintf(hFile,"\t\t%d<\bRecoilX>\r\n", Weapon[cnt].bRecoilX); + FilePrintf(hFile,"\t\t%d<\bRecoilY>\r\n", Weapon[cnt].bRecoilY); + FilePrintf(hFile,"\t\t%d<\ubRecoilDelay>\r\n", Weapon[cnt].ubRecoilDelay); FilePrintf(hFile,"\t\r\n"); } FilePrintf(hFile,"\r\n"); @@ -880,10 +927,13 @@ BOOLEAN WriteWeaponStats() FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubShotsPer4Turns); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubShotsPerBurst); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubBurstPenalty); + FilePrintf(hFile,"\t\t%d<\bRecoilX>", Weapon[cnt].bRecoilX); + FilePrintf(hFile,"\t\t%d<\bRecoilY>", Weapon[cnt].bRecoilY); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubBulletSpeed); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubImpact); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubDeadliness); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].bAccuracy); + FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].nAccuracy); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubMagSize); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].usRange); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].usReloadDelay); @@ -903,6 +953,8 @@ BOOLEAN WriteWeaponStats() FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].maxdistformessydeath); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].AutoPenalty); FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].NoSemiAuto); + FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].ubAimLevels ); + FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].EasyUnjam); @@ -915,7 +967,7 @@ BOOLEAN WriteWeaponStats() return( TRUE ); } -UINT16 GunRange( OBJECTTYPE * pObj ) +UINT16 GunRange( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier ) // SANDRO - added argument { //INT8 bAttachPos; UINT16 rng; @@ -953,8 +1005,20 @@ UINT16 GunRange( OBJECTTYPE * pObj ) //} + UINT16 usRange = GetModifiedGunRange(pObj->usItem); + // Snap: attachment status is factored into the range bonus calculation - rng = Weapon[ pObj->usItem ].usRange + GetRangeBonus(pObj); + rng = usRange + GetRangeBonus(pObj); + + // SANDRO - STOMP traits - Gunslinger bonus range with pistols + if ( pSoldier != NULL && Item[ pObj->usItem ].usItemClass & IC_GUN ) + { + if ((Weapon[ pObj->usItem ].ubWeaponType == GUN_PISTOL || Weapon[ pObj->usItem ].ubWeaponType == GUN_M_PISTOL) && + gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) ) + { + rng += (rng * gSkillTraitValues.ubGSEffectiveRangeBonusPistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ) / 100 ); + } + } return rng; } @@ -977,7 +1041,7 @@ INT32 EffectiveArmour( OBJECTTYPE * pObj ) iValue = iValue * (*pObj)[0]->data.objectStatus * Armour[ Item[pObj->usItem].ubClassIndex ].ubCoverage / 10000; for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 ) + if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists()) { INT32 iValue2; @@ -1077,7 +1141,7 @@ INT32 ExplosiveEffectiveArmour( OBJECTTYPE * pObj ) } for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 ) + if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists()) { INT32 iValue2; @@ -1136,7 +1200,8 @@ void AdjustImpactByHitLocation( INT32 iImpact, UINT8 ubHitLocation, INT32 * piNe { case AIM_SHOT_HEAD: // 1.5x damage from successful hits to the head! - *piImpactForCrits = HEAD_DAMAGE_ADJUSTMENT( iImpact ); + //*piImpactForCrits = HEAD_DAMAGE_ADJUSTMENT( iImpact ); //comm by ddd + *piImpactForCrits = INT32(gGameExternalOptions.fShotHeadDivisor*iImpact); *piNewImpact = *piImpactForCrits; break; case AIM_SHOT_LEGS: @@ -1173,7 +1238,7 @@ BOOLEAN CheckForGunJam( SOLDIERTYPE * pSoldier ) { // Algorithm for jamming int maxJamChance = 50; // Externalize this? - int reliability = Item[pObj->usItem].bReliability; + int reliability = GetReliability( pObj ); int condition = (*pObj)[0]->data.gun.bGunStatus; int invertedBaseJamChance = condition + (reliability * 2) - gGameExternalOptions.ubWeaponReliabilityReductionPerRainIntensity * gbCurrentRainIntensity; @@ -1242,15 +1307,27 @@ BOOLEAN CheckForGunJam( SOLDIERTYPE * pSoldier ) if(EnoughPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM], FALSE)) { DeductPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM]); - int iResult = SkillCheck( pSoldier, UNJAM_GUN_CHECK, (INT8) ((Item[pObj->usItem].bReliability + Item[(*pObj)[0]->data.gun.usGunAmmoItem].bReliability)* 4) ); + INT8 bChanceMod; + + if ( Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].EasyUnjam ) + bChanceMod = 100; + else + bChanceMod = (INT8) (GetReliability( pObj )* 4); + + int iResult = SkillCheck( pSoldier, UNJAM_GUN_CHECK, bChanceMod); + if (iResult > 0) { // yay! unjammed the gun (*pObj)[0]->data.gun.bGunAmmoStatus *= -1; // MECHANICAL/DEXTERITY GAIN: Unjammed a gun - StatChange( pSoldier, MECHANAMT, 5, FALSE ); - StatChange( pSoldier, DEXTAMT, 5, FALSE ); + + if (bChanceMod < 100) // don't give exp for unjamming an easily unjammable gun + { + StatChange( pSoldier, MECHANAMT, 5, FALSE ); + StatChange( pSoldier, DEXTAMT, 5, FALSE ); + } DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); @@ -1400,9 +1477,9 @@ BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) break; case IC_LAUNCHER: - if ( Item[pSoldier->usAttackingWeapon].rocketlauncher ) + if ( Item[pSoldier->usAttackingWeapon].rocketlauncher ){ UseGun( pSoldier, sTargetGridNo ); - else + } else { // ATE: PAtch up - bookkeeping for spreading done out of whak if ( pSoldier->flags.fDoSpread) { @@ -1440,6 +1517,7 @@ BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) { UseLauncher( pSoldier, sTargetGridNo ); } + } break; @@ -1559,9 +1637,573 @@ void GetTargetWorldPositions( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, FLOAT *pdZPos = dTargetZ; } +// HEADROCK HAM 4: The CTH formula has been radically altered, and the value it returns is used very differently. +// This function now no longer rolls any random variables - that is relegated to other functions. However, this +// function is now responsible for altering the "center point" for the attack, given target movement and previous +// bullets fired in a volley. +BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) +{ + // CTH is now used as a Muzzle Sway value. That is, it determines how wide our shot can go off the "center point" + // of the attack. Later on, we'll randomize just how far the shot actually goes within that sway radius. + UINT32 uiMuzzleSway; + INT16 sXMapPos, sYMapPos; + INT16 sAPCost; + FLOAT dTargetX; + FLOAT dTargetY; + FLOAT dTargetZ; + UINT16 usItemNum; + BOOLEAN fBuckshot; + UINT8 ubVolume; + CHAR8 zBurstString[512]; + UINT8 ubDirection; + INT32 sNewGridNo; + UINT8 ubMerc; + BOOLEAN fGonnaHit = FALSE; + FLOAT dExpGain = 0; + UINT32 uiDepreciateTest; + + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("UseGun") ); + + // Calculate total APs required to complete the entire attack, including all relevant weapon AP costs + // with possible turning and gun-raising costs as well. + sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, FALSE, pSoldier->aiData.bAimTime ); + + usItemNum = pSoldier->usAttackingWeapon; + + // CALC MUZZLE SWAY + if ( Item[ usItemNum ].usItemClass == IC_THROWING_KNIFE ) + { + uiMuzzleSway = 100 - CalcThrownChanceToHit( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation ); + } + else + { + uiMuzzleSway = 100 - CalcChanceToHitGun( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation ); + } + + //ATE: Added if we are in meanwhile, we always hit... + if ( AreInMeanwhile( ) ) + { + uiMuzzleSway = 0; // HEADROCK HAM 4: This ensures a direct shot at the target. + } + + #ifdef JA2BETAVERSION + if ( gfReportHitChances ) + { + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Hit chance was %ld, roll %ld (range %d)", uiHitChance, uiDiceRoll, PythSpacesAway( pSoldier->sGridNo, pSoldier->sTargetGridNo ) ); + } + #endif + + if ( pSoldier->bDoBurst ) + { + // Only deduct points once for Burst and Autofire (on firing the first bullet). + if ( pSoldier->bDoBurst == 1 ) + { + INT8 bShotsToFire = pSoldier->bDoAutofire ? + pSoldier->bDoAutofire : + GetShotsPerBurst(&pSoldier->inv[HANDPOS]); + + if ( Weapon[ usItemNum ].sBurstSound != NO_WEAPON_SOUND ) + { + // IF we are silenced? + UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); + if( noisefactor < MAX_PERCENT_NOISE_VOLUME_FOR_SILENCED_SOUND || Weapon[ usItemNum ].ubAttackVolume <= 10 ) + { + // Pick sound file baed on how many bullets we are going to fire... + sprintf( zBurstString, gzBurstSndStrings[ Weapon[ usItemNum ].sSilencedBurstSound ], bShotsToFire ); + + // Try playing sound... + pSoldier->iBurstSoundID = PlayJA2SampleFromFile( zBurstString, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + else + { + // Pick sound file baed on how many bullets we are going to fire... + // Lesh: changed next line + sprintf( zBurstString, gzBurstSndStrings[ Weapon[ usItemNum ].sBurstSound ], bShotsToFire ); + + INT8 volume = HIGHVOLUME; + if ( noisefactor < 100 ) volume = (INT8) ((volume * noisefactor) / 100); + // Try playing sound... + pSoldier->iBurstSoundID = PlayJA2SampleFromFile( zBurstString, RATE_11025, SoundVolume( (INT8) volume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + + /* + //DIGICRAB: We don't need this anymore, because of the burst sound modification + // If we don't have the burst sound, a normal shot will be played for each shot + if ( pSoldier->iBurstSoundID == NO_SAMPLE ) + { + // If failed, play normal default.... + pSoldier->iBurstSoundID = PlayJA2Sample( Weapon[ usItemNum ].sBurstSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + */ + } + + DeductPoints( pSoldier, sAPCost, 0 ); + } + + } + else + { + // ONLY DEDUCT FOR THE FIRST HAND when doing two-pistol attacks + if ( pSoldier->IsValidSecondHandShot( ) && pSoldier->inv[ HANDPOS ][0]->data.gun.bGunStatus >= USABLE && pSoldier->inv[HANDPOS][0]->data.gun.bGunAmmoStatus > 0 ) + { + // only deduct APs when the main gun fires + if ( pSoldier->ubAttackingHand == HANDPOS ) + { + DeductPoints( pSoldier, sAPCost, 0 ); + } + } + else + { + DeductPoints( pSoldier, sAPCost, 0 ); + } + + //PLAY SOUND + // ( For throwing knife.. it's earlier in the animation + if ( Weapon[ usItemNum ].sSound != NO_WEAPON_SOUND && Item[ usItemNum ].usItemClass != IC_THROWING_KNIFE ) + { + // Switch on silencer... + UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); + if( noisefactor < MAX_PERCENT_NOISE_VOLUME_FOR_SILENCED_SOUND || Weapon[ usItemNum ].ubAttackVolume <= 10 ) + { + INT32 uiSound; + + uiSound = Weapon [ usItemNum ].silencedSound ; + //if ( Weapon[ usItemNum ].ubCalibre == AMMO9 || Weapon[ usItemNum ].ubCalibre == AMMO38 || Weapon[ usItemNum ].ubCalibre == AMMO57 ) + //{ + // uiSound = S_SILENCER_1; + //} + //else + //{ + // uiSound = S_SILENCER_2; + //} + + PlayJA2Sample( uiSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + + } + else + { + INT8 volume = HIGHVOLUME; + if ( noisefactor < 100 ) volume = (volume * noisefactor) / 100; + PlayJA2Sample( Weapon[ usItemNum ].sSound, RATE_11025, SoundVolume( volume, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + } + } + +//ddd{ . silencer + if ( (Item[ usItemNum ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor) + { + OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); + if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) ) + { + for (attachmentList::iterator iter = (*pInHand)[0]->attachments.begin(); iter != (*pInHand)[0]->attachments.end(); ++iter) + { + if (Item[iter->usItem].hidemuzzleflash ) + { + OBJECTTYPE* pA= &(*iter); + if ( (*pA)[0]->data.objectStatus >=USABLE) + { + INT16 ammoReliability = Item[(*pInHand)[0]->data.gun.usGunAmmoItem].bReliability; + INT16 uiDepreciateTest = BASIC_DEPRECIATE_CHANCE + 3 * + (Item[ iter->usItem ].bReliability + ammoReliability); + if ( !PreRandom( uiDepreciateTest ) && ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > 1) ) + (*pA)[0]->data.objectStatus--; + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"rel =%d ",Item[ iter->usItem ].bReliability ); + } + } + } + } + } //if ( Item[ usItemNum ].usItemClass == IC_GUN ) +//ddd} + + //DIGICRAB: Barrel extender wear code + // Relocated from CalcChanceToHitGun + if ( Item[ usItemNum ].usItemClass == IC_GUN ) + { + OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); + + // lalien: search for barrel extender not for any item with range bonus. (else barrel extender will fall off even when none is attached) + OBJECTTYPE* pAttachment = FindAttachment( pInHand, GUN_BARREL_EXTENDER ); + + if ( pAttachment ) + { + // reduce status and see if it falls off + (*pAttachment)[0]->data.objectStatus -= (INT8) Random( 2 ); + + if ( (*pAttachment)[0]->data.objectStatus - Random( 35 ) - Random( 35 ) < USABLE ) + { + //CHRISL: This setup assumes that remove() will work successfully, but if it doesn't we'll duplicate the item. + // barrel extender falls off! + // drop it to ground + //AddItemToPool( pSoldier->sGridNo, pAttachment, 1, pSoldier->pathing.bLevel, 0, -1 ); + + // since barrel extenders are not removable we cannot call RemoveAttachment here + // and must create the item by hand + //(*pInHand)[0]->attachments.remove(*pAttachment); + //ADB ubWeight has been removed, see comments in OBJECTTYPE + //pInHand->ubWeight = CalculateObjectWeight( pInHand ); + + //CHRISL: Instead of the above, use this function which is basially redundant to what remove() does, but includes + // a failsafe so we don't cause an item duplication. + for(std::list::iterator iter = (*pInHand)[0]->attachments.begin(); + iter != (*pInHand)[0]->attachments.end(); ++iter){ + if(*iter == *pAttachment) + { + AddItemToPool( pSoldier->sGridNo, pAttachment, 1, pSoldier->pathing.bLevel, 0, -1 ); + + iter = (*pInHand)[0]->RemoveAttachmentAtIter(iter); + + break; + } + } + + // big penalty to hit + // HEADROCK HAM 4: Muzzle sway INCREASES when a barrel extender falls off. + if(uiMuzzleSway > 70) + { + uiMuzzleSway = 100; + } + else + { + uiMuzzleSway += 30; + } + + // curse! + if ( pSoldier->bTeam == OUR_TEAM ) + { + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 46 ], pSoldier->name ); + } + } + } + } + + // Some things we don't do for knives... + if ( Item[ usItemNum ].usItemClass != IC_THROWING_KNIFE ) + { + // If realtime - set counter to freeup from attacking once done + if ( ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) ) + { + + // Set delay based on stats, weapon type, etc + pSoldier->sReloadDelay = (INT16)( Weapon[ usItemNum ].usReloadDelay + MANDATORY_WEAPON_DELAY ); + + // If a bad guy, double the delay! + if ( (pSoldier->flags.uiStatusFlags & SOLDIER_ENEMY ) ) + { + pSoldier->sReloadDelay = ( pSoldier->sReloadDelay * 2 ); + } + + + // slow down demo mode! + if ( gTacticalStatus.uiFlags & DEMOMODE ) + { + pSoldier->sReloadDelay *= 2; + } + + //pSoldier->flags.fReloading = TRUE; + //RESETTIMECOUNTER( pSoldier->timeCounters.ReloadCounter, pSoldier->sReloadDelay ); + } + + // Deduct AMMO! + DeductAmmo( pSoldier, pSoldier->ubAttackingHand ); + + // ATE: Check if we should say quote... + if ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft == 0 && !Item[pSoldier->usAttackingWeapon].rocketlauncher ) + { + if ( pSoldier->bTeam == gbPlayerNum ) + { + pSoldier->flags.fSayAmmoQuotePending = TRUE; + } + } + + // set buckshot and muzzle flash + fBuckshot = FALSE; + if (!CREATURE_OR_BLOODCAT( pSoldier ) ) + { + if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) ) + pSoldier->flags.fMuzzleFlash = FALSE; + else + pSoldier->flags.fMuzzleFlash = TRUE; + + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("UseGun: Muzzle flash = %d",pSoldier->flags.fMuzzleFlash)); + + if ( AmmoTypes[pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].numberOfBullets > 1 ) + fBuckshot = TRUE; + + //switch ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType ) + //{ + // case AMMO_BUCKSHOT: + // fBuckshot = TRUE; + // break; + // case AMMO_SLEEP_DART: + // pSoldier->flags.fMuzzleFlash = FALSE; + // break; + // default: + // break; + //} + } + } + else // throwing knife + { + fBuckshot = FALSE; + pSoldier->flags.fMuzzleFlash = FALSE; + + // Deduct knife from inv! (not here, later?) + } + + if ( Item[usItemNum].rocketlauncher ) + { + if ( WillExplosiveWeaponFail( pSoldier, &( pSoldier->inv[ HANDPOS ] ) ) ) + { + if ( Item[usItemNum].singleshotrocketlauncher ) + { + CreateItem( Item[usItemNum].discardedlauncheritem , pSoldier->inv[ HANDPOS ][0]->data.objectStatus,&(pSoldier->inv[ HANDPOS ] ) ); + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); + IgniteExplosion( pSoldier->ubID, CenterX( pSoldier->sGridNo ), CenterY( pSoldier->sGridNo ), 0, pSoldier->sGridNo, C1, pSoldier->pathing.bLevel ); + } + else + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pSoldier->inv[HANDPOS].usItem , pSoldier->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) ); + + IgniteExplosion( pSoldier->ubID, CenterX( pSoldier->sGridNo ), CenterY( pSoldier->sGridNo ), 0, pSoldier->sGridNo, pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem, pSoldier->pathing.bLevel ); + pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + } + // Reduce again for attack end 'cause it has been incremented for a normal attack + // + // Not anymore. Only the attack animation was increased, and it will decrease itself. + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - ATTACK ANIMATION %s ENDED BY BAD EXPLOSIVE CHECK, Now %d", gAnimControl[ pSoldier->usAnimState ].zAnimStr, gTacticalStatus.ubAttackBusyCount ) ); + DebugAttackBusy( String("@@@@@@@ Freeing up attacker - ATTACK ANIMATION %s ENDED BY BAD EXPLOSIVE CHECK\n", gAnimControl[ pSoldier->usAnimState ].zAnimStr ) ); + // ReduceAttackBusyCount( pSoldier->ubID, FALSE ); + + return( FALSE ); + } + } + + // GET TARGET XY VALUES + ConvertGridNoToCenterCellXY( sTargetGridNo, &sXMapPos, &sYMapPos ); + + // ATE; Moved a whole blotch if logic code for finding target positions to a function + // so other places can use it + // If the target contains a soldier, this function determines the x,y,z coordinates of the center of the + // targeted bodypart. + GetTargetWorldPositions( pSoldier, sTargetGridNo, &dTargetX, &dTargetY, &dTargetZ ); + + ////////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: New Shooting Mechanism + // + // This single function is now responsible for determining the point where the bullet will go. It adjusts + // the target x/y/z coordinates autonomously, based on the various effects of the new shooting mechanism. + // + // Therefore, once we reach FireBulletGivenTarget, the coordinates passed to that function are the ABSOLUTE + // final coordinates of the bullet, so FireBullet doesn't actually need to calculate anything beyond that except + // the angle increments required to put the bullet through those coordinates. + + INT16 sApertureRatio = 0; + if ( !AreInMeanwhile() ) + { + AdjustTargetCenterPoint( pSoldier, sTargetGridNo, &dTargetX, &dTargetY, &dTargetZ, &pSoldier->inv[ pSoldier->ubAttackingHand ], uiMuzzleSway, &sApertureRatio ); + } + + ////////////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Basic Experience Gain + // + // This part gives out basic experience gain for taking a shot or throwing a knife. It gives a few number of + // "free" points for any attack, and then an additional number of points based on how difficult the shot is, + // and how well the gun is being aimed. + // All points given here are FAILURE type, and cannot cause level gain. + // In addition, once the target is HIT, the shooter receives an additional number of points. + + if ( Item[ usItemNum ].usItemClass != IC_THROWING_KNIFE ) + { + // NB bDoBurst will be 2 at this point for the first shot since it was incremented + // above + // HEADROCK: Actually, it's 1 for the first shot. Works fine regardless though. + // HEADROCK HAM 4: Extra experience gain now given when the target is hit. This part only gives basic points + // for the attack (FAILURE type). + if ( PTR_OURTEAM && pSoldier->ubTargetID != NOBODY && (!pSoldier->bDoBurst || pSoldier->bDoBurst == 2 ) && (gTacticalStatus.uiFlags & INCOMBAT ) && ( SoldierToSoldierBodyPartChanceToGetThrough( pSoldier, MercPtrs[ pSoldier->ubTargetID ], pSoldier->bAimShotLocation ) > 0 ) ) + { + // add base pts for taking a shot, whether it hits or misses + dExpGain = 2.0f; + + if ( pSoldier->IsValidSecondHandShot( ) && pSoldier->inv[ HANDPOS ][0]->data.gun.bGunStatus >= USABLE && pSoldier->inv[HANDPOS][0]->data.gun.bGunAmmoStatus > 0 ) + { + // reduce exp gain for two pistol shooting since both shots give xp + dExpGain = (dExpGain * 2) / 3; + } + + if ( MercPtrs[ pSoldier->ubTargetID ]->ubBodyType == COW || MercPtrs[ pSoldier->ubTargetID ]->ubBodyType == CROW ) + { + dExpGain /= 2; + } + else if ( MercPtrs[ pSoldier->ubTargetID ]->flags.uiStatusFlags & SOLDIER_VEHICLE || AM_A_ROBOT( MercPtrs[ pSoldier->ubTargetID ] ) || TANK( MercPtrs[ pSoldier->ubTargetID ] ) ) + { + // no exp from shooting a vehicle that you can't damage and can't move! + dExpGain = 0; + } + + UINT16 usDextGain = (UINT16)(dExpGain / 2); + UINT16 usAgilGain = (UINT16)(dExpGain / 2); + UINT16 usMrksGain = 0; + + // Extra marksmanship/dexterity bonus for aiming. + if (pSoldier->aiData.bAimTime) + { + dExpGain += (3 * sApertureRatio) / 100; // At this point, usExpGain could equal up to 5. + usDextGain += (UINT16)(dExpGain / 3); + usMrksGain += (UINT16)((dExpGain * 2) / 3); + } + + // DEXTERITY/AGILITY/MARKSMANSHIP GAIN: gun attack + StatChange( pSoldier, AGILAMT, usAgilGain, FROM_FAILURE ); + StatChange( pSoldier, DEXTAMT, usDextGain, FROM_FAILURE ); + StatChange( pSoldier, MARKAMT, usMrksGain, FROM_FAILURE ); + } + } + else + { + // HEADROCK HAM 4: Extra experience gain now done when the bullet hits the target. This part only + // gives basic experience for the attack (FAILURE type). + // Improve for using a throwing knife.... + if (PTR_OURTEAM && pSoldier->ubTargetID != NOBODY) + { + // add base pts for taking a shot, whether it hits or misses + dExpGain = 5.0f; + + if ( MercPtrs[ pSoldier->ubTargetID ]->ubBodyType == COW || MercPtrs[ pSoldier->ubTargetID ]->ubBodyType == CROW ) + { + dExpGain /= 2; + } + else if ( MercPtrs[ pSoldier->ubTargetID ]->flags.uiStatusFlags & SOLDIER_VEHICLE || AM_A_ROBOT( MercPtrs[ pSoldier->ubTargetID ] ) || TANK( MercPtrs[ pSoldier->ubTargetID ] ) ) + { + // no exp from shooting a vehicle that you can't damage and can't move! + dExpGain = 0; + } + + UINT16 usDextGain = (UINT16)(dExpGain / 2); + UINT16 usAgilGain = (UINT16)(dExpGain / 2); + UINT16 usMrksGain = 0; + + // Extra marksmanship/dexterity bonus for aiming. + if (pSoldier->aiData.bAimTime) + { + dExpGain += (5 * sApertureRatio) / 100; // At this point, usExpGain could equal up to 10. + usDextGain += (UINT16)(dExpGain / 3); + usMrksGain += (UINT16)((dExpGain * 2) / 3); + } + + // DEXTERITY/AGILITY/MARKSMANSHIP GAIN: gun attack + StatChange( pSoldier, AGILAMT, usAgilGain, FROM_FAILURE ); + StatChange( pSoldier, DEXTAMT, usDextGain, FROM_FAILURE ); + StatChange( pSoldier, MARKAMT, usMrksGain, FROM_FAILURE ); + } + } + + /////////////////////////////// Fire bullet at the target coordinates. + //hayden + if((is_server && pSoldier->ubID<120) || (!is_server && is_client && pSoldier->ubID<20) || (!is_server && !is_client) ) + { + FireBulletGivenTarget( pSoldier, dTargetX, dTargetY, dTargetZ, pSoldier->usAttackingWeapon, sApertureRatio, fBuckshot, FALSE ); + } + else + { + FireBulletGivenTarget( pSoldier, dTargetX, dTargetY, dTargetZ, pSoldier->usAttackingWeapon, sApertureRatio, fBuckshot, TRUE ); + } + //bottom one is fake (ie not in my control) + + ubVolume = Weapon[ pSoldier->usAttackingWeapon ].ubAttackVolume; + + if ( Item[ usItemNum ].usItemClass == IC_THROWING_KNIFE ) + { + // Here, remove the knife... or (for now) rocket launcher + pSoldier->inv[ HANDPOS ].RemoveObjectsFromStack(1); + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); + } + else if ( Item[usItemNum].rocketlauncher ) + { + if ( Item[usItemNum].singleshotrocketlauncher ) + { + CreateItem( Item[usItemNum].discardedlauncheritem, pSoldier->inv[ HANDPOS ][0]->data.objectStatus, &(pSoldier->inv[ HANDPOS ] ) ); + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); + } + + // Direction to center of explosion + ubDirection = gOppositeDirection[ pSoldier->ubDirection ]; + sNewGridNo = NewGridNo( pSoldier->sGridNo, (UINT16)(1 * DirectionInc( ubDirection ) ) ); + + // Check if a person exists here and is not prone.... + ubMerc = WhoIsThere2( sNewGridNo, pSoldier->pathing.bLevel ); + + if ( ubMerc != NOBODY ) + { + if ( gAnimControl[ MercPtrs[ ubMerc ]->usAnimState ].ubHeight != ANIM_PRONE ) + { + // Increment attack counter... +// gTacticalStatus.ubAttackBusyCount++; + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Incrementing Attack: Exaust from LAW", gTacticalStatus.ubAttackBusyCount ) ); + DebugAttackBusy( "Incrementing Attack: Exaust from LAW\n" ); + + MercPtrs[ ubMerc ]->EVENT_SoldierGotHit( MINI_GRENADE, 10, 200, pSoldier->ubDirection, 0, pSoldier->ubID, 0, ANIM_CROUCH, 0, sNewGridNo ); + } + } + } + else + { + // Snap: get cumulative noise reduction from the weapon and its attachments + UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); + if ( ubVolume * noisefactor > 25000 ) + { // Snap: hack this to prevent overflow (damn miserly programmers!) + ubVolume = 250; + } + else + { + ubVolume = __max( 1, ( ubVolume * GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) / 100 ); + } + } + + MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->pathing.bLevel, pSoldier->bOverTerrainType, ubVolume, NOISE_GUNFIRE ); + + if ( pSoldier->bDoBurst ) + { + // done, if bursting, increment + pSoldier->bDoBurst++; + } + + // CJC: since jamming is no longer affected by reliability, increase chance of status going down for really unreliabile guns + //INT16 ammoReliability = 0; // Madd: ammo reliability affects gun + + //if ( Item[usItemNum].usItemClass == IC_GUN ) + //{ + // OBJECTTYPE *pGun = &(pSoldier->inv[pSoldier->ubAttackingHand]); + // ammoReliability = Item[(*pGun)[0]->data.gun.usGunAmmoItem].bReliability; + //} + + uiDepreciateTest = BASIC_DEPRECIATE_CHANCE + 3 * GetReliability( &(pSoldier->inv[pSoldier->ubAttackingHand]) ); + + if ( !PreRandom( uiDepreciateTest ) && ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > 1) ) + { + pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus--; + } + + // reduce monster smell (gunpowder smell) + if ( pSoldier->aiData.bMonsterSmell > 0 && Random( 2 ) == 0 ) + { + pSoldier->aiData.bMonsterSmell--; + } + +// manual recharge + if (Weapon[Item[usItemNum].ubClassIndex].APsToReloadManually > 0) + pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER; +// + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("UseGun: done")); + return( TRUE ); +} BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) { + if(UsingNewCTHSystem() == true) + return UseGunNCTH(pSoldier, sTargetGridNo); + UINT32 uiHitChance, uiDiceRoll; INT16 sXMapPos, sYMapPos; INT16 sAPCost; @@ -1691,9 +2333,39 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) { fCalculateCTHDuringGunfire = TRUE; uiHitChance = CalcChanceToHitGun( pSoldier, sTargetGridNo, pSoldier->aiData.bAimTime, pSoldier->bAimShotLocation ); + //CHRISL: + //pSoldier->CTH.push_back(uiHitChance); + //if(pSoldier->bDoAutofire == pSoldier->bDoBurst && pSoldier->CTH.size() > 0) + // pSoldier->CTH.clear(); } fCalculateCTHDuringGunfire = FALSE; +//ddd{ . silencer + if ( (Item[ usItemNum ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor) + { + OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); + if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) ) + { + for (attachmentList::iterator iter = (*pInHand)[0]->attachments.begin(); iter != (*pInHand)[0]->attachments.end(); ++iter) + { + if (Item[iter->usItem].hidemuzzleflash ) + { + OBJECTTYPE* pA= &(*iter); + if ( (*pA)[0]->data.objectStatus >=USABLE) + { + INT16 ammoReliability = Item[(*pInHand)[0]->data.gun.usGunAmmoItem].bReliability; + INT16 uiDepreciateTest = BASIC_DEPRECIATE_CHANCE + 3 * + (Item[ iter->usItem ].bReliability + ammoReliability); + if ( !PreRandom( uiDepreciateTest ) && ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > 1) ) + (*pA)[0]->data.objectStatus--; + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"rel =%d ",Item[ iter->usItem ].bReliability ); + } + } + } + } + } //if ( Item[ usItemNum ].usItemClass == IC_GUN ) +//ddd} + //DIGICRAB: Barrel extender wear code // Relocated from CalcChanceToHitGun if ( Item[ usItemNum ].usItemClass == IC_GUN ) @@ -1703,7 +2375,7 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) // lalien: search for barrel extender not for any item with range bonus. (else barrel extender will fall off even when none is attached) OBJECTTYPE* pAttachment = FindAttachment( pInHand, GUN_BARREL_EXTENDER ); - if ( pAttachment ) + if ( pAttachment->exists() ) { // reduce status and see if it falls off (*pAttachment)[0]->data.objectStatus -= (INT8) Random( 2 ); @@ -1728,7 +2400,9 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) if(*iter == *pAttachment) { AddItemToPool( pSoldier->sGridNo, pAttachment, 1, pSoldier->pathing.bLevel, 0, -1 ); - iter = (*pInHand)[0]->attachments.erase(iter); + + iter = (*pInHand)[0]->RemoveAttachmentAtIter(iter); + break; } } @@ -1958,7 +2632,13 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pSoldier->inv[HANDPOS].usItem , pSoldier->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) ); IgniteExplosion( pSoldier->ubID, CenterX( pSoldier->sGridNo ), CenterY( pSoldier->sGridNo ), 0, pSoldier->sGridNo, pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem, pSoldier->pathing.bLevel ); - pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + + OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pSoldier->inv[pSoldier->ubAttackingHand ]), pSoldier->inv[pSoldier->ubAttackingHand ].usItem ); + if(pLaunchable){ + pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem; + } else { + pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + } } // Reduce again for attack end 'cause it has been incremented for a normal attack // @@ -2039,16 +2719,19 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) pSoldier->bDoBurst++; } + /* //WarmSteel - Replaced with GetReliability( pObj ) // CJC: since jamming is no longer affected by reliability, increase chance of status going down for really unreliabile guns INT16 ammoReliability = 0; // Madd: ammo reliability affects gun + if ( Item[usItemNum].usItemClass == IC_GUN ) { OBJECTTYPE *pGun = &(pSoldier->inv[pSoldier->ubAttackingHand]); ammoReliability = Item[(*pGun)[0]->data.gun.usGunAmmoItem].bReliability; } + */ - uiDepreciateTest = BASIC_DEPRECIATE_CHANCE + 3 * (Item[ usItemNum ].bReliability + ammoReliability); + uiDepreciateTest = BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ) ); if ( !PreRandom( uiDepreciateTest ) && ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > 1) ) { @@ -2117,6 +2800,15 @@ BOOLEAN UseBlade( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) iDiceRoll = (INT32) PreRandom( 100 ); //sprintf( gDebugStr, "Hit Chance: %d %d", (int)uiHitChance, uiDiceRoll ); + // SANDRO - new mercs' records + if ( pSoldier->bTeam == gbPlayerNum && pSoldier->ubProfile != NO_PROFILE ) + { + gMercProfiles[ pSoldier->ubProfile ].records.usBladeAttacks++; + if ( iDiceRoll < iHitChance ) + { + gMercProfiles[ pSoldier->ubProfile ].records.usShotsHit++; + } + } // WDS 07/19/2008 - Random number use fix if ( iDiceRoll < iHitChance ) @@ -2158,6 +2850,10 @@ BOOLEAN UseBlade( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus -= (INT8) Random( bMaxDrop ); // 0 to (maxDrop - 1) } + // SANDRO - new merc records - times wounded (stabbed) + if ( pTargetSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pTargetSoldier->ubProfile ].records.usTimesWoundedStabbed++; + // Send event for getting hit memset( &(SWeaponHit), 0, sizeof( SWeaponHit ) ); SWeaponHit.usSoldierID = pTargetSoldier->ubID; @@ -2263,6 +2959,7 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea BOOLEAN fNoMoreItems = FALSE; // The enemy has no more items to steal! BOOLEAN fNoMoreItemInHand = FALSE; BOOLEAN fSoldierCollapsed = FALSE; + BOOLEAN fStealAttempt = FALSE; // added - SANDRO // Deduct points! // August 13 2002: unless stealing - APs already deducted elsewhere @@ -2276,6 +2973,7 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea else { // APs were already reduced! + //SANDRO - actually we will redure them here, but lower and based on number of items stolen. } // See if a guy is here! @@ -2292,7 +2990,7 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea if (fStealing) { // Calculate the possible chance to steal! - if ( AM_A_ROBOT( pTargetSoldier ) || TANK( pTargetSoldier ) || CREATURE_OR_BLOODCAT( pTargetSoldier ) || TANK( pTargetSoldier ) ) + if ( AM_A_ROBOT( pTargetSoldier ) || TANK( pTargetSoldier ) || CREATURE_OR_BLOODCAT( pTargetSoldier ) || TANK( pTargetSoldier ) || (SOLDIER_CLASS_MILITIA(pTargetSoldier->ubSoldierClass) && (gGameExternalOptions.ubMilitiaDropEquipment != 2)) ) // added militia here - SANDRO { iHitChance = 0; } @@ -2342,75 +3040,168 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea // ----------------------------------- if (fStealing ) { + // SANDRO - unable to steal from militia if they are not allowed to drop equipment + if (SOLDIER_CLASS_MILITIA(pTargetSoldier->ubSoldierClass) && (gGameExternalOptions.ubMilitiaDropEquipment != 2) ) + { + DeductPoints( pSoldier, (APBPConstants[AP_STEAL_ITEM] / 5), 0 ); + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); + return ( TRUE ); + } + fFailure=FALSE; + // WDS 07/19/2008 - Random number use fix + // Do we have the chance to steal more than 1 item? + // SANDRO - taking items from collapsed soldiers is treated differently + if (( fSoldierCollapsed || (!gGameExternalOptions.fEnhancedCloseCombatSystem && iDiceRoll < (iHitChance * 2 / 3))) && pSoldier->bTeam == gbPlayerNum ) + { + // first, charge extra Aps, because it's difficlut to pickup from other soldier + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + DeductPoints( pSoldier, (GetBasicAPsToPickupItem( pSoldier ) * 2), 0 ); + + // The item that the enemy holds in his hand before the stealing + usOldItem = pTargetSoldier->inv[HANDPOS].usItem; + + INT16 sNumStolenItems = StealItems(pSoldier, pTargetSoldier,&ubIndexRet); + + // We have only stolen 1 item, because the enemy has not more than one item. + if ( sNumStolenItems == 1) + { + // charge Aps + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + DeductPoints( pSoldier, GetBasicAPsToPickupItem( pSoldier ), 0 ); + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_STOLE_SOMETHING ], pSoldier->name, ShortItemNames[ pTargetSoldier->inv[ubIndexRet].usItem ] ); + if (pTargetSoldier->inv[ubIndexRet].MoveThisObjectTo(gTempObject, 1) == 0) { + + // Try to place the item in the merc inventory + if (!AutoPlaceObject( pSoldier, &gTempObject, TRUE )) + { + // Place the item on the ground + AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + } + } + + // The item that the enemy holds in his hand before the stealing + usNewItem = pTargetSoldier->inv[HANDPOS].usItem; + + if (usOldItem != usNewItem) + { + pTargetSoldier->ReLoadSoldierAnimationDueToHandItemChange( usOldItem, usNewItem ); + } + } + // The enemy has no more items to steal + else if (sNumStolenItems == 0) + { + fNoMoreItems = TRUE; + } + } // WDS 07/19/2008 - Random number use fix // Do we have luck on stealing? - if ( iDiceRoll < iHitChance && iHitChance > 0 ) + else if ( iDiceRoll < iHitChance && iHitChance > 0 ) { - // WDS 07/19/2008 - Random number use fix - // Do we have the chance to steal more than 1 item? - if (( iDiceRoll < iHitChance * 2 / 3) || (pTargetSoldier->bCollapsed)) + if ( pTargetSoldier->inv[HANDPOS].exists() == true ) { - // The item that the enemy holds in his hand before the stealing - usOldItem = pTargetSoldier->inv[HANDPOS].usItem; + UINT16 usOldItemTarget = pTargetSoldier->inv[HANDPOS].usItem; - INT16 sNumStolenItems = StealItems(pSoldier, pTargetSoldier,&ubIndexRet); + fStealAttempt = TRUE; // added for check - // We have only stolen 1 item, because the enemy has not more than one item. - if ( sNumStolenItems == 1) + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_STOLE_SOMETHING ], pSoldier->name, ShortItemNames[ pTargetSoldier->inv[HANDPOS].usItem ] ); + + // if successful - place the item to our hands + if (iDiceRoll < (iHitChance * 2 / 3) && gGameExternalOptions.fEnhancedCloseCombatSystem) { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_STOLE_SOMETHING ], pSoldier->name, ShortItemNames[ pTargetSoldier->inv[ubIndexRet].usItem ] ); - if (pTargetSoldier->inv[ubIndexRet].MoveThisObjectTo(gTempObject, 1) == 0) { + usOldItem = pSoldier->inv[HANDPOS].usItem; + OBJECTTYPE oTempObjectSecondHand; + INT8 bEmptySl; + oTempObjectSecondHand.usItem = 0; - // Try to place the item in the merc inventory - if (!AutoPlaceObject( pSoldier, &gTempObject, TRUE )) + // if we have something in main hand, place it into inventory or on the ground + if (pSoldier->inv[HANDPOS].exists() == true ) + { + if( pSoldier->bTeam != gbPlayerNum ) // for enemies, ignore rules and place it anywhere + { + bEmptySl = FindEmptySlotWithin( pSoldier, BIGPOCKSTART, NUM_INV_SLOTS ); + SwapObjs( pSoldier, HANDPOS, bEmptySl, TRUE ); + } + else if (!PlaceInAnyPocket( pSoldier, &pSoldier->inv[HANDPOS], FALSE, 5)) + { + if (!AutoPlaceObject( pSoldier, &pSoldier->inv[HANDPOS], FALSE, 5)) + AddItemToPool( pSoldier->sGridNo, &pSoldier->inv[HANDPOS], 1, pSoldier->pathing.bLevel, 0, -1 ); + } + } + // if twohanded item, place the secondhand item if any to temp space + if (pSoldier->inv[SECONDHANDPOS].exists() == true && Item[pTargetSoldier->inv[HANDPOS].usItem].twohanded) + { + if( pSoldier->bTeam != gbPlayerNum ) // for enemies, ignore rules and place it anywhere + { + bEmptySl = FindEmptySlotWithin( pSoldier, BIGPOCKSTART, NUM_INV_SLOTS ); + SwapObjs( pSoldier, SECONDHANDPOS, bEmptySl, TRUE ); + } + else + { + pSoldier->inv[SECONDHANDPOS].MoveThisObjectTo(oTempObjectSecondHand, 1); + } + } + // now take the item + if (pTargetSoldier->inv[HANDPOS].MoveThisObjectTo(gTempObject, 1) == 0) + { + if (PlaceObject( pSoldier, HANDPOS, &gTempObject )) + { + pSoldier->ReLoadSoldierAnimationDueToHandItemChange( usOldItem, gTempObject.usItem ); + if( pSoldier->bTeam != gbPlayerNum ) // make sure item is droppable now, so we don't lose our gun if killed this enemy + { + pSoldier->inv[HANDPOS].fFlags &= ~OBJECT_UNDROPPABLE; + } + } + else { - // Place the item on the ground AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); } } - - // The item that the enemy holds in his hand before the stealing - usNewItem = pTargetSoldier->inv[HANDPOS].usItem; - - if (usOldItem != usNewItem) + // if second hand item was removed place it now somewhere + if (oTempObjectSecondHand.usItem != 0 ) { - pTargetSoldier->ReLoadSoldierAnimationDueToHandItemChange( usOldItem, usNewItem ); + if (!PlaceInAnyPocket( pSoldier, &pSoldier->inv[HANDPOS], FALSE, 5)) + { + if (!AutoPlaceObject( pSoldier, &oTempObjectSecondHand, FALSE )) + { + AddItemToPool( pSoldier->sGridNo, &oTempObjectSecondHand, 1, pSoldier->pathing.bLevel, 0, -1 ); + } + } } - } - // The enemy has no more items to steal - else if (sNumStolenItems == 0) - { - fNoMoreItems = TRUE; - } - } - // We had not much luck, so we can only steal 1 item. - else if ( pTargetSoldier->inv[HANDPOS].exists() == true ) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_STOLE_SOMETHING ], pSoldier->name, ShortItemNames[ pTargetSoldier->inv[HANDPOS].usItem ] ); - usOldItem = pTargetSoldier->inv[HANDPOS].usItem; - if ( pSoldier->bTeam == gbPlayerNum ) - { - pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); - } + // add to merc records + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usItemsStolen++; + } // Item dropped somewhere... roll based on the same chance to determine where! - if (pTargetSoldier->inv[HANDPOS].MoveThisObjectTo(gTempObject, 1) == 0) { - iDiceRoll = (INT32) PreRandom( 100 ); - if (iDiceRoll < iHitChance) + else + { + if ( pSoldier->bTeam == gbPlayerNum ) { - // Drop item in the our tile - AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + pSoldier->DoMercBattleSound( BATTLE_SOUND_CURSE1 ); } - else + if (pTargetSoldier->inv[HANDPOS].MoveThisObjectTo(gTempObject, 1) == 0) { - // Drop item in the target's tile - AddItemToPool( pTargetSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + iDiceRoll = (INT32) PreRandom( 100 ); + if (iDiceRoll < iHitChance) + { + // Drop item in the our tile + AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + } + else + { + // Drop item in the target's tile + AddItemToPool( pTargetSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, 0, -1 ); + } } + // add to merc records + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usItemsStolen++; } // Reload buddy's animation... - pTargetSoldier->ReLoadSoldierAnimationDueToHandItemChange( usOldItem, NOTHING ); + pTargetSoldier->ReLoadSoldierAnimationDueToHandItemChange( usOldItemTarget, NOTHING ); } // Enemy has no item in his hand. else @@ -2426,6 +3217,44 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea fFailure=TRUE; } + // SANDRO - Enhanced Close Combat System + // Deduct APs for stealing now (moved from Soldier Control.cpp) - SANDRO + // If stolen something or fail to steal, reduce APs by the full amount + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + if (fSoldierCollapsed) + { + // APs are reduced in Handle Items.cpp in "SoldierStealItemFromSoldier" + } + else if ( fStealAttempt || (fFailure == TRUE)) + { + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && ( gGameOptions.fNewTraitSystem )) + { + DeductPoints( pSoldier, max( 1, (INT16)((APBPConstants[AP_STEAL_ITEM] * (100 - gSkillTraitValues.ubMAReducedAPsToSteal * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/ 100) + 0.5)), 200); + } + else + { + DeductPoints( pSoldier, APBPConstants[AP_STEAL_ITEM], 200 ); + } + } + // Only 1/7 of original AP cost, if the enemy has nothing to steal + else if ((fNoMoreItems == TRUE) || (fNoMoreItemInHand == TRUE)) + { + DeductPoints( pSoldier, (APBPConstants[AP_STEAL_ITEM] / 7), 0 ); + } + } + else + { + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && ( gGameOptions.fNewTraitSystem )) + { + DeductPoints( pSoldier, max( 1, (INT16)((APBPConstants[AP_STEAL_ITEM] * (100 - gSkillTraitValues.ubMAReducedAPsToSteal * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ))/ 100) + 0.5)), 0); + } + else + { + DeductPoints( pSoldier, APBPConstants[AP_STEAL_ITEM], 0 ); + } + } + // We failed to steal something! if (fFailure) { @@ -2466,20 +3295,54 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea { if (fFailure == FALSE) { - // We were successfull in stealing. Give some experience - StatChange( pSoldier, STRAMT, 8, FALSE ); - StatChange( pSoldier, DEXTAMT, 3, FALSE ); - StatChange( pSoldier, AGILAMT, 3, FALSE ); + // SANDRO - Enhanced Close Combat System - experience for stealing changed + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + // stealing from unconsious opponents is not rewarded much + if (fSoldierCollapsed) + { + StatChange( pSoldier, DEXTAMT, 1, FALSE ); + } + else + { + // We were successfull in stealing. Give some experience + StatChange( pSoldier, STRAMT, 6, FALSE ); + StatChange( pSoldier, DEXTAMT, 10, FALSE ); + StatChange( pSoldier, AGILAMT, 10, FALSE ); + } + } + else + { + // We were successfull in stealing. Give some experience + StatChange( pSoldier, STRAMT, 8, FALSE ); + StatChange( pSoldier, DEXTAMT, 3, FALSE ); + StatChange( pSoldier, AGILAMT, 3, FALSE ); + } } else { - // failed a steal; give some experience - StatChange( pSoldier, STRAMT, 4, FROM_FAILURE ); - StatChange( pSoldier, DEXTAMT, 1, FROM_FAILURE ); - StatChange( pSoldier, AGILAMT, 1, FROM_FAILURE ); + // SANDRO - Enhanced Close Combat System - experience for stealing changed + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + // failed a steal; give some experience - slightly changed by SANDRO + StatChange( pSoldier, STRAMT, 2, FROM_FAILURE ); + StatChange( pSoldier, DEXTAMT, 4, FROM_FAILURE ); + StatChange( pSoldier, AGILAMT, 4, FROM_FAILURE ); + } + else + { + // failed a steal; give some experience + StatChange( pSoldier, STRAMT, 4, FROM_FAILURE ); + StatChange( pSoldier, DEXTAMT, 1, FROM_FAILURE ); + StatChange( pSoldier, AGILAMT, 1, FROM_FAILURE ); + } } } + // SANDRO - Enhanced Close Combat System - Notice merc after stealing + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + pTargetSoldier->EVENT_SetSoldierDesiredDirection( GetDirectionFromGridNo( pSoldier->sGridNo, pTargetSoldier ) ); + // 0verhaul: Also handled in the animation transition // #ifdef JA2BETAVERSION // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - steal") ); @@ -2492,11 +3355,25 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea // ----------------------------------- else { - // ATE/CC: if doing ninja spin kick (only), automatically make it a hit - if ( pSoldier->usAnimState == NINJA_SPINKICK) + // SANDRO - new mercs' records + if ( pSoldier->bTeam == gbPlayerNum && pSoldier->ubProfile != NO_PROFILE ) { - // Let him to succeed by a random amount - iDiceRoll = PreRandom( iHitChance ); + gMercProfiles[ pSoldier->ubProfile ].records.usHtHAttacks++; + if ( iDiceRoll < iHitChance ) + { + gMercProfiles[ pSoldier->ubProfile ].records.usShotsHit++; + } + } + + // SANDRO - Enhanced Close Combat System - spinning kick is not automatic but just more damaging + if (!gGameExternalOptions.fEnhancedCloseCombatSystem) + { + // ATE/CC: if doing ninja spin kick (only), automatically make it a hit + if ( pSoldier->usAnimState == NINJA_SPINKICK) + { + // Let him to succeed by a random amount + iDiceRoll = PreRandom( iHitChance ); + } } if ( pSoldier->bTeam == gbPlayerNum && pTargetSoldier->bTeam != gbPlayerNum ) @@ -2507,6 +3384,28 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea { ubExpGain = 8; + // SANDRO - Enhanced Close Combat System - EXP given based on type of attack + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + // Increased EXP for head strike + if (pSoldier->bAimShotLocation == AIM_SHOT_HEAD) + { + ubExpGain += 2; + } + // Decreased EXP for leg strike + else if (pSoldier->bAimShotLocation == AIM_SHOT_LEGS) + { + ubExpGain -= 4; + } + + // Double EXP for focused attack + if ( (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6)) && + ((HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT)) && gGameOptions.fNewTraitSystem )) + { + ubExpGain *= 2; + } + } + if ( pTargetSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE || AM_A_ROBOT( pTargetSoldier ) || TANK( pTargetSoldier ) ) { ubExpGain = 0; @@ -2516,15 +3415,47 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea ubExpGain /= 2; } - - StatChange( pSoldier, DEXTAMT, ubExpGain, FALSE ); - StatChange( pSoldier, STRAMT, (ubExpGain+1)/3, FALSE ); - StatChange( pSoldier, AGILAMT, (ubExpGain+1)/3, FALSE ); + // SANDRO - Enhanced Close Combat System + if ( gGameExternalOptions.fEnhancedCloseCombatSystem && pTargetSoldier->bCollapsed) + { + // beating unconscious enemy is a matter of brute strength, so give exp mostly to Stregnth + StatChange( pSoldier, DEXTAMT, (ubExpGain+1)/3, FALSE ); + StatChange( pSoldier, STRAMT, ubExpGain + 1, FALSE ); + StatChange( pSoldier, AGILAMT, (ubExpGain+1)/3, FALSE ); + } + else + { + StatChange( pSoldier, DEXTAMT, ubExpGain, FALSE ); + StatChange( pSoldier, STRAMT, (ubExpGain+1)/3, FALSE ); + StatChange( pSoldier, AGILAMT, (ubExpGain+1)/3, FALSE ); + } } else { ubExpGain = 4; + // SANDRO - Enhanced Close Combat System - EXP given based on type of attack + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + // Increased EXP for head strike + if (pSoldier->bAimShotLocation == AIM_SHOT_HEAD) + { + ubExpGain += 1; + } + // Decreased EXP for leg strike + else if (pSoldier->bAimShotLocation == AIM_SHOT_LEGS) + { + ubExpGain -= 2; + } + + // Double EXP for focused attack + if ( (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6)) && + ((HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT)) && gGameOptions.fNewTraitSystem ) ) + { + ubExpGain *= 2; + } + } + if ( pTargetSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE || AM_A_ROBOT( pTargetSoldier ) || TANK( pTargetSoldier ) ) { ubExpGain = 0; @@ -2534,7 +3465,6 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea ubExpGain /= 2; } - StatChange( pSoldier, DEXTAMT, ubExpGain, FALSE ); StatChange( pSoldier, STRAMT, (ubExpGain+1)/3, FALSE ); StatChange( pSoldier, AGILAMT, (ubExpGain+1)/3, FALSE ); @@ -2545,12 +3475,48 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea // being attacked... if successfully dodged, give experience if ( iDiceRoll > iHitChance ) { - StatChange( pTargetSoldier, DEXTAMT, 8, FALSE ); - StatChange( pTargetSoldier, STRAMT, 3, FALSE ); - StatChange( pTargetSoldier, AGILAMT, 3, FALSE ); + // SANDRO - Enhanced Close Combat System - More logical - give EXP for dodging to Agility most + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + StatChange( pTargetSoldier, DEXTAMT, 5, FALSE ); // 4 istead of 8 + StatChange( pTargetSoldier, STRAMT, 2, FALSE ); // 2 instead of 3 + StatChange( pTargetSoldier, AGILAMT, 8, FALSE ); // 8 instead of 3 + } + else + { + StatChange( pTargetSoldier, DEXTAMT, 8, FALSE ); + StatChange( pTargetSoldier, STRAMT, 3, FALSE ); + StatChange( pTargetSoldier, AGILAMT, 3, FALSE ); + } } } + // SANDRO - Enhanced Close Combat System - Add dodge animation of target if missed ninja spin kick + if ( (iDiceRoll >= iHitChance) && pSoldier->usAnimState == NINJA_SPINKICK && gGameExternalOptions.fEnhancedCloseCombatSystem + && gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND && IS_MERC_BODY_TYPE( pTargetSoldier )) + { + pTargetSoldier->ChangeSoldierState( DODGE_ONE, 0 , FALSE ); + // after dodging melee attack go to apropriate stance + if ( (gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH)) + { + if ((((NUM_SKILL_TRAITS( pTargetSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || + (HAS_SKILL_TRAIT( pTargetSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && + pTargetSoldier->ubBodyType == REGMALE ) + { + //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH; + pTargetSoldier->usPendingAnimation = NINJA_BREATH ; + } + else + { + pTargetSoldier->usPendingAnimation = PUNCH_BREATH ; + } + } + else if ( (gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE)) + { + //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH; + pTargetSoldier->usPendingAnimation = KNIFE_BREATH ; + } + } // WDS 07/19/2008 - Random number use fix if ( iDiceRoll < iHitChance || AreInMeanwhile( ) ) @@ -2558,6 +3524,10 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea // CALCULATE DAMAGE! iImpact = HTHImpact( pSoldier, pTargetSoldier, (iHitChance - iDiceRoll), FALSE ); + // SANDRO - new merc records - times wounded (punched) + if ( pTargetSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pTargetSoldier->ubProfile ].records.usTimesWoundedPunched++; + // Send event for getting hit memset( &(SWeaponHit), 0, sizeof( SWeaponHit ) ); SWeaponHit.usSoldierID = pTargetSoldier->ubID; @@ -2687,6 +3657,14 @@ BOOLEAN UseThrown( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) } + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass == IC_GRENADE || Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass == IC_BOMB || Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass == IC_THROWN) + { + gMercProfiles[ pSoldier->ubProfile ].records.usGrenadesThrown++; + } + ///////////////////////////////////////////////////////////////////////////////////// + CalculateLaunchItemParamsForThrow( pSoldier, sTargetGridNo, pSoldier->bTargetLevel, (INT16)(pSoldier->bTargetLevel * 256 ), &(pSoldier->inv[ HANDPOS ] ), (INT8)(uiDiceRoll - uiHitChance), THROW_ARM_ITEM, 0 ); //AXP 25.03.2007: Cleaned up throwing AP costs. Now only turning + stance change AP @@ -2737,7 +3715,7 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) pObj = &(pSoldier->inv[HANDPOS]); attachmentList::iterator iter; for (iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) { - if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV ) + if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV && iter->exists()) { break; } @@ -2748,7 +3726,10 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) return( FALSE ); } - if ( Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize > 1 || ( Item[pObj->usItem].grenadelauncher && GetMagSize(pObj) > 1 )) + //CHRISL: Added a magsize value to Explosives.xml which is checked by GetExpMagSize. This will allow OAS to load individual grenades into + // multi-launch grenades and fire correctly + //if ( Weapon[GetAttachedGrenadeLauncher(pObj)].ubMagSize > 1 || ( Item[pObj->usItem].grenadelauncher && GetMagSize(pObj) > 1 )) + if(GetExpMagSize(&(*iter)) > 1) CreateItem( iter->usItem, 100, &Launchable ); else CreateItem( iter->usItem, (*iter)[0]->data.objectStatus, &Launchable ); @@ -2831,6 +3812,15 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) DeductPoints( pSoldier, sAPCost, 0 ); } + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - new mercs' records + if ( Item[ usItemNum ].usItemClass == IC_LAUNCHER || Item[usItemNum].grenadelauncher || + Item[usItemNum].rocketlauncher || Item[usItemNum].singleshotrocketlauncher || Item[usItemNum].mortar ) + { + gMercProfiles[ pSoldier->ubProfile ].records.usMissilesLaunched++; + } + ///////////////////////////////////////////////////////////////////////////////////// + CalculateLaunchItemParamsForThrow( pSoldier, sTargetGridNo, pSoldier->bTargetLevel, 0, &Launchable, (INT8)(uiDiceRoll - uiHitChance), THROW_ARM_ITEM, 0 ); iID = CreatePhysicalObject( pSoldier->pTempObject, pSoldier->pThrowParams->dLifeSpan, pSoldier->pThrowParams->dX, pSoldier->pThrowParams->dY, pSoldier->pThrowParams->dZ, pSoldier->pThrowParams->dForceX, pSoldier->pThrowParams->dForceY, pSoldier->pThrowParams->dForceZ, pSoldier->ubID, pSoldier->pThrowParams->ubActionCode, pSoldier->pThrowParams->uiActionData, FALSE ); @@ -3051,7 +4041,14 @@ void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 s DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("WeaponHit: RPG7 item: %d, Ammo: %d",pSoldier->inv[HANDPOS].usItem , pSoldier->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) ); IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem, pTargetSoldier->pathing.bLevel ); - pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + + //This is just to make multishot launchers work in semi auto. It's not really a permanent solution because it still doesn't allow autofire, but it will do for now. + OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pSoldier->inv[pSoldier->ubAttackingHand ]), pSoldier->inv[pSoldier->ubAttackingHand ].usItem ); + if(pLaunchable){ + pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem; + } else { + pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + } } else if ( AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].explosionSize > 1) { @@ -3172,7 +4169,14 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pAttacker->inv[HANDPOS].usItem , pAttacker->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) ); IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem , (INT8)( sZPos >= WALL_HEIGHT ) ); - pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + + //This is just to make multishot launchers work in semi auto. It's not really a permanent solution because it still doesn't allow autofire, but it will do for now. + OBJECTTYPE * pLaunchable = FindLaunchableAttachment( &(pAttacker->inv[pAttacker->ubAttackingHand ]), pAttacker->inv[pAttacker->ubAttackingHand ].usItem ); + if(pLaunchable){ + pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = pLaunchable->usItem; + } else { + pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE; + } } else if ( AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].explosionSize > 1) { @@ -3513,7 +4517,9 @@ void WindowHit( INT32 sGridNo, UINT16 usStructureID, BOOLEAN fBlowWindowSouth, B AniParams.uiFlags = ANITILE_FORWARD; pNode = CreateAnimationTile( &AniParams ); - + //dddokno{ +CompileWorldMovementCosts(); +//dddokno} PlayJA2Sample( GLASS_SHATTER1 + Random(2), RATE_11025, MIDVOLUME, 1, SoundDir( sGridNo ) ); } @@ -3544,7 +4550,7 @@ BOOLEAN InRange( SOLDIERTYPE *pSoldier, INT32 sGridNo ) else { // For given weapon, check range - if ( sRange <= GunRange( &(pSoldier->inv[HANDPOS]) ) ) + if ( sRange <= GunRange( &(pSoldier->inv[HANDPOS]), pSoldier ) ) // SANDRO - added argument { return( TRUE ); } @@ -3553,205 +4559,974 @@ BOOLEAN InRange( SOLDIERTYPE *pSoldier, INT32 sGridNo ) return( FALSE ); } -UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ) +UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ) { - //SOLDIERTYPE *vicpSoldier; - SOLDIERTYPE * pTarget; - INT32 iChance, iRange, iSightRange, iMaxRange, iBonus; //, minRange; - //rain - //INT32 iScopeBonus; - //end rain - INT32 iGunCondition, iMarksmanship; - INT32 iPenalty; + ////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: + // + // The CTH/Firing system has been completely revamped. CTH is now the result of + // two completely separate calculations. One takes into account skill and conditions, + // the other relies on gun accuracy. + // See also UseGun() for further notes. + // + ////////////////////////////////////////////////////////////////////////////////// + + // Basic defines + SOLDIERTYPE * pTarget; + INT32 iChance, iRange, iSightRange; //, minRange; + UINT16 usInHand; OBJECTTYPE * pInHand; -// INT8 bAttachPos; - INT8 bBandaged; - INT16 sDistVis; - UINT8 ubAdjAimPos; + INT8 bBandaged, iTraitModifier; + INT16 sDistVis, sDistVisNoScope; UINT8 ubTargetID; bool highPowerScope = false; - UINT32 pScope; - - // HEADROCK HAM 3.5: Variable holds total autofire penalty. INT16 sTotalAutofirePenalty = 0; - - DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun")); - - if ( pSoldier->stats.bMarksmanship == 0 ) - { - // HEADROCK: (HAM) Altered to accept external arguments - // return( MINCHANCETOHIT ); - return( gGameExternalOptions.ubMinimumCTH ); - } - + bool fCantSeeTarget = false; + FLOAT scopeRangeMod; + // make sure the guy's actually got a weapon in his hand! pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); usInHand = pSoldier->usAttackingWeapon; - //CHRISL: We have new modifiers when using a high power scope so find out if we have one from the start - for(attachmentList::iterator iter = (*pInHand)[0]->attachments.begin(); iter != (*pInHand)[0]->attachments.end(); iter++) - { - if(Item[iter->usItem].aimbonus > HIGH_POWER_SCOPE) - { - highPowerScope = true; - pScope = iter->usItem; - break; - } - } - - // DETERMINE BASE CHANCE OF HITTING - iGunCondition = WEAPON_STATUS_MOD( (*pInHand)[0]->data.gun.bGunStatus ); - - if (Item[usInHand].rocketlauncher ) - { - // use the same calculation as for mechanical thrown weapons - iMarksmanship = ( EffectiveDexterity( pSoldier ) + EffectiveMarksmanship( pSoldier ) + EffectiveWisdom( pSoldier ) + (10 * EffectiveExpLevel( pSoldier ) )) / 4; - // heavy weapons trait helps out - if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPS )) - { - iMarksmanship += gbSkillTraitBonus[HEAVY_WEAPS] * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS ); - } - } - else - { - iMarksmanship = EffectiveMarksmanship( pSoldier ); - - if ( AM_A_ROBOT( pSoldier ) ) - { - SOLDIERTYPE * pSoldier2; - - pSoldier2 = pSoldier->GetRobotController( ); - if ( pSoldier2 ) - { - iMarksmanship = __max( iMarksmanship, EffectiveMarksmanship( pSoldier2 ) ); - } - } - } - - // modify chance to hit by morale - iMarksmanship += GetMoraleModifier( pSoldier ); - - // penalize marksmanship for fatigue - iMarksmanship -= GetSkillCheckPenaltyForFatigue( pSoldier, iMarksmanship ); - - //if ( PTR_OURTEAM ) - //{ - // iChance = ( iMarksmanship * iGunCondition ) / 100; - //} - //else - { - if (iGunCondition >= iMarksmanship) - // base chance is equal to the shooter's marksmanship skill - iChance = iMarksmanship; - else - // base chance is equal to the average of marksmanship & gun's condition! - iChance = (iMarksmanship + iGunCondition) / 2; - } - // if shooting same target as the last shot - if (sGridNo == pSoldier->sLastTarget ) - iChance += AIM_BONUS_SAME_TARGET; // give a bonus to hit - - if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == PSYCHO ) - { - iChance += AIM_BONUS_PSYCHO; - } // calculate actual range (in units, 10 units = 1 tile) iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); - if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND ) - { - //CHRISL: Incur a penalty if using a highPowerScope - if(highPowerScope == true && iRange > Item[pScope].minrangeforaimbonus) - { - iPenalty = (Item[pScope].aimbonus * (iRange-Item[pScope].minrangeforaimbonus)) / 1000; - if (iPenalty > AIM_BONUS_PRONE) - { - iPenalty = AIM_BONUS_PRONE; + // Find a target in the tile + ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel ); // Target ubID + pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel ); // Target Pointer + + // Calculate how easy it is to handle this gun. + FLOAT iGunDifficulty = (FLOAT)(( Weapon[ usInHand ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(pInHand) )) / 100); + iGunDifficulty *= (FLOAT)(100 / APBPConstants[AP_MAXIMUM]); // Adjust for 100AP/25AP + FLOAT iGunBaseDifficulty = iGunDifficulty; + FLOAT iGunAimDifficulty = iGunDifficulty; + + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // + // CALCULATE LINE OF SIGHT + // + ///////////////////////////////////////////////////////////////////////////////////////////////////// + + //CHRISL: We have a new way to do this using a global variable + gbForceWeaponReady = true; + + sDistVis = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ) * CELL_X_SIZE; + + iSightRange = 0; + + if (ubTargetID != NOBODY && pSoldier->aiData.bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY) + iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false ); + if (iSightRange == 0) { // didn't do a bodypart-based test or can't see specific body part aimed at + iSightRange = SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, pSoldier->bTargetLevel, pSoldier->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT, false ); + } + if (iSightRange == 0) { // Can't see the target but we still need to know what the sight range would be if we could so we can deal with cover penalties + iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false, true ); + fCantSeeTarget = true; + } + + gbForceWeaponReady = false; + + //CHRIS: This next value needs to be determined with no vision modifiers from our weapon + gbForceWeaponNotReady = true; + sDistVisNoScope = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ) * CELL_X_SIZE; + gbForceWeaponNotReady = false; + scopeRangeMod = (float)sDistVis / (float)sDistVisNoScope; // percentage DistVis has been enhanced due to an attached scope + iSightRange = (INT32)(iSightRange / scopeRangeMod); + if(iSightRange > 0){ + iSightRange -= GetGearAimBonus ( pSoldier, iSightRange, ubAimTime ) * iSightRange / 100; + if ( gGameOptions.fNewTraitSystem ) { + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) { + iSightRange -= ((gSkillTraitValues.ubSNEffRangeToTargetReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )) * iSightRange) /100; } - iChance -= iPenalty; + } + else if ( HAS_SKILL_TRAIT( pSoldier, PROF_SNIPER_OT ) ) { + iSightRange -= ((gbSkillTraitBonus[ PROF_SNIPER_OT ] * NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )) * iSightRange) /100; + } + if (iSightRange < 1) { + iSightRange = 1; } } - // if shooter is crouched, he aims slightly better (to max of AIM_BONUS_CROUCHING) - else if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH ) + if(iSightRange > sDistVis) + fCantSeeTarget = true; + + ////////////////////////////////////////////////////////////////////////////////// + // First step: Calculate a base CTH value + // + // This "Base" CTH is a percentage value describing how well our gun's muzzle is aimed + // when not spending any extra effort on aiming. In other words, it's the most basic state, + // where the shooter only brings up the gun into the general direction of the target, and + // pulls the trigger. + // + // This is calculated first by factoring in skills, and later by adding up various conditional + // factors into a percentage which is then applied to those skills. + // + // The most important skill here is EXPERIENCE. + + FLOAT iBaseModifier = 0; + + INT8 bExperience = EffectiveExpLevel( pSoldier ); + INT8 bMarksmanship = EffectiveMarksmanship( pSoldier ); + INT8 bDexterity = EffectiveDexterity( pSoldier );; + INT8 bWisdom = EffectiveWisdom( pSoldier ); + + if ( bMarksmanship == 0 || bDexterity == 0 ) { - iBonus = iRange / 10; - if (iBonus > AIM_BONUS_CROUCHING) - { - iBonus = AIM_BONUS_CROUCHING; - } - iChance += iBonus; - //CHRISL: Incur a penalty if using a highPowerScope - if(highPowerScope == true && iRange > Item[pScope].minrangeforaimbonus) - { - iPenalty = ((Item[pScope].aimbonus/2) * (iRange-Item[pScope].minrangeforaimbonus)) / 1000; - if (iPenalty > AIM_BONUS_CROUCHING) - { - iPenalty = AIM_BONUS_CROUCHING; - } - iChance -= iPenalty; - } + return( gGameExternalOptions.ubMinimumCTH ); } - // if shooter is prone, he aims even better, except at really close range - else if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) + + // Calculate the basic value for BASE CTH by factoring in all the character's skills. + FLOAT iCombinedSkill = (FLOAT)(gGameCTHConstants.BASE_EXP*(bExperience*10)); + iCombinedSkill += (FLOAT)(gGameCTHConstants.BASE_MARKS * bMarksmanship); + iCombinedSkill += (FLOAT)(gGameCTHConstants.BASE_WIS * bWisdom); + iCombinedSkill += (FLOAT)(gGameCTHConstants.BASE_DEX * bDexterity); + + // Divide by the total coefficient value. + iCombinedSkill = (FLOAT)(iCombinedSkill / + (gGameCTHConstants.BASE_EXP+ + gGameCTHConstants.BASE_MARKS+ + gGameCTHConstants.BASE_WIS+ + gGameCTHConstants.BASE_DEX)); + + // At this point we have a value of 1 to 100. Divide by 3. + iCombinedSkill /= 3; + + // iCombinedSkill is now our basic CTH. Its range is 0 to 33. + iChance = (INT32)iCombinedSkill; + + // Add a flat Base bonus from the item and its attachments. + iChance += GetFlatBaseModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); + + // We now begin adding up factors that may increase or decrease Base CTH. They are pooled together to form a percentage + // value. + + // MORALE + INT8 iCurrentMorale = GetMoraleModifier(pSoldier); + if (iCurrentMorale > 0) { - if (iRange > MIN_PRONE_RANGE) + iBaseModifier += (FLOAT)(iCurrentMorale * gGameCTHConstants.BASE_HIGH_MORALE); + } + else if (iCurrentMorale < 0) + { + iBaseModifier += (FLOAT)(iCurrentMorale * gGameCTHConstants.BASE_LOW_MORALE); + } + + if ( gGameOptions.fNewTraitSystem ) + { + iTraitModifier = 0; + // Bonus for heavy weapons moved here from above to get instant CtH bonus and not marksmanship bonus, + // which is supressed by weapon condition + if (Item[usInHand].rocketlauncher || Item[usInHand].singleshotrocketlauncher) { - iBonus = iRange / 10; - if (iBonus > AIM_BONUS_PRONE) - { - iBonus = AIM_BONUS_PRONE; + iTraitModifier += gSkillTraitValues.bCtHModifierRocketLaunchers; // -25% for untrained mercs !!! + + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT )) + iTraitModifier += gSkillTraitValues.ubHWBonusCtHRocketLaunchers * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ); // +25% per trait + } + // Added CtH bonus for Gunslinger trait on pistols and machine-pistols + else if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierPistols; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iTraitModifier += gSkillTraitValues.ubGSBonusCtHPistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); // +10% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_M_PISTOL ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierMachinePistols; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && ((pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0) || !gSkillTraitValues.ubGSCtHMPExcludeAuto)) + iTraitModifier += gSkillTraitValues.ubGSBonusCtHMachinePistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); // +5% per trait + } + // Added CtH bonus for Machinegunner skill on assault rifles, SMGs and LMGs + else if ( Weapon[usInHand].ubWeaponType == GUN_AS_RIFLE ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierAssaultRifles; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iTraitModifier += gSkillTraitValues.ubAWBonusCtHAssaultRifles * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_SMG ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierSMGs; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iTraitModifier += gSkillTraitValues.ubAWBonusCtHSMGs * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_LMG ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierLMGs; // -10% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iTraitModifier += gSkillTraitValues.ubAWBonusCtHLMGs * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + // Added CtH bonus for Gunslinger trait on pistols and machine-pistols + else if ( Weapon[usInHand].ubWeaponType == GUN_SN_RIFLE ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierSniperRifles; // -10% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iTraitModifier += gSkillTraitValues.ubSNBonusCtHSniperRifles * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); // +5% per trait + } + // Added CtH bonus for Ranger skill on rifles and shotguns + else if ( Weapon[usInHand].ubWeaponType == GUN_RIFLE ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierRifles; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iTraitModifier += gSkillTraitValues.ubRABonusCtHRifles * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); // +5% per trait + //CHRISL: Why wouldn't sniper training include standard rifles which are often used as "poor-man sniper rifles" + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iTraitModifier += gSkillTraitValues.ubSNBonusCtHRifles * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_SHOTGUN ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierShotguns; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + iTraitModifier += gSkillTraitValues.ubRABonusCtHShotguns * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); // +10% per trait + } + + // Added small CtH penalty for robot if controller hasn't the Technician trait + if( AM_A_ROBOT( pSoldier ) ) + { + iTraitModifier += gSkillTraitValues.bCtHModifierRobot; // -10% + + if ( HAS_SKILL_TRAIT( pSoldier->GetRobotController(), TECHNICIAN_NT ) ) + iTraitModifier += gSkillTraitValues.ubTECtHControlledRobotBonus * NUM_SKILL_TRAITS( pSoldier->GetRobotController(), TECHNICIAN_NT ); // +10% per trait + } + + // Added character traits influence + if ( pSoldier->ubProfile != NO_PROFILE ) + { + // Sociable - better performance in groups + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs > 2 ) + iTraitModifier += 5; + else if ( bNumMercs > 0 ) + iTraitModifier += 2; } - // Snap: bipod bonus is now calculated in GetToHitBonus - //bAttachPos = FindAttachment( pInHand, BIPOD ); - //if (bAttachPos != ITEM_NOT_FOUND) - //{ // extra bonus to hit for a bipod, up to half the prone bonus itself - // iBonus += (iBonus * WEAPON_STATUS_MOD(GetBipodStatus(pInHand)) / 100) / 2; - //} - iChance += iBonus; + // Loner - better performance when alone + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs == 0 ) + iTraitModifier += 5; + else if ( bNumMercs <= 1 ) + iTraitModifier += 2; + } + // Aggressive - bonus on bursts/autofire + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + if (( pSoldier->bDoBurst || pSoldier->bDoAutofire ) && !ubAimTime ) + iTraitModifier += 5; + } + // Show-off - better performance if some babes around to impress + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SHOWOFF ); + if ( bNumMercs > 1 ) + iTraitModifier += 5; + else if ( bNumMercs > 0 ) + iTraitModifier += 2; + } + // Added disabilities + if ( pSoldier->ubProfile != NO_PROFILE ) + { + // Heat intolerant penalty + if ( MercIsHot( pSoldier ) ) + { + iTraitModifier -= 15; + } + // Small penalty for fear of insects in tropical sectors + else if ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) && MercIsInTropicalSector( pSoldier ) ) + { + // fear of insects, and we are in tropical sector + iTraitModifier -= 5; + } + } + } + // Dauntless - penalty for not taking proper cover + if (pTarget != NULL) + { + if ( pTarget->ubProfile != NO_PROFILE ) + { + if ( gMercProfiles[ pTarget->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + iTraitModifier += 5; + } + } + //Give 40% the normal stomp modifier as a base mod + iBaseModifier += (FLOAT)iTraitModifier * 0.4f; + } + else + { + // PSYCHO + if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO ) + { + iBaseModifier += (FLOAT)gGameCTHConstants.BASE_PSYCHO; } } - //Madd: inherent weapon accuracy bonus - iChance += Weapon[usInHand].bAccuracy; + // SHOOTING AT SAME TARGET AGAIN + if (sGridNo == pSoldier->sLastTarget ) + iBaseModifier += (FLOAT)gGameCTHConstants.BASE_SAME_TARGET; -// if ( !(Item[ usInHand ].fFlags & ITEM_TWO_HANDED) ) + ///////////////////////////////////////////// + // Gun Difficulty Modifiers + + // FIRING 1-HANDED WEAPONS if ( !(Item[ usInHand ].twohanded ) ) { - if (pSoldier->inv[SECONDHANDPOS].exists() == false) + if (pSoldier->inv[SECONDHANDPOS].exists() != false) { - // firing with gun in right hand, and second hand empty (ie: no grenade, med kit or anything there) - // Madd: easier to fire pistol/smg w/one hand free, essentially this will make pistols a little bit more accurate, and hopefully still useful later in the game - if (Weapon[usInHand].ubWeaponClass == HANDGUNCLASS) - iChance += AIM_BONUS_TWO_HANDED_PISTOL; + if ( pSoldier->IsValidSecondHandShot( ) ) + { + // Penalty for shooting two pistols. Ambidextrous trait halves this, once per skill level. + FLOAT iTempPenalty = (gGameCTHConstants.BASE_TWO_GUNS * iGunBaseDifficulty) - iGunBaseDifficulty; + INT8 traitLoop = (gGameOptions.fNewTraitSystem?NUM_SKILL_TRAITS( pSoldier, AMBIDEXTROUS_NT ):NUM_SKILL_TRAITS( pSoldier, AMBIDEXT_OT )); + + for (INT32 x = 0; x < traitLoop; x++) + { + iTempPenalty /= 2; + } + + iGunBaseDifficulty += iTempPenalty; + } + else + { + // Penalty for shooting a pistol with just one hand + iGunBaseDifficulty *= gGameCTHConstants.BASE_ONE_HANDED; + } + } + } + + // HEAVY WEAPON + if (Item[usInHand].rocketlauncher && !(gGameOptions.fNewTraitSystem) ) + { + // Penalty for shooting heavy weapons (launchers). Heavy Weapons skill halves this, once per skill level. + FLOAT iTempPenalty = (gGameCTHConstants.BASE_HEAVY_WEAPON * iGunBaseDifficulty) - iGunBaseDifficulty; + + for (INT32 x=0; x < NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS_OT ); x++) + { + iTempPenalty /= 2; + } + + iGunBaseDifficulty += iTempPenalty; + } + + // STANCE + switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) + { + case ANIM_CROUCH: + iGunBaseDifficulty *= gGameCTHConstants.BASE_CROUCHING_STANCE; + break; + case ANIM_PRONE: + iGunBaseDifficulty *= gGameCTHConstants.BASE_PRONE_STANCE; + break; + } + + // Percent based modifier from the gun and its attachments + iGunBaseDifficulty += (iGunBaseDifficulty * GetPercentHandlingModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight )) / 100; + + // End gun difficulty modifiers + ///////////////////////////////////////////// + + // Now apply Gun Difficulty to the Base Modifier. + iBaseModifier += iGunBaseDifficulty * gGameCTHConstants.BASE_DRAW_COST; + + // INJURY + if (pSoldier->stats.bLife < pSoldier->stats.bLifeMax) + { + FLOAT iTempPenalty = gGameCTHConstants.BASE_INJURY; + + // Bleeding damage is used as a percentage off the Max Life, giving a penalty of up to BASE_INJURY. + iBaseModifier += (pSoldier->bBleeding * iTempPenalty) / pSoldier->stats.bLifeMax; + + // Bandage damage is used similarly, but is only 1/3 as bad. + bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding; + iBaseModifier += ((bBandaged * iTempPenalty) / pSoldier->stats.bLifeMax) / 3; + } + + // FATIGUE + iBaseModifier += (gGameCTHConstants.BASE_FATIGUE * (100 - pSoldier->bBreath)) / 100; + + // DRUNKNESS + INT8 iDrunkness = GetDrunkLevel(pSoldier); + if (iDrunkness > 0) + { + iDrunkness -= 1; + iBaseModifier += gGameCTHConstants.BASE_DRUNK[iDrunkness]; + } + + // GASSED + if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) + { + iBaseModifier += gGameCTHConstants.BASE_GASSED; + } + + // BEING BANDAGED + if (pSoldier->ubServiceCount > 0) + { + iBaseModifier += gGameCTHConstants.BASE_BEING_BANDAGED; + } + + // SHOCK (SHOOTER) + if (pSoldier->aiData.bShock) + { + FLOAT iTempPenalty = gGameCTHConstants.BASE_SHOCK; + INT32 iShockPercentage = (pSoldier->aiData.bShock * 100) / gGameExternalOptions.ubMaxSuppressionShock; + + iBaseModifier += (iTempPenalty * iShockPercentage) / 100; + } + + ///////////// + // Target-specific tests + + INT32 iHeightDifference = 0; + if ( pTarget == NULL ) + { + // Shooting to roof. + if ( pSoldier->bTargetLevel > pSoldier->pathing.bLevel ) + { + iHeightDifference = 3 * pSoldier->bTargetLevel; + } + } + else + { + // HEIGHT DIFFERENCE + + UINT32 uiShooterHeight = 0; + UINT32 uiTargetHeight = 0; + + if ( pSoldier->pathing.bLevel > 0 ) + { + uiShooterHeight += 3 * pSoldier->pathing.bLevel; + } + + switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) + { + case ANIM_STAND: + uiShooterHeight += 2; + break; + case ANIM_CROUCH: + uiShooterHeight += 1; + break; + } + + if (pTarget->pathing.bLevel > 0) + { + uiTargetHeight += 3 * pTarget->pathing.bLevel; + } + + switch ( gAnimControl[ pTarget->usAnimState ].ubEndHeight ) + { + case ANIM_STAND: + switch (ubAimPos) + { + case AIM_SHOT_HEAD: + uiTargetHeight += 2; + break; + case AIM_SHOT_TORSO: + case AIM_SHOT_RANDOM: + case AIM_SHOT_GLAND: + uiTargetHeight += 1; + break; + } + break; + case ANIM_CROUCH: + switch (ubAimPos) + { + case AIM_SHOT_HEAD: + uiTargetHeight += 1; + break; + } + break; + } + + iHeightDifference = uiShooterHeight - uiTargetHeight; + if (iHeightDifference < 0) + { + iHeightDifference *= -1; } else { - // Madd: harder to fire smgs w/something in other hand - // SMGs are treated as pistols for these purpose except there is a -5 penalty; - if (Weapon[usInHand].ubWeaponClass == SMGCLASS) - { - iChance -= AIM_PENALTY_SMG; - } + iHeightDifference = 0; + } - if ( !HAS_SKILL_TRAIT( pSoldier, AMBIDEXT ) ) + // AGILITY OR EXPERIENCE + FLOAT iTempPenalty = __max((pTarget->stats.bExpLevel*10), pTarget->stats.bAgility); + iBaseModifier += (iTempPenalty * gGameCTHConstants.BASE_AGILE_TARGET) / 100; + } + + // Height difference is mitigated by range. A LONGER range reduces this penalty! + if (iRange > 0 && iHeightDifference > 0) + { + FLOAT iTempPenalty = gGameCTHConstants.BASE_SHOOTING_UPWARDS * iHeightDifference; + iTempPenalty /= iRange; + + iBaseModifier += iTempPenalty; + } + + // INVIS TARGET + if (fCantSeeTarget) + { + iBaseModifier += gGameCTHConstants.BASE_TARGET_INVISIBLE; + } + + // GAME DIFFICULTY + if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_PC ) && (pSoldier->bSide != gbPlayerNum) ) + { + iBaseModifier += gGameCTHConstants.BASE_DIFFICULTY[gGameOptions.ubDifficultyLevel]; + } + + // Percentage based-modifier from the weapon and its attachments + iBaseModifier += GetPercentBaseModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); + + + //////////////////////////////////// + // Finish BASE CTH calculation: + + + + iChance = (INT32)(iChance * (100+iBaseModifier)) / 100; + iChance = __max( iChance, 0 ); + iChance = __min( iChance, 100 ); + + + ////////////////////////////////////////////////////////////////////////////////// + // Second step: Calculate bonuses from aiming + // + // In this step, we figure out how much CTH we get from aiming. Naturally, we + // need extra aiming (bAimTime) to be applied. + // + // CTH is capped by a value determined by the shooter's skills. The better + // your skills, the higher CTH can go. A steady hand (DEX) and training + // (MRK) are paramount here. + // After that, the cap is raised or lowered by other factors, like fatigue + // or the size of the gun. + // + // Finally, we determine how much each Aim Click will give us. Returns are + // diminishing, so the more clicks we put in, the less CTH for each additional + // click. However, the last few points can be absolutely crucial for long-range + // shooting. + // + // Scope magnification can be important here, but only if the target is closer + // than the scope's minimum aiming range. If it is closer, the shooter begins + // to suffer aiming penalties which can render aiming almost useless. + + if (ubAimTime > 0) + { + + // Are we using a scope? If so, what's the range factor? + FLOAT iScopeMagFactor = GetBestScopeMagnificationFactor( pInHand, (UINT32)iRange ); + //CHRISL: This does make sense but it effectively makes high powered scopes worthless if a target is actually visible. As an example, a Battle Scope + // is going to have a iScopeMagFactor of 7. With a "NORMAL_SHOOTING_DISTANCE" also of 7, we're going to end up with uiBestScopeRange of 49. That's + // effectilvey saying that any target within 490m is "too close" for the scope to be effective. That by itself isn't realistic. But in JA2 it's also + // a big drawback. Consider that normally (excluding terrain, lighting and environment) you can see 26 tiles. The Battle Scope increases that by 50% + // in bright light, meaning you can see up to 39 tiles away. A target standing 49 tiles is considered "invisible" to you because the target is beyond + // your 39 tile vision range. Sniper scopes (10 iScopeMagFactor) are even worse (uiBestScopeRange = 70 but visible range limited to 49 tiles). So the + // only way to get the full benefit of a higher powered scope is to have a spotter AND to suffer the various "TARGET_INVISIBLE" penalties. This makes + // no sense. Admittedly, higher powered scopes should be less efficienct at "close range" but is 490m (700m for sniper scope) really "close range"? + // Also, we can't simply change NORMAL_SHOOTING_DISTANCE because this value also effects shooting without a scope. We don't want ot make it harder for + // "scopeless" shooting. So to try and counter some of this, while still showing that scopes are less effecient at "close range", I'm going to cut the + // uiBestScopeRange value in half. This should allow a Battle Scope to reach full effeciency at 24 tiles and a Sniper scope will be fully effecient at + // 35 tiles. ACOG becomes fully effecient at 14 tiles and 2x is fully effeciency at 7 tiles (compared to 28 and 14 respectively). This does mean that a + // 2x scope reaches full effeciency at the same point as "scopeless" shooting, but I don't think this will be a serious problem. + FLOAT rangeModifier = gGameCTHConstants.SCOPE_RANGE_MULTIPLIER; + if( gGameOptions.fNewTraitSystem ) + { + if(iScopeMagFactor > .5) + rangeModifier -= (NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ) * 0.05f); + else + rangeModifier -= (NUM_SKILL_TRAITS( pSoldier, RANGER_NT ) * 0.05f); + } + else + rangeModifier -= (NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT ) * 0.05f); + UINT32 uiBestScopeRange = (UINT32)(iScopeMagFactor * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE * rangeModifier); + + FLOAT iAimModifier = 0; + + // WEAPON CONDITION + if ( pSoldier->inv[HANDPOS][0]->data.objectStatus < 50 ) + { + iAimModifier += gGameCTHConstants.AIM_GUN_CONDITION * (50 - pSoldier->inv[HANDPOS][0]->data.objectStatus); + } + + // MORALE + INT32 iTempModifier = GetMoraleModifier( pSoldier ); + if ( iTempModifier > 0 ) + { + iAimModifier += gGameCTHConstants.AIM_HIGH_MORALE * iTempModifier; + } + else if ( iTempModifier < 0 ) + { + iAimModifier += gGameCTHConstants.AIM_LOW_MORALE * iTempModifier; + } + + if(gGameOptions.fNewTraitSystem) + { + //Give 60% the normal stomp modifier as the aim mod + iAimModifier += (FLOAT)iTraitModifier * 0.6f; + } + else + { + if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO ) + { + iAimModifier += gGameCTHConstants.AIM_PSYCHO; + } + } + + ////////////////////////////////////////// + // Gun Handling modifiers + + switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight) + { + case ANIM_STAND: + iGunAimDifficulty *= gGameCTHConstants.AIM_STANDING_STANCE; + break; + + case ANIM_CROUCH: + iGunAimDifficulty *= gGameCTHConstants.AIM_CROUCHING_STANCE; + break; + + case ANIM_PRONE: + iGunAimDifficulty *= gGameCTHConstants.AIM_PRONE_STANCE; + break; + } + + // FIRING 1-HANDED WEAPONS + if ( !(Item[ usInHand ].twohanded ) ) + { + if (pSoldier->inv[SECONDHANDPOS].exists() != false) { if ( pSoldier->IsValidSecondHandShot( ) ) { - // penalty to aim when firing two pistols - iChance -= AIM_PENALTY_DUAL_PISTOLS; + // Penalty for shooting two pistols. Ambidextrous trait halves this, once per skill level. + FLOAT iTempPenalty = (gGameCTHConstants.AIM_TWO_GUNS * iGunAimDifficulty) - iGunAimDifficulty; + INT8 traitLoop = (gGameOptions.fNewTraitSystem?NUM_SKILL_TRAITS( pSoldier, AMBIDEXTROUS_NT ):NUM_SKILL_TRAITS( pSoldier, AMBIDEXT_OT )); + + for (INT32 x = 0; x < traitLoop; x++) + { + iTempPenalty /= 2; + } + + iGunAimDifficulty += iTempPenalty; } - /* else { - // penalty to aim with pistol being fired one-handed - iChance -= AIM_PENALTY_ONE_HANDED_PISTOL; + // Penalty for shooting a pistol with just one hand + iGunAimDifficulty *= gGameCTHConstants.AIM_ONE_HANDED; } - */ } } + + // HEAVY WEAPON + if (Item[usInHand].rocketlauncher && !(gGameOptions.fNewTraitSystem) ) + { + // Penalty for shooting heavy weapons (launchers). Heavy Weapons skill halves this, once per skill level. + FLOAT iTempPenalty = (gGameCTHConstants.AIM_HEAVY_WEAPON * iGunAimDifficulty) - iGunAimDifficulty; + + for (INT32 x=0; x < NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS_OT ); x++) + { + iTempPenalty /= 2; + } + + iGunAimDifficulty += iTempPenalty; + } + + iGunAimDifficulty += (iGunAimDifficulty * GetPercentHandlingModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight )) / 100; + + // End Gun Handling modifiers + ////////////////////////////////////////// + + iAimModifier += gGameCTHConstants.AIM_DRAW_COST * iGunAimDifficulty; + + // VISIBILITY + if (iRange > 0 && iSightRange > iRange) + { + FLOAT iTempPenalty = (FLOAT)((FLOAT)iSightRange / (FLOAT)iRange); + iTempPenalty = (FLOAT)(100 / iTempPenalty); + iAimModifier += ((100-iTempPenalty) * gGameCTHConstants.AIM_VISIBILITY)/100; + iAimModifier = __max( gGameCTHConstants.AIM_TARGET_INVISIBLE, iAimModifier ); + } + //if (iSightRange == -1) + if(fCantSeeTarget) + { + iAimModifier += gGameCTHConstants.AIM_TARGET_INVISIBLE; + } + + // INJURY + if (pSoldier->stats.bLife < pSoldier->stats.bLifeMax) + { + FLOAT iTempPenalty = gGameCTHConstants.AIM_INJURY; + + // Bleeding damage is used as a percentage off the Max Life, giving a penalty of up to BASE_INJURY. + iAimModifier += (pSoldier->bBleeding * iTempPenalty) / pSoldier->stats.bLifeMax; + + // Bandage damage is used similarly, but is only 1/3 as bad. + bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding; + iAimModifier += ((bBandaged * iTempPenalty) / pSoldier->stats.bLifeMax) / 3; + } + + // FATIGUE + iAimModifier += (gGameCTHConstants.AIM_FATIGUE * (100 - pSoldier->bBreath)) / 100; + + // DRUNKNESS + INT8 iDrunkness = GetDrunkLevel(pSoldier); + if (iDrunkness > 0) + { + iDrunkness -= 1; + iAimModifier += gGameCTHConstants.AIM_DRUNK[iDrunkness]; + } + + // GASSED + if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) + { + iAimModifier += gGameCTHConstants.AIM_GASSED; + } + + // BEING BANDAGED + if (pSoldier->ubServiceCount > 0) + { + iAimModifier += gGameCTHConstants.AIM_BEING_BANDAGED; + } + + // SHOCK (SHOOTER) + if (pSoldier->aiData.bShock) + { + FLOAT iTempPenalty = gGameCTHConstants.AIM_SHOCK; + INT32 iShockPercentage = (pSoldier->aiData.bShock * 100) / gGameExternalOptions.ubMaxSuppressionShock; + + iAimModifier += (iTempPenalty * iShockPercentage) / 100; + } + + ///////////// + // Target-specific tests + + INT32 iHeightDifference = 0; + if ( pTarget == NULL ) + { + // Shooting to roof. + if ( pSoldier->bTargetLevel > pSoldier->pathing.bLevel ) + { + iHeightDifference = 3 * pSoldier->bTargetLevel; + } + } + else + { + // HEIGHT DIFFERENCE + + UINT32 uiShooterHeight = 0; + UINT32 uiTargetHeight = 0; + + if ( pSoldier->pathing.bLevel > 0 ) + { + uiShooterHeight += 3 * pSoldier->pathing.bLevel; + } + + switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) + { + case ANIM_STAND: + uiShooterHeight += 2; + break; + case ANIM_CROUCH: + uiShooterHeight += 1; + break; + } + + if (pTarget->pathing.bLevel > 0) + { + uiTargetHeight += 3 * pTarget->pathing.bLevel; + } + + switch ( gAnimControl[ pTarget->usAnimState ].ubEndHeight ) + { + case ANIM_STAND: + switch (ubAimPos) + { + case AIM_SHOT_HEAD: + uiTargetHeight += 2; + break; + case AIM_SHOT_TORSO: + case AIM_SHOT_RANDOM: + case AIM_SHOT_GLAND: + uiTargetHeight += 1; + break; + } + break; + case ANIM_CROUCH: + switch (ubAimPos) + { + case AIM_SHOT_HEAD: + uiTargetHeight += 1; + break; + } + break; + } + + iHeightDifference = uiShooterHeight - uiTargetHeight; + if (iHeightDifference < 0) + { + iHeightDifference *= -1; + } + else + { + iHeightDifference = 0; + } + } + + // Height difference is mitigated by range. A LONGER range reduces this penalty! + if (iRange > 0 && iHeightDifference > 0) + { + FLOAT iTempPenalty = gGameCTHConstants.AIM_SHOOTING_UPWARDS * iHeightDifference; + iTempPenalty /= iRange; + + iAimModifier += iTempPenalty; + } + + // GAME DIFFICULTY + if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_PC ) && (pSoldier->bSide != gbPlayerNum) ) + { + iAimModifier += gGameCTHConstants.AIM_DIFFICULTY[gGameOptions.ubDifficultyLevel]; + } + + // Percent modifier from the weapon and its attachments + iAimModifier += GetPercentAimModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); + + // Calculate final max aiming + + + ////////////////////////////////////////// + // Start by calculating the CTH cap, the absolute maximum CTH a shooter can get. + iCombinedSkill = ( gGameCTHConstants.AIM_EXP * bExperience * 10 ); + iCombinedSkill += ( gGameCTHConstants.AIM_MARKS * bMarksmanship ); + iCombinedSkill += ( gGameCTHConstants.AIM_WIS * bWisdom ); + iCombinedSkill += ( gGameCTHConstants.AIM_DEX * bDexterity ); + + iCombinedSkill /= (gGameCTHConstants.AIM_EXP + gGameCTHConstants.AIM_MARKS + gGameCTHConstants.AIM_WIS + gGameCTHConstants.AIM_DEX); + + UINT32 uiCap = (UINT32)iCombinedSkill; + // Add percent-based modifier from the gun and its attachments + uiCap += (uiCap * GetPercentCapModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight )) / 100; + + // Add bonuses from Sniper Skill. Applies only when using a scope at or above its "best" range. + INT16 sDifference = 99 - uiCap; + INT16 sSniperSkillBonus = 0; + if (uiCap < gGameExternalOptions.ubMaximumCTH && iScopeMagFactor > 1.0 && iRange >= (INT32)uiBestScopeRange ) + { + INT8 loop; + if(gGameOptions.fNewTraitSystem) + { + if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL || Weapon[usInHand].ubWeaponType == GUN_M_PISTOL ) + loop = NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); + else + loop = NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); + } + else + loop = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT ); + + for (INT8 cnt = 0; cnt < loop; cnt++) + { + // For each level of the sniper skill, cover a defined distance between the current CTH Cap and 99 (the + // maximum... + if(gGameOptions.fNewTraitSystem) + { + if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL || Weapon[usInHand].ubWeaponType == GUN_M_PISTOL ) + sSniperSkillBonus += (INT16)((sDifference * gSkillTraitValues.ubGSAimingBonusPerClick) / gGameExternalOptions.ubMaximumCTH); + else + sSniperSkillBonus += (INT16)((sDifference * gSkillTraitValues.ubSNAimingBonusPerClick) / gGameExternalOptions.ubMaximumCTH); + } + else + sSniperSkillBonus += (INT16)((sDifference * gGameCTHConstants.AIM_SNIPER_SKILL) / gGameExternalOptions.ubMaximumCTH); + sDifference -= sSniperSkillBonus; + } + + uiCap += sSniperSkillBonus; + } + + // Make sure cap is within limits + uiCap = __max(uiCap, __max(0,(UINT32)iChance)); + uiCap = __min(uiCap, gGameExternalOptions.ubMaximumCTH); + + // Now figure out the distance between the Base CTH and the CTH Cap. This is the distance we'll potentially + // cover when applying the maximum number of aiming clicks for this gun. + INT32 iMaxAimBonus = uiCap - iChance; + + iMaxAimBonus = (UINT32)((iMaxAimBonus * (100+iAimModifier)) / 100); + iMaxAimBonus = __max(0, iMaxAimBonus); // can't get less than 0 points for aiming... + + // factor in scopes under their range + if (iScopeMagFactor > 1.0 && iRange < (INT32)uiBestScopeRange) + { + // Calculate how much penalty this scope should give at this range + FLOAT dScopePenaltyRatio = ((FLOAT)uiBestScopeRange / (FLOAT)iRange); + INT32 iScopePenalty = (INT32)(dScopePenaltyRatio * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE * (iScopeMagFactor /2)); + iMaxAimBonus += iScopePenalty; + } + else if (iScopeMagFactor == 1.0f && GetHighestScopeMagnificationFactor( pInHand ) > 1.0f ) + { + // Not using a scope, but it's still there. Give half the penalty based on the size of the scope. + INT32 iScopePenalty = (INT32)(((GetHighestScopeMagnificationFactor( pInHand )/2) * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE)/2); + iMaxAimBonus += iScopePenalty; + } + + // Now let's find out how many CTH points we get per aiming level. + UINT8 ubAllowedAimingLevels = AllowedAimingLevels( pSoldier, sGridNo ); + FLOAT dAimFractionsDivisor = 0.0; + for (UINT8 cnt = 0; cnt < ubAllowedAimingLevels; cnt++) + { + dAimFractionsDivisor += (cnt+1); + } + + FLOAT iAimPoints = 0; + FLOAT iAimPointFraction = (FLOAT)((FLOAT)iMaxAimBonus / dAimFractionsDivisor); + for (UINT8 x = 0; x < ubAimTime; x++) + { + iAimPoints += iAimPointFraction * (ubAllowedAimingLevels-x); + // Add Flat Modifier from the weapon and its attachments + iAimPoints += GetFlatAimModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); + } + + // Finally, add the appropriate number of CTH points to our chance-to-hit, and limit it into good values. + iChance = __max(iChance + (INT32)iAimPoints, iChance); + iChance = __min(iChance, (INT32)uiCap); } + + // Impose global limits. + iChance = __min(iChance, gGameExternalOptions.ubMaximumCTH); + iChance = __max(iChance, gGameExternalOptions.ubMinimumCTH); + + return (iChance); +} + +/* + + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun")); + + + if ( AM_A_ROBOT( pSoldier ) ) + { + SOLDIERTYPE * pSoldier2; + pSoldier2 = pSoldier->GetRobotController( ); + if ( pSoldier2 ) + { + uiExperience = EffectiveExpLevel( pSoldier2 ); + uiMarksmanship = EffectiveMarksmanship( pSoldier2 ); + uiDexterity = EffectiveDexterity( pSoldier2 );; + uiWisdom = EffectiveWisdom( pSoldier2 ); + } + } + + // calculate actual range (in units, 10 units = 1 tile) + iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); // If in burst mode, deduct points for change to hit for each shot after the first if ( pSoldier->bDoBurst && pSoldier->bDoAutofire == 0 ) @@ -3783,137 +5558,6 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, sTotalAutofirePenalty = iPenalty; } - //ADB we need to calculate the distance visible and SoldierTo...LOSTests that we want to - //calculate it when firing, so the scope can be accounted for when the weapon is raised - //I consider this a hack to change the global, but passing a var alllll the way down to GetVisionBonus was worse - //if anyone wants to change it go for it, I don't know what usAnimState should be set - - //store old flag - UINT32 oldFlag = gAnimControl[ pSoldier->usAnimState ].uiFlags; - //add the necessary bits to the flag - gAnimControl[ pSoldier->usAnimState ].uiFlags |= (ANIM_FIREREADY | ANIM_FIRE); - - // 0verhaul: Changed to take expanded range from shooting at different levels into account - //ADB this change does nothing - either way it is random - we don't know what level we are shooting to, which is - //what the last parameter is, and the soldier's current level is as good a guess as ground level. - //so if you really want to fix this, pass in a value - sDistVis = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ); - - // CJC August 13 2002: Wow, this has been wrong the whole time. bTargetCubeLevel seems to be generally set to 2 - - // but if a character is shooting at an enemy in a particular spot, then we should be using the target position on the body. - - // CJC August 13, 2002 - // If the start soldier has a body part they are aiming at, and know about the person in the tile, then use that height instead - iSightRange = -1; - - // give some leeway to allow people to spot for each other... - //so make the range to calculate the bullet at 255+ - ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel ); - // best to use team knowledge as well, in case of spotting for someone else - // 0verhaul: Why not use the distance visible as the max for line of sight testing? - //ADB because A) the bullet can travel farther than I can see and B) I might have a spotter - - //We are firing a gun, and so the gun will be pointed and the scope will be used, even if it isn't now, so don't forget that we are in a firing animation - if (ubTargetID != NOBODY && pSoldier->aiData.bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY) - { - iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false ); - } - if (iSightRange == -1) // didn't do a bodypart-based test - { - iSightRange = SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, pSoldier->bTargetLevel, pSoldier->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT, false ); - } - - //restore old flag - gAnimControl[ pSoldier->usAnimState ].uiFlags = oldFlag; - - if ( iSightRange > (sDistVis * CELL_X_SIZE) ) - { - //CHRISL: Because of the changes I've made to how scopes modify iSightRange, this penalty makes it basically impossible - // to shot at targets you can't see yourself. While this isn't an issue for most weapons, it overly restricts the - // effectiveness of sniper rifles. So pull this penalty but leave the one that comes later in the code. - // shooting beyond max normal vision... penalize such distance at double (also later we halve the remaining chance) - //iSightRange += (iSightRange - sDistVis * CELL_X_SIZE); - } - - // if shooter spent some extra time aiming and can see the target - if (iSightRange > 0 && ubAimTime && !pSoldier->bDoBurst ) - { - // CHRISL: Rather then a flat +10/click bonus, we're going to try a bonus that's based on MRK and Lvl which gets - // progressivly less the more we aim. Everything is based on the maxBonus that a merc can possibly get which - // uses the equation: 20+(MRK/20*LVL)+Accuracy+(Sniper trait * 10). This value is then split between the 8 - // possible AimTime's using a max aimTime bonus of 10. - INT16 bonusProgression[8] = {500,500,600,600,750,750,750,1000}; - FLOAT maxBonus = 20+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER )*10); - INT8 maxClickBonus = 10; - FLOAT aimTimeBonus; - for(int i = 0; i < ubAimTime; i++) - { - aimTimeBonus = __min((maxBonus*bonusProgression[i]/1000),maxClickBonus); - maxBonus -= aimTimeBonus; - iChance += (INT32)floor(aimTimeBonus+.5); - } -/* if(highPowerScope == true) - { - { - if ( NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER ) == 2 ) - aimTimeBonus = -((__max(0,75-pSoldier->stats.bMarksmanship))/(pSoldier->stats.bExpLevel*2)); - else if( NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER ) == 1 ) - aimTimeBonus = -((__max(0,85-pSoldier->stats.bMarksmanship))/(pSoldier->stats.bExpLevel*2)); - else - aimTimeBonus = -((__max(0,100-pSoldier->stats.bMarksmanship))/(pSoldier->stats.bExpLevel)); - aimTimeBonus = __max(-9, aimTimeBonus); - aimTimeBonus = __min(0, aimTimeBonus); - aimTimeBonus += AIM_BONUS_PER_AP; - } - else - aimTimeBonus = AIM_BONUS_PER_AP; - iChance += (aimTimeBonus * ubAimTime); // bonus for every pt of aiming*/ - } - - if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_PC ) ) // if this is a computer AI controlled enemy - { - if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY ) - { - // On easy, penalize all enemies by 5% - iChance -= 5; - } - else - { - // max with 0 to prevent this being a bonus, for JA2 it's just a penalty to make early enemies easy - // CJC note: IDIOT! This should have been a min. It's kind of too late now... - // CJC 2002-05-17: changed the max to a min to make this work. - iChance += __min( 0, gbDiff[ DIFF_ENEMY_TO_HIT_MOD ][ SoldierDifficultyLevel( pSoldier ) ] ); - } - } - - // if shooter is being affected by gas - if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) - { - iChance -= AIM_PENALTY_GASSED; - } - - // if shooter is being bandaged at the same time, his concentration is off - if (pSoldier->ubServiceCount > 0) - iChance -= AIM_PENALTY_GETTINGAID; - - // if shooter is still in shock - if (pSoldier->aiData.bShock) - { - // HEADROCK HAM B2.8: Placed a maximum here, as shock is now also used in suppression. - UINT16 usShockPenalty; - - usShockPenalty = pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK; - - if (gGameExternalOptions.usMaxShooterCoweringPenalty > 0) - { - if ( usShockPenalty > gGameExternalOptions.usMaxShooterCoweringPenalty ) - usShockPenalty = gGameExternalOptions.usMaxShooterCoweringPenalty; - } - if ( usShockPenalty < 1 ) - usShockPenalty = 1; - - iChance -= usShockPenalty; - } // WANNE: Changed this, because RPGs are not in the calculation, only guns //if ( Item[ usInHand ].usItemClass == IC_GUN ) @@ -3926,89 +5570,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, iMaxRange = CELL_X_SIZE; // one tile } - if ( iSightRange > 0 ) - { - // Madd: Spacific item bonuses are no longer hard-coded - - // Snap: use tohitbonus or aimbonus instead - /*if (pSoldier->inv[HEAD1POS].usItem == SUNGOGGLES || pSoldier->inv[HEAD2POS].usItem == SUNGOGGLES) - { - // decrease effective range by 10% when using sungoggles (w or w/o scope) - iSightRange -= iRange / 10; //basically, +1% to hit per every 2 squares - }*/ - - //bAttachPos = FindAttachment( pInHand, SNIPERSCOPE ); - - //// does gun have scope, long range recommends its use, and shooter's aiming? - //if (bAttachPos != NO_SLOT && (iRange > MIN_SCOPE_RANGE) && (ubAimTime > 0)) - //{ - // // reduce effective sight range by 20% per extra aiming time AP of the distance - // // beyond MIN_SCOPE_RANGE. Max reduction is 80% of the range beyond. - // iScopeBonus = ((SNIPERSCOPE_AIM_BONUS * ubAimTime) * (iRange - MIN_SCOPE_RANGE)) / 100; - - // // adjust for scope condition, only has full affect at 100% - // iScopeBonus = (iScopeBonus * WEAPON_STATUS_MOD(pInHand->bAttachStatus[bAttachPos])) / 100; - - //rain - // reduce scope effectiveness when it's raining - // iScopeBonus /= 1 + gbCurrentRainIntensity; //madd: commented out -- didn't do anything but cause a warning :S - //end rain - - // // reduce effective range by the bonus obtained from the scope - // iSightRange -= iScopeBonus; - // if (iSightRange < 1) - // { - // iSightRange = 1; - // } - //} - - //bAttachPos = FindAttachment( pInHand, LASERSCOPE ); - //if (usInHand == ROCKET_RIFLE || usInHand == AUTO_ROCKET_RIFLE || bAttachPos != NO_SLOT) // rocket rifle has one built in - //{ - // INT8 bLaserStatus; - - // if ( usInHand == ROCKET_RIFLE || usInHand == AUTO_ROCKET_RIFLE ) - // { - // bLaserStatus = WEAPON_STATUS_MOD((*pInHand)[0]->data.gun.bGunStatus); - // } - // else - // { - // bLaserStatus = WEAPON_STATUS_MOD(pInHand->bAttachStatus[ bAttachPos ]); - // } - // - // // laser scope isn't of much use in high light levels; add something for that - // if (bLaserStatus > 50) - // { - // iScopeBonus = LASERSCOPE_BONUS * (bLaserStatus - 50) / 50; - // } - // else - // { - // // laser scope in bad condition creates aim penalty! - // iScopeBonus = - LASERSCOPE_BONUS * (50 - bLaserStatus) / 50; - // } - // - // iChance += iScopeBonus; - - //} - - //Madd: Some gear can affect the to-hit bonus and the bonus from aiming - DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: before bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); - iSightRange -= GetGearAimBonus ( pSoldier, iRange, ubAimTime ); - iChance += GetGearToHitBonus ( pSoldier ); - DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after gear bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); - - // Reduce effective range by the aiming bonus (e.g. from sniper scope) - iSightRange -= GetAimBonus( pInHand, iRange, ubAimTime ); - //CHRISL: If we have the Sniper skill, reduce effective range - if ( HAS_SKILL_TRAIT( pSoldier, PROF_SNIPER ) ) - { - iSightRange -= ((gbSkillTraitBonus[ PROF_SNIPER ] * NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER )) * iRange) /100; - } - if (iSightRange < 1) - { - iSightRange = 1; - } // HEADROCK HAM B2.1 : The TARGET's shock now also affects aiming. If the target is prone // and in shock, they are harder to hit! This represents a target that's cowering as close // to the ground (and as close to any possible cover, like a small dune or a fold of earth @@ -4105,35 +5667,6 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after to hit bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); } - // if aiming at the head, reduce chance to hit - if (ubAimPos == AIM_SHOT_HEAD) - { - // penalty of 3% per tile - iPenalty = 3 * iSightRange / 10; - iChance -= iPenalty; - } - else if (ubAimPos == AIM_SHOT_LEGS) - { - // penalty of 1% per tile - iPenalty = iSightRange / 10; - iChance -= iPenalty; - } - - //NumMessage("EFFECTIVE RANGE = ",range); - - // ADJUST FOR RANGE - // bonus if range is less than normal range, penalty if it's more - //iChance += (NORMAL_RANGE - iRange) / (CELL_X_SIZE / 5); // 5% per tile - - // Effects of actual gun max range... the numbers are based on wanting -40% - // at range 26for a pistol with range 13, and -0 for a sniper rifle with range 80 - iPenalty = ((iMaxRange - iRange * 3) * 10) / (17 * CELL_X_SIZE); - if ( iPenalty < 0 ) - { - iChance += iPenalty; - } - //iChance -= 20 * iRange / iMaxRange; - if ( TANK( pSoldier ) && ( iRange / CELL_X_SIZE < MaxNormalDistanceVisible() ) ) { // tank; penalize at close range! @@ -4146,27 +5679,6 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, // firing blind! iChance -= AIM_PENALTY_BLIND; } - else - { - // Effects based on aiming & sight - // From for JA2.5: 3% bonus/penalty for each tile different from range NORMAL_RANGE. - // This doesn't provide a bigger bonus at close range, but stretches it out, making medium - // range less penalized, and longer range more penalized - iChance += 3 * ( NORMAL_RANGE - iSightRange ) / CELL_X_SIZE; - /* - if (iSightRange < NORMAL_RANGE) - { - // bonus to hit of 20% at point blank (would be 25% at range 0); - //at NORMAL_RANGE, bonus is 0 - iChance += 25 * (NORMAL_RANGE - iSightRange) / NORMAL_RANGE; - } - else - { - // penalty of 2% / tile - iChance -= (iSightRange - NORMAL_RANGE) / 5; - } - */ - } // HEADROCK HAM 3.5: Moved this here for now. // HEADROCK HAM B2.5: One of every X bullets in a tracer magazine is a tracer round, which will @@ -4250,23 +5762,6 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, } } - // adjust for roof/not on roof - if ( pSoldier->pathing.bLevel == 0 ) - { - if ( pSoldier->bTargetLevel > 0 ) - { - // penalty for firing up - iChance -= AIM_PENALTY_FIRING_UP; - } - } - else // pSoldier->pathing.bLevel > 0 ) - { - if ( pSoldier->bTargetLevel == 0 ) - { - iChance += AIM_BONUS_FIRING_DOWN; - } - } - pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel ); if (pTarget != NULL) @@ -4340,6 +5835,2048 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, // penalty for amount that enemy has moved // HEADROCK HAM B2.6: Externalized the value iPenalty = __min( (UINT16)((float)pTarget->bTilesMoved * (float)gGameExternalOptions.iMovementEffectOnAiming), 30 ); + iChance -= iPenalty; + + // reduce dodge ability by the attacker's stats + iBonus = ( EffectiveDexterity( pSoldier ) / 5 + EffectiveExpLevel( pSoldier ) * 2); + if ( TANK( pTarget ) || (pSoldier->ubBodyType != QUEENMONSTER) ) + { + // reduce ability to track shots + iBonus = iBonus / 2; + } + + if ( iPenalty > iBonus ) + { + iChance -= (iPenalty - iBonus); + } + } + } + + + + // CHECK IF TARGET IS WITHIN GUN'S EFFECTIVE MAXIMUM RANGE + if ( iRange > iMaxRange ) + { + // a bullet WILL travel that far if not blocked, but it's NOT accurate, + // because beyond maximum range, the bullet drops rapidly + + // This won't cause the bullet to be off to the left or right, only make it + // drop in flight. + iChance /= 2; + } + + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: ichance = %d",iChance)); + return (iChance); +}*/ + +UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ) +{ + if(UsingNewCTHSystem() == true) + return CalcNewChanceToHitGun(pSoldier, sGridNo, ubAimTime, ubAimPos); + + //CHRISL: I've tried to sort and reorganize this function to make it a little easier to follow. I've removed most of the unused code fragments and removed + // alot of the notes. I've also tried to sort the various portions of the function so that similar actions orrucr at the same place in the code. The + // following is the newly written function + SOLDIERTYPE * pTarget; + OBJECTTYPE * pInHand; + INT32 iChance; //CTH + INT32 iRange; //Actual range to target + INT32 iSightRange = 0; //LOS range + INT32 iCoverRange; //Amount sight range is modified due to cover + INT32 iMaxRange; //Weapon maximum range + INT32 iMinRange; //Minimum effective range + INT32 iGunCondition; //Weapons effective condition + INT32 iMarksmanship; //Mercs effective marksmanship + INT32 iAccRangeMod; //Range modifier granted from weapon accuracy + INT32 iBonus, iPenalty; + INT16 sDistVis, sDistVisNoScope, iMaxNormRange, iScopeVisionRangeBonus, sCoweringPenalty = 0, sTotalAutofirePenalty = 0; + INT16 bonusProgression[8] = {500,500,600,600,750,750,750,1000}; //Aiming progression + UINT16 usInHand, usShockPenalty, MIN_RANGE_FOR_FULL_COWER, MAX_TARGET_COWERING_PENALTY; + UINT16 iBulletsLeft, iTracersFired = 0, iBulletsPerTracer, iBulletsSinceLastTracer=0, iRoundsFiredPreviously; + INT8 bBandaged, maxClickBonus = 10, AIM_PENALTY_PER_TARGET_SHOCK; + UINT8 ubAdjAimPos, ubTargetID, bLightLevel, ubCoweringDivisor, ubAutoPenaltySinceLastTracer=0; + FLOAT maxBonus, aimTimeBonus, scopeRangeMod, iAimBonus; + bool fCantSeeTarget = false, fCoverObscured = false; + + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun")); + if ( pSoldier->stats.bMarksmanship == 0 ) { + return( gGameExternalOptions.ubMinimumCTH ); + } + + ///////////////////////////////////////////////////////////////////////////////////// + // Assign basic variables + pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel ); + pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); + iGunCondition = WEAPON_STATUS_MOD( (*pInHand)[0]->data.gun.bGunStatus ); + usInHand = pSoldier->usAttackingWeapon; + ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel ); + bLightLevel = LightTrueLevel(sGridNo, pSoldier->bTargetLevel); + usShockPenalty = pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK; + iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer; + AIM_PENALTY_PER_TARGET_SHOCK = gGameExternalOptions.ubAimPenaltyPerTargetShock; + MIN_RANGE_FOR_FULL_COWER = gGameExternalOptions.usMinRangeForFullCoweringPenalty; + MAX_TARGET_COWERING_PENALTY = gGameExternalOptions.usMaxTargetCoweringPenalty; + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Assign range variables -- all range values are in units (10 units = 1 tile) + iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); // calculate actual range + gbForceWeaponReady = true; + sDistVis = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ) * CELL_X_SIZE; + iScopeVisionRangeBonus = GetTotalVisionRangeBonus(pSoldier, bLightLevel); // not an actual range value, simply a modifier for range calculations + if (ubTargetID != NOBODY && pSoldier->aiData.bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY) + iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false ); + if (iSightRange == 0) { // didn't do a bodypart-based test or can't see specific body part aimed at + iSightRange = SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, pSoldier->bTargetLevel, pSoldier->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT, false ); + fCoverObscured = true; + } + if (iSightRange == 0) { // Can't see the target but we still need to know what the sight range would be if we could so we can deal with cover penalties + iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false, true ); + fCantSeeTarget = true; + fCoverObscured = false; + } + gbForceWeaponReady = false; + gbForceWeaponNotReady = true; + sDistVisNoScope = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ) * CELL_X_SIZE; + gbForceWeaponNotReady = false; + scopeRangeMod = (float)sDistVis / (float)sDistVisNoScope; // percentage DistVis has been enhanced due to an attached scope + iMaxNormRange = MaxNormalDistanceVisible() * CELL_X_SIZE; + if ( Item[ usInHand ].usItemClass == IC_GUN || Item[ usInHand ].usItemClass == IC_LAUNCHER) + iMaxRange = GunRange( pInHand, pSoldier ); // SANDRO - added argument + else + iMaxRange = CELL_X_SIZE; // one tile + iCoverRange = iSightRange - iRange; + iMinRange = iMaxRange / 10; + iAccRangeMod = iRange * Weapon[usInHand].bAccuracy / 100; + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Modify Sight and Physical Range + iSightRange = (INT32)(iSightRange / scopeRangeMod); + if(iSightRange > 0){ + iSightRange -= GetGearAimBonus ( pSoldier, iSightRange, ubAimTime ) * iSightRange / 100; + if ( gGameOptions.fNewTraitSystem ) { + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) { + iSightRange -= ((gSkillTraitValues.ubSNEffRangeToTargetReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )) * iSightRange) /100; + } + } + else if ( HAS_SKILL_TRAIT( pSoldier, PROF_SNIPER_OT ) ) { + iSightRange -= ((gbSkillTraitBonus[ PROF_SNIPER_OT ] * NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )) * iSightRange) /100; + } + if (iRange < GetMinRangeForAimBonus(pInHand) && iScopeVisionRangeBonus > 50){ // iSightRange penalty for using a high power scope within min range due to poor focus + for(UINT8 loop = 0; loop < ((GetMinRangeForAimBonus(pInHand) - iRange)/CELL_X_SIZE); loop++){ + iSightRange += iSightRange * iScopeVisionRangeBonus / 100; + } + } + if (iSightRange < 1) { + iSightRange = 1; + } + } + if(iSightRange > sDistVis) + fCantSeeTarget = true; + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Determine iMarksmanship and Base CTH + if (Item[usInHand].rocketlauncher ){ + // use the same calculation as for mechanical thrown weapons + iMarksmanship = ( EffectiveDexterity( pSoldier ) + EffectiveMarksmanship( pSoldier ) + EffectiveWisdom( pSoldier ) + (10 * EffectiveExpLevel( pSoldier ) )) / 4; + // heavy weapons trait helps out + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPS_OT ) && !( gGameOptions.fNewTraitSystem )) // SANDRO - old/new traits + iMarksmanship += gbSkillTraitBonus[HEAVY_WEAPS_OT] * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS_OT ); + } else { + iMarksmanship = EffectiveMarksmanship( pSoldier ); + if ( AM_A_ROBOT( pSoldier ) ) { + SOLDIERTYPE * pSoldier2; + pSoldier2 = pSoldier->GetRobotController( ); + if ( pSoldier2 ) + iMarksmanship = __max( iMarksmanship, EffectiveMarksmanship( pSoldier2 ) ); + } + } + // modify chance to hit by morale + iMarksmanship += GetMoraleModifier( pSoldier ); + // penalize marksmanship for fatigue + iMarksmanship -= GetSkillCheckPenaltyForFatigue( pSoldier, iMarksmanship ); + if (iGunCondition >= iMarksmanship) // base chance is equal to the shooter's marksmanship skill + iChance = iMarksmanship; + else // base chance is equal to the average of marksmanship & gun's condition! + iChance = (iMarksmanship + iGunCondition) / 2; + // if shooting same target as the last shot + if (sGridNo == pSoldier->sLastTarget ) // give a bonus to hit + iChance += AIM_BONUS_SAME_TARGET; + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Range and Size modifiers + + // Effects of actual gun max range... the numbers are based on wanting -40% + // at range 26for a pistol with range 13, and -0 for a sniper rifle with range 80 + // The result is about 1.5% penalty per tile but only after about 30% of max range. Within 30% max range, there is no modifier + iPenalty = ((iMaxRange - (iRange-iAccRangeMod) * 3) * 10) / (17 * CELL_X_SIZE); + if ( iPenalty < 0 ) + iChance += iPenalty; + if ( TANK( pSoldier ) && ( iRange / CELL_X_SIZE < MaxNormalDistanceVisible() ) ) + iChance -= 2 * ( MaxNormalDistanceVisible() - (iRange / CELL_X_SIZE) ); + // Like the above modifier, only this applies to long range weapons trying to be used in close quater. Penalty will result when within 10% of max range + iPenalty = (((iRange - iMinRange - iAccRangeMod) * 12) * 10) / (17 * CELL_X_SIZE); + if ( iPenalty < 0 ) + iChance += iPenalty; + + // Effects of visual range + // From for JA2.5: 3% bonus/penalty for each tile different from range NORMAL_RANGE. + if (!TANK(pSoldier)) // WANNE: No penalty on the tank + iPenalty = 3 * ( NORMAL_RANGE - iSightRange ) / CELL_X_SIZE; + if ( fCantSeeTarget ) + iPenalty = min(iPenalty, -gGameExternalOptions.iPenaltyShootUnSeen); + iChance += iPenalty; + //CHRISL: We should probably include these target size penalties even if we can't see the target so that shooting a "hidden" head is harder then a "hidden" body + // if aiming at the head, reduce chance to hit + if (ubAimPos == AIM_SHOT_HEAD) + { + // penalty of 3% per tile + //iPenalty = 3 * iSightRange / 10; //comm by ddd + iPenalty = INT32(gGameExternalOptions.uShotHeadPenalty * iSightRange / 10); + iChance -= iPenalty; + } + else if (ubAimPos == AIM_SHOT_LEGS) + { + // penalty of 1% per tile + iPenalty = iSightRange / 10; + iChance -= iPenalty; + } + //CHRISL: A target's stance should have no impact on an aimed, headshot. The head doesn't get any smaller just because the target is crouching down. + if (pTarget != NULL && ubAimPos != AIM_SHOT_HEAD) + { + // targeting a merc + // adjust for crouched/prone target + switch( gAnimControl[ pTarget->usAnimState ].ubHeight ) + { + case ANIM_CROUCH: + if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE ) + { + // 13% penalty per tile closer than min range + iChance -= 13 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ); + } + else + { + // at anything other than point-blank range + if (iRange > POINT_BLANK_RANGE + 10 * (AIM_PENALTY_TARGET_CROUCHED / 3) ) + { + iChance -= AIM_PENALTY_TARGET_CROUCHED; + } + else if (iRange > POINT_BLANK_RANGE) + { + // at close range give same bonus as prone, up to maximum of AIM_PENALTY_TARGET_CROUCHED + iChance -= 3 * ((iRange - POINT_BLANK_RANGE) / CELL_X_SIZE); // penalty -3%/tile + } + } + break; + case ANIM_PRONE: + if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE ) + { + // 25% penalty per tile closer than min range + iChance -= 25 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ); + } + else + { + // at anything other than point-blank range + if (iRange > POINT_BLANK_RANGE) + { + // reduce chance to hit with distance to the prone/immersed target + iPenalty = 3 * ((iRange - POINT_BLANK_RANGE) / CELL_X_SIZE); // penalty -3%/tile + iPenalty = __min( iPenalty, AIM_PENALTY_TARGET_PRONE ); + + iChance -= iPenalty; + } + } + break; + case ANIM_STAND: + // if we are prone and at close range, then penalize shots to the torso or head! + if ( iRange <= MIN_PRONE_RANGE && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) + { + if ( ubAimPos == AIM_SHOT_RANDOM || ubAimPos == AIM_SHOT_GLAND ) + { + ubAdjAimPos = AIM_SHOT_TORSO; + } + else + { + ubAdjAimPos = ubAimPos; + } + // lose 10% per height difference, lessened by distance + // e.g. 30% to aim at head at range 1, only 10% at range 3 + // or 20% to aim at torso at range 1, no penalty at range 3 + // NB torso aim position is 2, so (5-aimpos) is 3, for legs it's 2, for head 4 + iChance -= (5 - ubAdjAimPos - iRange / CELL_X_SIZE) * 10; + } + break; + default: + break; + } + } + if (pTarget != NULL) + { + // penalty for amount that enemy has moved + // HEADROCK HAM B2.6: Externalized the value + iPenalty = __min( (UINT16)((float)pTarget->bTilesMoved * (float)gGameExternalOptions.iMovementEffectOnAiming), 30 ); + /////////////////////////////////////////////////////////////////////////////////// + // SANDRO - fearless characters do not even take their head down no matter what + if ( gGameOptions.fNewTraitSystem && pTarget->ubProfile != NO_PROFILE ) + { + if ( gMercProfiles[ pTarget->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + iPenalty -= (iPenalty * 2 / 3); // two thirds only + } + /////////////////////////////////////////////////////////////////////////////////// + iChance -= iPenalty; + + // if target sees us, he may have a chance to dodge before the gun goes off + // but ability to dodge is reduced if crouched or prone! + if (pTarget->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY && !TANK( pTarget ) && !(pSoldier->ubBodyType != QUEENMONSTER) ) + { + iPenalty = ( EffectiveAgility( pTarget ) / 5 + EffectiveExpLevel( pTarget ) * 2); + switch( gAnimControl[ pTarget->usAnimState ].ubHeight ) + { + case ANIM_CROUCH: + iPenalty = iPenalty * 2 / 3; + break; + case ANIM_PRONE: + iPenalty /= 3; + break; + } + + // reduce dodge ability by the attacker's stats + iBonus = ( EffectiveDexterity( pSoldier ) / 5 + EffectiveExpLevel( pSoldier ) * 2); + if ( TANK( pTarget ) || (pSoldier->ubBodyType != QUEENMONSTER) ) + { + // reduce ability to track shots + iBonus = iBonus / 2; + } + + if ( iPenalty > iBonus ) + { + iChance -= (iPenalty - iBonus); + } + } + if(fCoverObscured){ // If we can't see the body part but can see the tile include a -1%/tile penalty + iPenalty = iCoverRange / CELL_X_SIZE; + iChance -= iPenalty; + } + } + else if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE ) + { + // 25% penalty per tile closer than min range + iChance -= 25 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ); + } + for(attachmentList::iterator iter = (*pInHand)[0]->attachments.begin(); iter != (*pInHand)[0]->attachments.end(); iter++) + { + if(iter->exists() && Item[iter->usItem].aimbonus >= gGameExternalOptions.sHighPowerScope && iRange > Item[iter->usItem].minrangeforaimbonus) + { + iPenalty = (Item[iter->usItem].aimbonus * (iRange - Item[iter->usItem].minrangeforaimbonus)) / 1000; + iPenalty = min(AIM_BONUS_PRONE, iPenalty); + iChance -= iPenalty; + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Modify for traits + if( gGameOptions.fNewTraitSystem ) + { + // Bonus for heavy weapons moved here from above to get instant CtH bonus and not marksmanship bonus, + // which is supressed by weapon condition + if (Item[usInHand].rocketlauncher || Item[usInHand].singleshotrocketlauncher) + { + iChance += gSkillTraitValues.bCtHModifierRocketLaunchers; // -25% for untrained mercs !!! + + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT )) + iChance += gSkillTraitValues.ubHWBonusCtHRocketLaunchers * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ); // +25% per trait + } + // Added CtH bonus for Gunslinger trait on pistols and machine-pistols + else if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL ) + { + iChance += gSkillTraitValues.bCtHModifierPistols; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubGSBonusCtHPistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); // +10% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_M_PISTOL ) + { + iChance += gSkillTraitValues.bCtHModifierMachinePistols; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && ((pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0) || !gSkillTraitValues.ubGSCtHMPExcludeAuto)) + iChance += gSkillTraitValues.ubGSBonusCtHMachinePistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); // +5% per trait + } + // Added CtH bonus for Machinegunner skill on assault rifles, SMGs and LMGs + else if ( Weapon[usInHand].ubWeaponType == GUN_AS_RIFLE ) + { + iChance += gSkillTraitValues.bCtHModifierAssaultRifles; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iChance += gSkillTraitValues.ubAWBonusCtHAssaultRifles * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_SMG ) + { + iChance += gSkillTraitValues.bCtHModifierSMGs; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iChance += gSkillTraitValues.ubAWBonusCtHSMGs * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_LMG ) + { + iChance += gSkillTraitValues.bCtHModifierLMGs; // -10% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iChance += gSkillTraitValues.ubAWBonusCtHLMGs * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + // Added CtH bonus for Gunslinger trait on pistols and machine-pistols + else if ( Weapon[usInHand].ubWeaponType == GUN_SN_RIFLE ) + { + iChance += gSkillTraitValues.bCtHModifierSniperRifles; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubSNBonusCtHSniperRifles * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); // +5% per trait + } + // Added CtH bonus for Ranger skill on rifles and shotguns + else if ( Weapon[usInHand].ubWeaponType == GUN_RIFLE ) + { + iChance += gSkillTraitValues.bCtHModifierRifles; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubRABonusCtHRifles * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); // +5% per trait + //CHRISL: Why wouldn't sniper training include standard rifles which are often used as "poor-man sniper rifles" + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubSNBonusCtHRifles * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_SHOTGUN ) + { + iChance += gSkillTraitValues.bCtHModifierShotguns; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + iChance += gSkillTraitValues.ubRABonusCtHShotguns * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); // +10% per trait + } + + // Added small CtH penalty for robot if controller hasn't the Technician trait + if( AM_A_ROBOT( pSoldier ) ) + { + iChance += gSkillTraitValues.bCtHModifierRobot; // -10% + + if ( HAS_SKILL_TRAIT( pSoldier->GetRobotController(), TECHNICIAN_NT ) ) + iChance += gSkillTraitValues.ubTECtHControlledRobotBonus * NUM_SKILL_TRAITS( pSoldier->GetRobotController(), TECHNICIAN_NT ); // +10% per trait + } + + // Added character traits influence + if ( pSoldier->ubProfile != NO_PROFILE ) + { + // Sociable - better performance in groups + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs > 2 ) + iChance += 5; + else if ( bNumMercs > 0 ) + iChance += 2; + } + // Loner - better performance when alone + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs == 0 ) + iChance += 5; + else if ( bNumMercs <= 1 ) + iChance += 2; + } + // Aggressive - bonus on bursts/autofire + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + if (( pSoldier->bDoBurst || pSoldier->bDoAutofire ) && !ubAimTime ) + iChance += 5; + } + // Show-off - better performance if some babes around to impress + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SHOWOFF ); + if ( bNumMercs > 1 ) + iChance += 5; + else if ( bNumMercs > 0 ) + iChance += 2; + } + // Added disabilities + if ( pSoldier->ubProfile != NO_PROFILE ) + { + // Heat intolerant penalty + if ( MercIsHot( pSoldier ) ) + { + iChance -= 15; + } + // Small penalty for fear of insects in tropical sectors + else if ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) && MercIsInTropicalSector( pSoldier ) ) + { + // fear of insects, and we are in tropical sector + iChance -= 5; + } + } + } + // Dauntless - penalty for not taking proper cover + if (pTarget != NULL) + { + if ( pTarget->ubProfile != NO_PROFILE ) + { + if ( gMercProfiles[ pTarget->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + iChance += 5; + } + } + } + else + { + // this rather unlogical bonus for psychotic characters applies only with old traits + if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO ) + { + iChance += AIM_BONUS_PSYCHO; + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Modify for stance and weapon + // if shooter is crouched, he aims slightly better (to max of AIM_BONUS_CROUCHING) + if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH ) + { + iBonus = iRange / 10; + if (iBonus > AIM_BONUS_CROUCHING) + { + iBonus = AIM_BONUS_CROUCHING; + } + iChance += iBonus; + } + // if shooter is prone, he aims even better, except at really close range + else if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) + { + if (iRange > MIN_PRONE_RANGE) + { + iBonus = iRange / 10; + if (iBonus > AIM_BONUS_PRONE) + { + iBonus = AIM_BONUS_PRONE; + } + iChance += iBonus; + } + } + //Madd: inherent weapon accuracy bonus + //iChance += Weapon[usInHand].bAccuracy; + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Modify for using one hand + if ( !(Item[ usInHand ].twohanded ) ) + { + if (pSoldier->inv[SECONDHANDPOS].exists() == false) + { + // firing with gun in right hand, and second hand empty (ie: no grenade, med kit or anything there) + // Madd: easier to fire pistol/smg w/one hand free, essentially this will make pistols a little bit more accurate, and hopefully still useful later in the game + if (Weapon[usInHand].ubWeaponClass == HANDGUNCLASS) + iChance += AIM_BONUS_TWO_HANDED_PISTOL; + } + else + { + // Madd: harder to fire smgs w/something in other hand + // SMGs are treated as pistols for these purpose except there is a -5 penalty; + if (Weapon[usInHand].ubWeaponClass == SMGCLASS) + { + iChance -= AIM_PENALTY_SMG; + } + if (gGameOptions.fNewTraitSystem) + { + // Okay, we will shoot from both weapons, calculate penalty to CtH + if ( pSoldier->IsValidSecondHandShot() ) + { + // penaly to shoot from dual weapons + iChance -= (INT32)(gSkillTraitValues.ubCtHPenaltyDualShot * (HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ? ((100 - gSkillTraitValues.ubAMPenaltyDoubleReduction)/100) : 1 )); + } + } + else // original code + { + if ( !HAS_SKILL_TRAIT( pSoldier, AMBIDEXT_OT ) ) + { + if ( pSoldier->IsValidSecondHandShot( ) ) + { + // penalty to aim when firing two pistols + iChance -= AIM_PENALTY_DUAL_PISTOLS; + } + /* + else + { + // penalty to aim with pistol being fired one-handed + iChance -= AIM_PENALTY_ONE_HANDED_PISTOL; + } + */ + } + } + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Modify for Recoil and Tracer effects + if ( pSoldier->bDoBurst && pSoldier->bDoAutofire == 0 ) + { + /*CHRISL: At this point in the calculation, Bipods, Foregrips and other "recoil stabalizing" bonuses should reduce the weapons "recoil penalty" + (BurstPenalty) by a percentage. This reduction should apply the the recoil per shot and not as a "flat" initial reduction. Later in the code, + Bipods also grant their flat CTH bonus so we don't need to mess this that here*/ + if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier) + { + iBonus = GetBurstToHitBonus(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier; + iPenalty = Weapon[pInHand->usItem].ubBurstPenalty * (pSoldier->bDoBurst - 1) * (gGameExternalOptions.bAimedBurstEnabled?gGameExternalOptions.uAimedBurstPenalty:1); + iPenalty = max(0, (iPenalty * (100 - iBonus))/100 ); + } + else + { + // Snap: bipod may reduce burst penalty + iPenalty = GetBurstPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * (pSoldier->bDoBurst - 1); + if(gGameExternalOptions.bAimedBurstEnabled) + iPenalty += Weapon[usInHand].ubBurstPenalty * (pSoldier->bDoBurst - 1) * gGameExternalOptions.uAimedBurstPenalty; + } + + // halve the penalty for people with the autofire trait + if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + { + iPenalty = max(0, ((iPenalty * (100 - gSkillTraitValues.ubAWAutoFirePenaltyReduction * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/100)); + } + } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS_OT ) ) + { + iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT ); + } + } + iChance -= iPenalty; + } + else if ( pSoldier->bDoAutofire > 0 ) + { + /*CHRISL: At this point in the calculation, Bipods, Foregrips and other "recoil stabalizing" bonuses should reduce the weapons "recoil penalty" + (AutoPenalty) by a percentage. This reduction should apply the the recoil per shot and not as a "flat" initial reduction. Later in the code, + Bipods also grant their flat CTH bonus so we don't need to mess this that here*/ + if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier) + { + iBonus = GetAutoToHitBonus(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier; + iPenalty = Weapon[pInHand->usItem].AutoPenalty * (pSoldier->bDoBurst - 1) * (gGameExternalOptions.bAimedBurstEnabled?gGameExternalOptions.uAimedBurstPenalty:1); + iPenalty = max(0, (iPenalty * (100 - iBonus))/100 ); + } + else + { + // Snap: bipod may reduce auto penalty + iPenalty = GetAutoPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * (pSoldier->bDoBurst - 1); + if(gGameExternalOptions.bAimedBurstEnabled) + iPenalty += Weapon[usInHand].AutoPenalty * (pSoldier->bDoBurst - 1) * gGameExternalOptions.uAimedBurstPenalty; + } + + // halve the penalty for people with the autofire trait + if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + { + iPenalty = max(0, ((iPenalty * (100 - gSkillTraitValues.ubAWAutoFirePenaltyReduction * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/100)); + } + } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS_OT ) ) + { + iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT ); + } + } + iChance -= iPenalty; + // HEADROCK HAM 3.5: Store the penalty + sTotalAutofirePenalty = iPenalty; + } + if (AmmoTypes[(*pInHand)[0]->data.gun.ubGunAmmoType].tracerEffect == 1 && gGameExternalOptions.ubRealisticTracers > 0 ) + { + /*CHRISL: We want to know here is how many tracers have been fired during this autofire sequence. But we also want to figure that based on how + much ammo we've used from the current mag. If every 3rd round is a tracer, and we previously fired 5 rounds from our "mag", then the first + round of this burst is a tracer, the 2nd & 3rd are normal, the 4th is a tracer, 5th & 6th are normal, etc.*/ + if (fCalculateCTHDuringGunfire) // Calculate number of bullets left right before firing this burst + iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft + (pSoldier->bDoBurst - 1); + else + iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft; + iRoundsFiredPreviously = GetMagSize(pInHand) - iBulletsLeft; //How many rounds had been fired before this autofire sequence + for( UINT8 cnt = 1; cnt <= pSoldier->bDoBurst; cnt++ ){ //How many tracers have been fired prior to this bullet in this autofire sequence + if((iRoundsFiredPreviously+cnt)%iBulletsPerTracer == 0) + iTracersFired++; + } + if ( iTracersFired > 0 ) { + if(sTotalAutofirePenalty > 0){ + INT16 sChanceLimit = min(gGameExternalOptions.ubCTHBumpPerTracer, ((iRange-(gGameExternalOptions.ubMinRangeTracerEffect*CELL_X_SIZE)) / CELL_X_SIZE) * gGameExternalOptions.ubRangeDifficultyAimingWithTracers); + sChanceLimit = max(0, sChanceLimit); + iBonus = sChanceLimit * iTracersFired; + iBonus = min(iBonus, sTotalAutofirePenalty); + } + + iChance += iBonus; + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Modify for Aim + if(ubAimTime) + { + // CHRISL: Rather then a flat +10/click bonus, we're going to try a bonus that's based on MRK and Lvl which gets + // progressivly less the more we aim. Everything is based on the maxBonus that a merc can possibly get which + // uses the equation: 20+(MRK/20*LVL)+Accuracy+(Sniper trait * 10). This value is then split between the 8 + // possible AimTime's using a max aimTime bonus of 10. + if ( gGameOptions.fNewTraitSystem ) { + // bonus to snipers and gunslingers + if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL || Weapon[usInHand].ubWeaponType == GUN_M_PISTOL ) + maxBonus = 20+((FLOAT)iMarksmanship/20*(EffectiveExpLevel(pSoldier)))+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )*gSkillTraitValues.ubGSAimingBonusPerClick); + else + maxBonus = 20+((FLOAT)iMarksmanship/20*(EffectiveExpLevel(pSoldier)))+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )*gSkillTraitValues.ubSNAimingBonusPerClick); + } else { + if(gGameExternalOptions.bAltAimEnabled) + maxBonus = (20*(iMarksmanship/100))+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )*10); + else + maxBonus = 20+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )*10); + } + iAimBonus = (float)GetAimBonus( pInHand, 100, 1 ); + for(int i = 0; i < ubAimTime; i++) { + aimTimeBonus = __min((maxBonus*bonusProgression[i]/1000),maxClickBonus); + maxBonus -= aimTimeBonus; + iChance += (INT32)floor(aimTimeBonus+.5); + //CHRISL: This is a slight extra bonus granted from a scopes AimBonus score + aimTimeBonus = __min(ceil((float)(iAimBonus * bonusProgression[i] / 1000)), 3); + iAimBonus -= aimTimeBonus; + iChance+= (INT32)floor(aimTimeBonus+.5); + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // AI Modifiers + if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_PC ) ) // if this is a computer AI controlled enemy + { + if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY ) + { + // On easy, penalize all enemies by 5% + iChance -= 5; + } + else + { + iChance += __min( 0, gbDiff[ DIFF_ENEMY_TO_HIT_MOD ][ SoldierDifficultyLevel( pSoldier ) ] ); + } + } + // SANDRO - Bonus CtH for Militia + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sGreenMilitiaCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sRegularMilitiaCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); + // bonus for enemy + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyEliteCtHBonusPercent) /100); + // SANDRO - option to make special NPCs stronger - chance to hit + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( pSoldier->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + iChance += (iChance * gGameExternalOptions.usSpecialNPCStronger / 100); + break; + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Situational modifiers + if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) + iChance -= AIM_PENALTY_GASSED; + if (pSoldier->ubServiceCount > 0) + iChance -= AIM_PENALTY_GETTINGAID; + if (pSoldier->aiData.bShock) + { + if (gGameExternalOptions.usMaxShooterCoweringPenalty > 0) + { + if ( usShockPenalty > gGameExternalOptions.usMaxShooterCoweringPenalty ) + usShockPenalty = gGameExternalOptions.usMaxShooterCoweringPenalty; + } + if ( usShockPenalty < 1 ) + usShockPenalty = 1; + + iChance -= usShockPenalty; + } + // adjust for roof/not on roof + if ( pSoldier->pathing.bLevel == 0 ) + { + if ( pSoldier->bTargetLevel > 0 ) + { + // penalty for firing up + iChance -= AIM_PENALTY_FIRING_UP; + } + } + else // pSoldier->pathing.bLevel > 0 ) + { + if ( pSoldier->bTargetLevel == 0 ) + { + iChance += AIM_BONUS_FIRING_DOWN; + } + } + // IF CHANCE EXISTS, BUT SHOOTER IS INJURED + if ((iChance > 0) && (pSoldier->stats.bLife < pSoldier->stats.bLifeMax)) + { + // if bandaged, give 1/2 of the bandaged life points back into equation + bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding; + + // injury penalty is based on % damage taken (max 2/3rds chance) + iPenalty = (iChance * 2 * (pSoldier->stats.bLifeMax - pSoldier->stats.bLife + (bBandaged / 2))) / + (3 * pSoldier->stats.bLifeMax); + + // reduce injury penalty due to merc's experience level (he can take it!) + iChance -= (iPenalty * (100 - (10 * ( EffectiveExpLevel( pSoldier ) - 1)))) / 100; + } + + // IF CHANCE EXISTS, BUT SHOOTER IS LOW ON BREATH + if ((iChance > 0) && (pSoldier->bBreath < 100)) + { + // breath penalty is based on % breath missing (max 1/2 chance) + iPenalty = (iChance * (100 - pSoldier->bBreath)) / 200; + // reduce breath penalty due to merc's dexterity (he can compensate!) + iChance -= (iPenalty * (100 - ( EffectiveDexterity( pSoldier ) - 10))) / 100; + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Equipment Modifiers + iChance += GetGearToHitBonus ( pSoldier ); + iChance += GetToHitBonus( pInHand, iRange, bLightLevel,gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE && iRange > MIN_PRONE_RANGE ); + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Suppression modifiers + if ( gGameExternalOptions.ubAimPenaltyPerTargetShock > 0 ) + { + if (pTarget != NULL) + { + if (pTarget->aiData.bShock ) + { + if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE) + { + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorProne; + + sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK); + sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor; + sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER; + + if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0) + { + if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty ) + sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty; + } + if ( sCoweringPenalty < 1 ) + sCoweringPenalty = 1; + + iChance -= sCoweringPenalty; + } + else if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_CROUCH) + { + switch ( ubAimPos ) + { + case AIM_SHOT_HEAD: + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedHead; + break; + case AIM_SHOT_TORSO: + case AIM_SHOT_RANDOM: + case AIM_SHOT_GLAND: + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedTorso; + break; + case AIM_SHOT_LEGS: + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedLegs; + break; + } + + sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK); + sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor; + sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER; + + if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0) + { + if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty ) + sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty; + } + if ( sCoweringPenalty < 1 ) + sCoweringPenalty = 1; + + // HEADROCK HAM B2.8.1: Added formula to make sure that cowering target penalties + // are not given when on the roof. + + if (pSoldier->pathing.bLevel == pTarget->pathing.bLevel && pSoldier->pathing.bLevel > 0) + sCoweringPenalty = 0; // No cowering penalties when both are on the roof! + else if (pSoldier->pathing.bLevel < pSoldier->pathing.bLevel && gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE) + sCoweringPenalty *= 2; // Much harder to shoot at anyone cowering above you. + else if (pSoldier->pathing.bLevel > pSoldier->pathing.bLevel) + sCoweringPenalty /= 2; // Much easier to shoot at cowerers below you. + iChance -= sCoweringPenalty; + } + } + } + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Max range modifier. This needs to be here, near the end of the function to + // guarantee that the max range penalty is properly calculated. + ///////////////////////////////////////////////////////////////////////////////////// + if ( iRange > iMaxRange ) + { + // a bullet WILL travel that far if not blocked, but it's NOT accurate, + // because beyond maximum range, the bullet drops rapidly + + // This won't cause the bullet to be off to the left or right, only make it + // drop in flight. + //iChance /= 2; //ddd + iChance = (INT32)(iChance / gGameExternalOptions.fOutOfGunRangeOrSight); + } + ///////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////// + // Adjust for Max and Min values + // HEADROCK: (HAM) Altered so called "Defined Limits" to accept external arguments. + // The divisor argument only works when the minimum is set to 0. It has a chance of 1 in X to + // bump the minimum back to 1, where X = the Divisor value. So a divisor value of 50 gives a 1/50 + // chance of getting some actual chance to hit despite the 0 minimum. The overall total would then + // be an effective CTH of only 1/5000 (50 chances to get a 1 out of 100 CTH, hehehe) + if (iChance <= gGameExternalOptions.ubMinimumCTH) + { + if ( TANK( pSoldier ) ) + { + // allow absolute minimums + iChance = 0; + } + else + { + iChance = gGameExternalOptions.ubMinimumCTH; + if ( gGameExternalOptions.ubMinimumCTH == 0 ) + { + if ( PreRandom( gGameExternalOptions.usMinimumCTHDivisor ) == (gGameExternalOptions.usMinimumCTHDivisor - 1) ) + { + iChance = 1; + } + } + } + } + else + { + // HEADROCK (HAM): Externalized maximum to JA2_OPTIONS.INI + // if (iChance > MAXCHANCETOHIT) + // iChance = MAXCHANCETOHIT; + if (iChance > gGameExternalOptions.ubMaximumCTH) + iChance = gGameExternalOptions.ubMaximumCTH; + } + ///////////////////////////////////////////////////////////////////////////////////// + + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: ichance = %d",iChance)); + return (iChance); + /*CHRISL: I've tried to sort and reorganize this function to make it a little easier to follow. All of this is the original function + //SOLDIERTYPE *vicpSoldier; + SOLDIERTYPE * pTarget; + INT32 iChance; //CTH + INT32 iRange; //Actual range to target + INT32 iSightRange; //LOS range + INT32 iTileRange; //LOS range to the tile target is in - in case we can't see the target + INT32 iVisionRange; //Effective visual range + INT32 iMaxRange; //Weapon maximum range + INT32 iGunCondition; //Weapons effective condition + INT32 iMarksmanship; //Mercs effective marksmanship + INT32 iBonus, iPenalty; + //rain + //INT32 iScopeBonus; + //end rain + UINT16 usInHand; + OBJECTTYPE * pInHand; +// INT8 bAttachPos; + INT8 bBandaged; + INT16 sDistVis; + UINT8 ubAdjAimPos; + UINT8 ubTargetID; + bool highPowerScope = false; + UINT32 pScope; + UINT8 bLightLevel = LightTrueLevel(sGridNo, pSoldier->bTargetLevel); + + // HEADROCK HAM 3.5: Variable holds total autofire penalty. + INT16 sTotalAutofirePenalty = 0; + + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun")); + + if ( pSoldier->stats.bMarksmanship == 0 ) + { + // HEADROCK: (HAM) Altered to accept external arguments + // return( MINCHANCETOHIT ); + return( gGameExternalOptions.ubMinimumCTH ); + } + + // make sure the guy's actually got a weapon in his hand! + pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]); + usInHand = pSoldier->usAttackingWeapon; + //CHRISL: We have new modifiers when using a high power scope so find out if we have one from the start + for(attachmentList::iterator iter = (*pInHand)[0]->attachments.begin(); iter != (*pInHand)[0]->attachments.end(); iter++) + { + if(Item[iter->usItem].aimbonus >= gGameExternalOptions.sHighPowerScope && iter->exists()) + { + highPowerScope = true; + pScope = iter->usItem; + break; + } + } + + ///////////////////////////////////////////////////////////////////////////////////// + // DETERMINE BASE CHANCE OF HITTING + iGunCondition = WEAPON_STATUS_MOD( (*pInHand)[0]->data.gun.bGunStatus ); + + if (Item[usInHand].rocketlauncher ) + { + // use the same calculation as for mechanical thrown weapons + iMarksmanship = ( EffectiveDexterity( pSoldier ) + EffectiveMarksmanship( pSoldier ) + EffectiveWisdom( pSoldier ) + (10 * EffectiveExpLevel( pSoldier ) )) / 4; + // heavy weapons trait helps out + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPS_OT ) && !( gGameOptions.fNewTraitSystem )) // SANDRO - old/new traits + { + iMarksmanship += gbSkillTraitBonus[HEAVY_WEAPS_OT] * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS_OT ); + } + } + else + { + iMarksmanship = EffectiveMarksmanship( pSoldier ); + + if ( AM_A_ROBOT( pSoldier ) ) + { + SOLDIERTYPE * pSoldier2; + + pSoldier2 = pSoldier->GetRobotController( ); + if ( pSoldier2 ) + { + iMarksmanship = __max( iMarksmanship, EffectiveMarksmanship( pSoldier2 ) ); + } + } + } + + // modify chance to hit by morale + iMarksmanship += GetMoraleModifier( pSoldier ); + + // penalize marksmanship for fatigue + iMarksmanship -= GetSkillCheckPenaltyForFatigue( pSoldier, iMarksmanship ); + + //if ( PTR_OURTEAM ) + //{ + // iChance = ( iMarksmanship * iGunCondition ) / 100; + //} + //else + { + if (iGunCondition >= iMarksmanship) + // base chance is equal to the shooter's marksmanship skill + iChance = iMarksmanship; + else + // base chance is equal to the average of marksmanship & gun's condition! + iChance = (iMarksmanship + iGunCondition) / 2; + } + ///////////////////////////////////////////////////////////////////////////////////// + + // if shooting same target as the last shot + if (sGridNo == pSoldier->sLastTarget ) + iChance += AIM_BONUS_SAME_TARGET; // give a bonus to hit + + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits + //////////////////////////////////////////////////// + // For every type of gun, there was added a penalty for untrained mercs. This penalty + // is rather small and is often compensated by single trait of that type + if( gGameOptions.fNewTraitSystem ) + { + // Bonus for heavy weapons moved here from above to get instant CtH bonus and not marksmanship bonus, + // which is supressed by weapon condition + if (Item[usInHand].rocketlauncher || Item[usInHand].singleshotrocketlauncher) + { + iChance += gSkillTraitValues.bCtHModifierRocketLaunchers; // -25% for untrained mercs !!! + + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT )) + iChance += gSkillTraitValues.ubHWBonusCtHRocketLaunchers * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ); // +25% per trait + } + // Added CtH bonus for Gunslinger trait on pistols and machine-pistols + else if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL ) + { + iChance += gSkillTraitValues.bCtHModifierPistols; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubGSBonusCtHPistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); // +10% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_M_PISTOL ) + { + iChance += gSkillTraitValues.bCtHModifierMachinePistols; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, GUNSLINGER_NT ) && ((pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0) || !gSkillTraitValues.ubGSCtHMPExcludeAuto)) + iChance += gSkillTraitValues.ubGSBonusCtHMachinePistols * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT ); // +5% per trait + } + // Added CtH bonus for Machinegunner skill on assault rifles, SMGs and LMGs + else if ( Weapon[usInHand].ubWeaponType == GUN_AS_RIFLE ) + { + iChance += gSkillTraitValues.bCtHModifierAssaultRifles; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iChance += gSkillTraitValues.ubAWBonusCtHAssaultRifles * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_SMG ) + { + iChance += gSkillTraitValues.bCtHModifierSMGs; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iChance += gSkillTraitValues.ubAWBonusCtHSMGs * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_LMG ) + { + iChance += gSkillTraitValues.bCtHModifierLMGs; // -10% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + iChance += gSkillTraitValues.ubAWBonusCtHLMGs * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT ); // +5% per trait + } + // Added CtH bonus for Gunslinger trait on pistols and machine-pistols + else if ( Weapon[usInHand].ubWeaponType == GUN_SN_RIFLE ) + { + iChance += gSkillTraitValues.bCtHModifierSniperRifles; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubSNBonusCtHSniperRifles * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); // +5% per trait + } + // Added CtH bonus for Ranger skill on rifles and shotguns + else if ( Weapon[usInHand].ubWeaponType == GUN_RIFLE ) + { + iChance += gSkillTraitValues.bCtHModifierRifles; // -5% for untrained mercs. + + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubRABonusCtHRifles * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); // +5% per trait + //CHRISL: Why wouldn't sniper training include standard rifles which are often used as "poor-man sniper rifles" + // this bonus is applied only on single shots! + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) && pSoldier->bDoBurst == 0 && pSoldier->bDoAutofire == 0 ) + iChance += gSkillTraitValues.ubSNBonusCtHRifles * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT ); // +5% per trait + } + else if ( Weapon[usInHand].ubWeaponType == GUN_SHOTGUN ) + { + iChance += gSkillTraitValues.bCtHModifierShotguns; // -5% for untrained mercs. + + if ( HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + iChance += gSkillTraitValues.ubRABonusCtHShotguns * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ); // +10% per trait + } + + // Added small CtH penalty for robot if controller hasn't the Technician trait + if( AM_A_ROBOT( pSoldier ) ) + { + iChance += gSkillTraitValues.bCtHModifierRobot; // -10% + + if ( HAS_SKILL_TRAIT( pSoldier->GetRobotController(), TECHNICIAN_NT ) ) + iChance += gSkillTraitValues.ubTECtHControlledRobotBonus * NUM_SKILL_TRAITS( pSoldier->GetRobotController(), TECHNICIAN_NT ); // +10% per trait + } + + // Added character traits influence + if ( pSoldier->ubProfile != NO_PROFILE ) + { + // Sociable - better performance in groups + if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs > 2 ) + iChance += 5; + else if ( bNumMercs > 0 ) + iChance += 2; + } + // Loner - better performance when alone + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs == 0 ) + iChance += 5; + else if ( bNumMercs <= 1 ) + iChance += 2; + } + // Aggressive - bonus on bursts/autofire + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + if (( pSoldier->bDoBurst || pSoldier->bDoAutofire ) && !ubAimTime ) + iChance += 5; + } + // Show-off - better performance if some babes around to impress + else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pSoldier->ubProfile, CHAR_TRAIT_SHOWOFF ); + if ( bNumMercs > 1 ) + iChance += 5; + else if ( bNumMercs > 0 ) + iChance += 2; + } + // Added disabilities + if ( pSoldier->ubProfile != NO_PROFILE ) + { + // Heat intolerant penalty + if ( MercIsHot( pSoldier ) ) + { + iChance -= 15; + } + // Small penalty for fear of insects in tropical sectors + else if ( (gMercProfiles[ pSoldier->ubProfile ].bDisability == FEAR_OF_INSECTS) && MercIsInTropicalSector( pSoldier ) ) + { + // fear of insects, and we are in tropical sector + iChance -= 5; + } + } + } + // Dauntless - penalty for not taking proper cover + pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel ); + if (pTarget != NULL) + { + if ( pTarget->ubProfile != NO_PROFILE ) + { + if ( gMercProfiles[ pTarget->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + iChance += 5; + } + } + } + else + { + // this rather unlogical bonus for psychotic characters applies only with old traits + if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO ) + { + iChance += AIM_BONUS_PSYCHO; + } + } + + // calculate actual range (in units, 10 units = 1 tile) + iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); + + //CHRISL: Incur a penalty if using a highPowerScope + if(highPowerScope == true && iRange > Item[pScope].minrangeforaimbonus) + { + iPenalty = (Item[pScope].aimbonus * (iRange-Item[pScope].minrangeforaimbonus)) / 1000; + if (iPenalty > AIM_BONUS_PRONE) + { + iPenalty = AIM_BONUS_PRONE; + } + iChance -= iPenalty; + } + // if shooter is crouched, he aims slightly better (to max of AIM_BONUS_CROUCHING) + if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH ) + { + iBonus = iRange / 10; + if (iBonus > AIM_BONUS_CROUCHING) + { + iBonus = AIM_BONUS_CROUCHING; + } + iChance += iBonus; + } + // if shooter is prone, he aims even better, except at really close range + else if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) + { + if (iRange > MIN_PRONE_RANGE) + { + iBonus = iRange / 10; + if (iBonus > AIM_BONUS_PRONE) + { + iBonus = AIM_BONUS_PRONE; + } + // Snap: bipod bonus is now calculated in GetToHitBonus + //bAttachPos = FindAttachment( pInHand, BIPOD ); + //if (bAttachPos != ITEM_NOT_FOUND) + //{ // extra bonus to hit for a bipod, up to half the prone bonus itself + // iBonus += (iBonus * WEAPON_STATUS_MOD(GetBipodStatus(pInHand)) / 100) / 2; + //} + iChance += iBonus; + } + } + + //Madd: inherent weapon accuracy bonus + iChance += Weapon[usInHand].bAccuracy; + +// if ( !(Item[ usInHand ].fFlags & ITEM_TWO_HANDED) ) + if ( !(Item[ usInHand ].twohanded ) ) + { + if (pSoldier->inv[SECONDHANDPOS].exists() == false) + { + // firing with gun in right hand, and second hand empty (ie: no grenade, med kit or anything there) + // Madd: easier to fire pistol/smg w/one hand free, essentially this will make pistols a little bit more accurate, and hopefully still useful later in the game + if (Weapon[usInHand].ubWeaponClass == HANDGUNCLASS) + iChance += AIM_BONUS_TWO_HANDED_PISTOL; + } + else + { + // Madd: harder to fire smgs w/something in other hand + // SMGs are treated as pistols for these purpose except there is a -5 penalty; + if (Weapon[usInHand].ubWeaponClass == SMGCLASS) + { + iChance -= AIM_PENALTY_SMG; + } + + ////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if (gGameOptions.fNewTraitSystem) + { + // Okay, we will shoot from both weapons, calculate penalty to CtH + if ( pSoldier->IsValidSecondHandShot() ) + { + // penaly to shoot from dual weapons + iChance -= (INT32)(gSkillTraitValues.ubCtHPenaltyDualShot * (HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) ? ((100 - gSkillTraitValues.ubAMPenaltyDoubleReduction)/100) : 1 )); + } + } + else // original code + { + if ( !HAS_SKILL_TRAIT( pSoldier, AMBIDEXT_OT ) ) + { + if ( pSoldier->IsValidSecondHandShot( ) ) + { + // penalty to aim when firing two pistols + iChance -= AIM_PENALTY_DUAL_PISTOLS; + } +// else +// { +// // penalty to aim with pistol being fired one-handed +// iChance -= AIM_PENALTY_ONE_HANDED_PISTOL; +// } + } + } + ////////////////////////////////////////////////////////////////// + } + } + + // If in burst mode, deduct points for chance to hit for each shot after the first + if ( pSoldier->bDoBurst && pSoldier->bDoAutofire == 0 ) + { +// CHRISL: At this point in the calculation, Bipods, Foregrips and other "recoil stabalizing" bonuses should reduce the weapons "recoil penalty" +// (BurstPenalty) by a percentage. This reduction should apply the the recoil per shot and not as a "flat" initial reduction. Later in the code, +// Bipods also grant their flat CTH bonus so we don't need to mess this that here + if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier) + { + iBonus = GetBurstToHitBonus(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier; + iPenalty = Weapon[pInHand->usItem].ubBurstPenalty * (pSoldier->bDoBurst - 1) * (gGameExternalOptions.bAimedBurstEnabled?gGameExternalOptions.uAimedBurstPenalty:1); + iPenalty = max(0, (iPenalty * (100 - iBonus))/100 ); + } + else + { + // Snap: bipod may reduce burst penalty + iPenalty = GetBurstPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * (pSoldier->bDoBurst - 1); + if(gGameExternalOptions.bAimedBurstEnabled) + iPenalty += Weapon[usInHand].ubBurstPenalty * (pSoldier->bDoBurst - 1) * gGameExternalOptions.uAimedBurstPenalty; + } + + // halve the penalty for people with the autofire trait + ////////////////////////////////////////////////////////////////// + if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + { + iPenalty = max(0, ((iPenalty * (100 - gSkillTraitValues.ubAWAutoFirePenaltyReduction * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/100)); + } + } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS_OT ) ) + { + iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT ); + } + } + ////////////////////////////////////////////////////////////////// + iChance -= iPenalty; + } + else if ( pSoldier->bDoAutofire > 0 ) + { +// CHRISL: At this point in the calculation, Bipods, Foregrips and other "recoil stabalizing" bonuses should reduce the weapons "recoil penalty" +// (AutoPenalty) by a percentage. This reduction should apply the the recoil per shot and not as a "flat" initial reduction. Later in the code, +// Bipods also grant their flat CTH bonus so we don't need to mess this that here + if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier) + { + iBonus = GetAutoToHitBonus(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier; + iPenalty = Weapon[pInHand->usItem].AutoPenalty * (pSoldier->bDoBurst - 1) * (gGameExternalOptions.bAimedBurstEnabled?gGameExternalOptions.uAimedBurstPenalty:1); + iPenalty = max(0, (iPenalty * (100 - iBonus))/100 ); + } + else + { + // Snap: bipod may reduce auto penalty + iPenalty = GetAutoPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * (pSoldier->bDoBurst - 1); + if(gGameExternalOptions.bAimedBurstEnabled) + iPenalty += Weapon[usInHand].AutoPenalty * (pSoldier->bDoBurst - 1) * gGameExternalOptions.uAimedBurstPenalty; + } + + // halve the penalty for people with the autofire trait + ////////////////////////////////////////////////////////////////// + if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + { + iPenalty = max(0, ((iPenalty * (100 - gSkillTraitValues.ubAWAutoFirePenaltyReduction * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/100)); + } + } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS_OT ) ) + { + iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT ); + } + } + ////////////////////////////////////////////////////////////////// + + iChance -= iPenalty; + // HEADROCK HAM 3.5: Store the penalty + sTotalAutofirePenalty = iPenalty; + } + + //ADB we need to calculate the distance visible and SoldierTo...LOSTests that we want to + //calculate it when firing, so the scope can be accounted for when the weapon is raised + //I consider this a hack to change the global, but passing a var alllll the way down to GetVisionBonus was worse + //if anyone wants to change it go for it, I don't know what usAnimState should be set + + //store old flag + UINT32 oldFlag = gAnimControl[ pSoldier->usAnimState ].uiFlags; + //add the necessary bits to the flag + gAnimControl[ pSoldier->usAnimState ].uiFlags |= (ANIM_FIREREADY | ANIM_FIRE); + + // 0verhaul: Changed to take expanded range from shooting at different levels into account + //ADB this change does nothing - either way it is random - we don't know what level we are shooting to, which is + //what the last parameter is, and the soldier's current level is as good a guess as ground level. + //so if you really want to fix this, pass in a value + sDistVis = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ); + + // CJC August 13 2002: Wow, this has been wrong the whole time. bTargetCubeLevel seems to be generally set to 2 - + // but if a character is shooting at an enemy in a particular spot, then we should be using the target position on the body. + + // CJC August 13, 2002 + // If the start soldier has a body part they are aiming at, and know about the person in the tile, then use that height instead + iSightRange = -1; + + // give some leeway to allow people to spot for each other... + //so make the range to calculate the bullet at 255+ + ubTargetID = WhoIsThere2( sGridNo, pSoldier->bTargetLevel ); + // best to use team knowledge as well, in case of spotting for someone else + // 0verhaul: Why not use the distance visible as the max for line of sight testing? + //ADB because A) the bullet can travel farther than I can see and B) I might have a spotter + + //We are firing a gun, and so the gun will be pointed and the scope will be used, even if it isn't now, so don't forget that we are in a firing animation + if (ubTargetID != NOBODY && pSoldier->aiData.bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY) + { + iSightRange = SoldierToSoldierLineOfSightTest( pSoldier, MercPtrs[ubTargetID], TRUE, NO_DISTANCE_LIMIT, pSoldier->bAimShotLocation, false ); + } + //CHRISL: This is useful if we're trying to target an opponent we can't actually see + iTileRange = SoldierTo3DLocationLineOfSightTest( pSoldier, sGridNo, pSoldier->bTargetLevel, pSoldier->bTargetCubeLevel, TRUE, NO_DISTANCE_LIMIT, false ); + if (iSightRange == -1) // didn't do a bodypart-based test + { + iSightRange = iTileRange; + } + // WANNE: Changed this, because RPGs are not in the calculation, only guns + //if ( Item[ usInHand ].usItemClass == IC_GUN ) + if ( Item[ usInHand ].usItemClass == IC_GUN || Item[ usInHand ].usItemClass == IC_LAUNCHER) + { + iMaxRange = GunRange( pInHand, pSoldier ); // SANDRO - added argument + } + else + { + iMaxRange = CELL_X_SIZE; // one tile + } + + if(iSightRange > 0){ + //Madd: Some gear can affect the to-hit bonus and the bonus from aiming + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: before bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); + //CHRISL: This is supposed to be a percentage increase/decrease + //iSightRange -= GetGearAimBonus ( pSoldier, iRange, ubAimTime ); + iSightRange -= GetGearAimBonus ( pSoldier, iRange, ubAimTime ) * iSightRange / 100; + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after gear bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); + + //CHRISL: We want our AimBonus to be based on our visual range, not our actual range + // Reduce effective range by the aiming bonus (e.g. from sniper scope) + //iSightRange -= GetAimBonus( pInHand, iRange, ubAimTime ); + iSightRange -= GetAimBonus( pInHand, iSightRange, ubAimTime ); + //CHRISL: If we have the Sniper skill, reduce effective range + ////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if ( gGameOptions.fNewTraitSystem ) + { + if ( HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) + { + iSightRange -= ((gSkillTraitValues.ubSNEffRangeToTargetReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )) * iSightRange) /100; + } + } + else if ( HAS_SKILL_TRAIT( pSoldier, PROF_SNIPER_OT ) ) + { + iSightRange -= ((gbSkillTraitBonus[ PROF_SNIPER_OT ] * NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )) * iSightRange) /100; + } + ////////////////////////////////////////////////////////////////// + if (iSightRange < 1) + { + iSightRange = 1; + } + } + + //restore old flag + gAnimControl[ pSoldier->usAnimState ].uiFlags = oldFlag; + + //CHRISL: Because of the changes I've made to how scopes modify iSightRange, this penalty makes it basically impossible + // to shot at targets you can't see yourself. While this isn't an issue for most weapons, it overly restricts the + // effectiveness of sniper rifles. So pull this penalty but leave the one that comes later in the code. + //if ( iSightRange > (sDistVis * CELL_X_SIZE) ) + //{ + // shooting beyond max normal vision... penalize such distance at double (also later we halve the remaining chance) + //iSightRange += (iSightRange - sDistVis * CELL_X_SIZE); + //} + + //CHRISL: Not being able to actually see the target should not restrict out ability to aim a weapon. Aiming is more then just sighting a specific target. It's + // also steadying the weapon and aiming where you think the target is. We will eventually get hit with a serious "Can't See the Target" penalty and aiming is + // the only way to even attempt to counter that. This is one reason for "Kevlar Grass" + // if shooter spent some extra time aiming and can see the target + //if (iSightRange > 0 && ubAimTime && !pSoldier->bDoBurst ) //comm by ddd + //if (iSightRange > 0 && ubAimTime ) + ////////////////////////////////////////////////////////////////// + if(ubAimTime) + { + // CHRISL: Rather then a flat +10/click bonus, we're going to try a bonus that's based on MRK and Lvl which gets + // progressivly less the more we aim. Everything is based on the maxBonus that a merc can possibly get which + // uses the equation: 20+(MRK/20*LVL)+Accuracy+(Sniper trait * 10). This value is then split between the 8 + // possible AimTime's using a max aimTime bonus of 10. + INT16 bonusProgression[8] = {500,500,600,600,750,750,750,1000}; + //FLOAT maxBonus = 20+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER )*10); + + ////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + FLOAT maxBonus; + if ( gGameOptions.fNewTraitSystem ) + { + // bonus to snipers and gunslingers + if ( Weapon[usInHand].ubWeaponType == GUN_PISTOL || Weapon[usInHand].ubWeaponType == GUN_PISTOL ) + maxBonus = 20+((FLOAT)iMarksmanship/20*(EffectiveExpLevel(pSoldier)))+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )*gSkillTraitValues.ubGSAimingBonusPerClick); + else + maxBonus = 20+((FLOAT)iMarksmanship/20*(EffectiveExpLevel(pSoldier)))+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )*gSkillTraitValues.ubSNAimingBonusPerClick); + } + else + { + if(gGameExternalOptions.bAltAimEnabled) + maxBonus = (20*(iMarksmanship/100))+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )*10); + else + maxBonus = 20+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )*10); + } + //}ddd + ////////////////////////////////////////////////////////////////// + INT8 maxClickBonus = 10; + FLOAT aimTimeBonus; + for(int i = 0; i < ubAimTime; i++) + { + aimTimeBonus = __min((maxBonus*bonusProgression[i]/1000),maxClickBonus); + maxBonus -= aimTimeBonus; + iChance += (INT32)floor(aimTimeBonus+.5); + } + ///ddd{ + //zilpin: aimed burst + //Reduce the aim time bonus based on weapon burst penalty, after the first shot. + //The burst penalty was already applied, but it also reduces the benefit of aiming. +// CHRISL: This is actaully applying the weapons AutoPenalty a second time. We already apply AutoPenalty/round (after the first) in the autofire +// section earlier in this code. We shouldn't be applying this again here. Plus, this modification should occur regardless of whether we aim +// or not. I've moved this condition to the burst/autofire portion of the code above. +// if(gGameExternalOptions.bAimedBurstEnabled) +// { +// //if( pSoldier->bDoAutofire ) +// // iChance -= Weapon[usInHand].AutoPenalty * pSoldier->bDoBurst * gGameExternalOptions.uAimedBurstPenalty; +// //else if( pSoldier->bDoBurst>1 ) +// // iChance -= Weapon[usInHand].ubBurstPenalty * pSoldier->bDoBurst * gGameExternalOptions.uAimedBurstPenalty; +// if( pSoldier->bDoAutofire>0 && pSoldier->bDoBurst>1) +// iChance -= Weapon[usInHand].AutoPenalty * pSoldier->bDoBurst * gGameExternalOptions.uAimedBurstPenalty; +// //if( pSoldier->bDoAutofire>10 ) +// // iChance -= Weapon[usInHand].AutoPenalty * pSoldier->bDoBurst * gGameExternalOptions.uAimedBurstPenalty; +// //else +// if( pSoldier->bDoBurst>1 && pSoldier->bDoAutofire==0) +// iChance -= Weapon[usInHand].ubBurstPenalty * pSoldier->bDoBurst * gGameExternalOptions.uAimedBurstPenalty; +// +// } + ///ddd} + +// if(highPowerScope == true) +// { +// { +// if ( NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER ) == 2 ) +// aimTimeBonus = -((__max(0,75-pSoldier->stats.bMarksmanship))/(pSoldier->stats.bExpLevel*2)); +// else if( NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER ) == 1 ) +// aimTimeBonus = -((__max(0,85-pSoldier->stats.bMarksmanship))/(pSoldier->stats.bExpLevel*2)); +// else +// aimTimeBonus = -((__max(0,100-pSoldier->stats.bMarksmanship))/(pSoldier->stats.bExpLevel)); +// aimTimeBonus = __max(-9, aimTimeBonus); +// aimTimeBonus = __min(0, aimTimeBonus); +// aimTimeBonus += AIM_BONUS_PER_AP; +// } +// else +// aimTimeBonus = AIM_BONUS_PER_AP; +// iChance += (aimTimeBonus * ubAimTime); // bonus for every pt of aiming + } + ////////////////////////////////////////////////////////////////// + + if ( !(pSoldier->flags.uiStatusFlags & SOLDIER_PC ) ) // if this is a computer AI controlled enemy + { + if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_EASY ) + { + // On easy, penalize all enemies by 5% + iChance -= 5; + } + else + { + // max with 0 to prevent this being a bonus, for JA2 it's just a penalty to make early enemies easy + // CJC note: IDIOT! This should have been a min. It's kind of too late now... + // CJC 2002-05-17: changed the max to a min to make this work. + iChance += __min( 0, gbDiff[ DIFF_ENEMY_TO_HIT_MOD ][ SoldierDifficultyLevel( pSoldier ) ] ); + } + } + + // if shooter is being affected by gas + if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) + { + iChance -= AIM_PENALTY_GASSED; + } + + // if shooter is being bandaged at the same time, his concentration is off + if (pSoldier->ubServiceCount > 0) + iChance -= AIM_PENALTY_GETTINGAID; + + // if shooter is still in shock + if (pSoldier->aiData.bShock) + { + // HEADROCK HAM B2.8: Placed a maximum here, as shock is now also used in suppression. + UINT16 usShockPenalty; + + usShockPenalty = pSoldier->aiData.bShock * AIM_PENALTY_PER_SHOCK; + + if (gGameExternalOptions.usMaxShooterCoweringPenalty > 0) + { + if ( usShockPenalty > gGameExternalOptions.usMaxShooterCoweringPenalty ) + usShockPenalty = gGameExternalOptions.usMaxShooterCoweringPenalty; + } + if ( usShockPenalty < 1 ) + usShockPenalty = 1; + + iChance -= usShockPenalty; + } + + //CHRISL: Just because we can't see a target, doesn't mean these armor/helmet modifiers should be ignored + iChance += GetGearToHitBonus ( pSoldier ); + + if ( iSightRange > 0 ) + { + //CHRISL: Moved iSightRange modifications to the range section above + // SANDRO - DELETED POINTLESS UNUSED PARTS OF CODE + + // HEADROCK HAM B2.1 : The TARGET's shock now also affects aiming. If the target is prone + // and in shock, they are harder to hit! This represents a target that's cowering as close + // to the ground (and as close to any possible cover, like a small dune or a fold of earth + // or anything like that). + if ( gGameExternalOptions.ubAimPenaltyPerTargetShock > 0 ) + { + // HEADROCK HAM B2.1 : This value determines how much penalty the target's shock-value gives the shooter. + // As of HAM B2.3: There's a maximum range at which 100% penalty is given. + // As of HAM B2.8: Target's stance and the targetted bodypart will affect the end result. + + INT8 AIM_PENALTY_PER_TARGET_SHOCK; + INT16 sCoweringPenalty = 0; + UINT8 ubCoweringDivisor; + UINT16 MIN_RANGE_FOR_FULL_COWER; + UINT16 MAX_TARGET_COWERING_PENALTY; + + AIM_PENALTY_PER_TARGET_SHOCK = gGameExternalOptions.ubAimPenaltyPerTargetShock; + MIN_RANGE_FOR_FULL_COWER = gGameExternalOptions.usMinRangeForFullCoweringPenalty; + MAX_TARGET_COWERING_PENALTY = gGameExternalOptions.usMaxTargetCoweringPenalty; + + pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel ); + if (pTarget != NULL) + { + if (pTarget->aiData.bShock ) + { + if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE) + { + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorProne; + + sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK); + sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor; + sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER; + + if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0) + { + if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty ) + sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty; + } + if ( sCoweringPenalty < 1 ) + sCoweringPenalty = 1; + + iChance -= sCoweringPenalty; + } + else if (gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_CROUCH) + { + switch ( ubAimPos ) + { + case AIM_SHOT_HEAD: + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedHead; + break; + case AIM_SHOT_TORSO: + case AIM_SHOT_RANDOM: + case AIM_SHOT_GLAND: + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedTorso; + break; + case AIM_SHOT_LEGS: + ubCoweringDivisor = gGameExternalOptions.ubCoweringPenaltyDivisorCrouchedLegs; + break; + } + + sCoweringPenalty = (pTarget->aiData.bShock * AIM_PENALTY_PER_TARGET_SHOCK); + sCoweringPenalty = sCoweringPenalty / ubCoweringDivisor; + sCoweringPenalty = (sCoweringPenalty * __min(iSightRange,MIN_RANGE_FOR_FULL_COWER)) / MIN_RANGE_FOR_FULL_COWER; + + if (gGameExternalOptions.usMaxTargetCoweringPenalty > 0) + { + if ( sCoweringPenalty > gGameExternalOptions.usMaxTargetCoweringPenalty ) + sCoweringPenalty = gGameExternalOptions.usMaxTargetCoweringPenalty; + } + if ( sCoweringPenalty < 1 ) + sCoweringPenalty = 1; + + // HEADROCK HAM B2.8.1: Added formula to make sure that cowering target penalties + // are not given when on the roof. + + if (pSoldier->pathing.bLevel == pTarget->pathing.bLevel && pSoldier->pathing.bLevel > 0) + sCoweringPenalty = 0; // No cowering penalties when both are on the roof! + else if (pSoldier->pathing.bLevel < pSoldier->pathing.bLevel && gAnimControl[ pTarget->usAnimState ].ubHeight == ANIM_PRONE) + sCoweringPenalty *= 2; // Much harder to shoot at anyone cowering above you. + else if (pSoldier->pathing.bLevel > pSoldier->pathing.bLevel) + sCoweringPenalty /= 2; // Much easier to shoot at cowerers below you. + iChance -= sCoweringPenalty; + } + } + } + } + } + + //CHRISL: This should effect us regardless of whether we can see the target or not + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after scope bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); + // Apply flat to-hit bonus (e.g. from laser scope) + // Snap: If prone and range is good, apply bipod bonus here as well + iChance += GetToHitBonus( pInHand, iRange, bLightLevel,gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE && iRange > MIN_PRONE_RANGE ); + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: after to hit bonus - ubAimTime = %d, iSightRange = %d, iChance = %d ", ubAimTime, iSightRange, iChance)); + + //NumMessage("EFFECTIVE RANGE = ",range); + + // ADJUST FOR RANGE + // bonus if range is less than normal range, penalty if it's more + //iChance += (NORMAL_RANGE - iRange) / (CELL_X_SIZE / 5); // 5% per tile + + // Effects of actual gun max range... the numbers are based on wanting -40% + // at range 26for a pistol with range 13, and -0 for a sniper rifle with range 80 + iPenalty = ((iMaxRange - iRange * 3) * 10) / (17 * CELL_X_SIZE); + if ( iPenalty < 0 ) + { + // No penalty on tanks + //if (!TANK(pSoldier)) + iChance += iPenalty; + } + //iChance -= 20 * iRange / iMaxRange; + + if ( TANK( pSoldier ) && ( iRange / CELL_X_SIZE < MaxNormalDistanceVisible() ) ) + { + // tank; penalize at close range! + // 2 percent per tile closer than max visible distance + iChance -= 2 * ( MaxNormalDistanceVisible() - (iRange / CELL_X_SIZE) ); + } + + ///////////////////////////////////////////////////////////////////////////////////////// + // Target Size Penalties + //if (iSightRange == 0) + //{ + // firing blind! + //iChance -= AIM_PENALTY_BLIND; + //} + if ( pSoldier->aiData.bOppList[ubTargetID] != SEEN_CURRENTLY &&(pSoldier->flags.uiStatusFlags & SOLDIER_PC) ) + iChance -=gGameExternalOptions.iPenaltyShootUnSeen; + else + { + // Effects based on aiming & sight + // From for JA2.5: 3% bonus/penalty for each tile different from range NORMAL_RANGE. + // This doesn't provide a bigger bonus at close range, but stretches it out, making medium + // range less penalized, and longer range more penalized + + // WANNE: No penalty on the tank + if (!TANK(pSoldier)) + iChance += 3 * ( NORMAL_RANGE - iSightRange ) / CELL_X_SIZE; + // if aiming at the head, reduce chance to hit + if (ubAimPos == AIM_SHOT_HEAD) + { + // penalty of 3% per tile + //iPenalty = 3 * iSightRange / 10; //comm by ddd + iPenalty = INT32(gGameExternalOptions.uShotHeadPenalty * iSightRange / 10); + iChance -= iPenalty; + } + else if (ubAimPos == AIM_SHOT_LEGS) + { + // penalty of 1% per tile + iPenalty = iSightRange / 10; + iChance -= iPenalty; + } + +// if (iSightRange < NORMAL_RANGE) +// { +// // bonus to hit of 20% at point blank (would be 25% at range 0); +// //at NORMAL_RANGE, bonus is 0 +// iChance += 25 * (NORMAL_RANGE - iSightRange) / NORMAL_RANGE; +// } +// else +// { +// // penalty of 2% / tile +// iChance -= (iSightRange - NORMAL_RANGE) / 5; +// } + } + ///////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////////// + // Tracer effects + // HEADROCK HAM 3.5: Moved this here for now. + // HEADROCK HAM B2.5: One of every X bullets in a tracer magazine is a tracer round, which will + // bump the CTH up by a certain amount. + + if (AmmoTypes[(*pInHand)[0]->data.gun.ubGunAmmoType].tracerEffect == 1 && gGameExternalOptions.ubRealisticTracers > 0 ) + { + UINT16 iBulletsLeft, iTracersFired, iBulletsPerTracer, iBulletsSinceLastTracer=0, iRoundsFiredPreviously; + UINT8 cnt; + UINT8 ubAutoPenaltySinceLastTracer=0; + //UINT16 iAutoPenaltySinceLastTracer; + iTracersFired = 0; + iBulletsPerTracer = gGameExternalOptions.ubNumBulletsPerTracer; + + // Calculate number of bullets left right before firing this burst + if (fCalculateCTHDuringGunfire) + { + iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft + (pSoldier->bDoBurst - 1); + } + else + { + iBulletsLeft = (*pInHand)[0]->data.gun.ubGunShotsLeft; + } + +// CHRISL: What we want to know here is how many tracers have been fired during this autofire sequence. But we also want to figure that based on how +// much ammo we've used from the current load. If every 3rd round is a tracer, and we previously fired 5 rounds from our "mag", then the first +// round of this burst is a tracer, the 2nd & 3rd are normal, the 4th is a tracer, 5th & 6th are normal, etc. + iRoundsFiredPreviously = GetMagSize(pInHand) - iBulletsLeft; //How many rounds had been fired before this autofire sequence + for( cnt = 1; cnt <= pSoldier->bDoBurst; cnt++ ){ + if((iRoundsFiredPreviously+cnt)%iBulletsPerTracer == 0) + iTracersFired++; + } + +// iBulletsSinceLastTracer = 0; +// for (cnt=0;cntbDoBurst;cnt++) +// { +// iBulletsSinceLastTracer++; +// if ((( iBulletsLeft - (cnt - 1) ) / iBulletsPerTracer) - ((iBulletsLeft - cnt) / iBulletsPerTracer) == 1) +// { +// iBulletsSinceLastTracer = 0; +// } +// } +// +// iTracersFired = ((iBulletsLeft+1) / iBulletsPerTracer) - (((iBulletsLeft+1) - (pSoldier->bDoBurst)) / iBulletsPerTracer); + + if ( iTracersFired > 0 ) + { + // HEADROCK HAM 3.5: I'm going to revise this - my current system makes no sense at all. What was I + // thinking?! +// CHRISL: Headrock may come around later and revise this again, but for the time being, I'm making some adjustments. With the current code +// the number of tracer rounds fired doesn't really matter. In most cases, the range is going to limit the max bonus so much that 1 tracer or +// 20 will have the same effect because we currently look at the "bump" value times the number of rouns and THEN modify for range. What we +// should be doing is modify the bump for range, multiply that by the number of tracer rounds fired, then make sure the bonus isn't more then +// our combined autofire penalty. + + // Correct all autofire penalty so far + //iBonus = iPenalty; + + // Add Tracer Bump if previous bullet was a tracer + //iBonus += (gGameExternalOptions.ubCTHBumpPerTracer * iTracersFired); + //iBonus = (gGameExternalOptions.ubCTHBumpPerTracer * iTracersFired); + + // Calculate penalty since last tracer was fired + // CHRISL: We already look at GetAutoPenalty earlier in the code, and that result was stored as sTotalAutofirePenalty so why this wonky recalculation? + //UINT8 ubAutoPenaltySinceLastTracer = GetAutoPenalty(pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) * iBulletsSinceLastTracer; + ////////////////////////////////////////////////////////////////// +// if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO +// { +// if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) +// { +// ubAutoPenaltySinceLastTracer = max(0, ((ubAutoPenaltySinceLastTracer * (100 - gSkillTraitValues.ubAWAutoFirePenaltyReduction * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/100)); +// } +// } +// else +// { +// if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS_OT ) ) +// { +// ubAutoPenaltySinceLastTracer /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT ); +// } +// } +// ////////////////////////////////////////////////////////////////// +// // Add penalty to bonus. +// //iBonus -= iAutoPenaltySinceLastTracer; + + /////////////////////////////////////////////////// + // HEADROCK HAM 3.5: Limit maximum bonus by range. +// CHRISL: We want to limit the maximum bonus "per round" by range. The way we have been doing it, it's max bonus by range, regardless of the +// number of rounds fired. This means firing 1 tracer or 20 makes no difference. And we can run this calculation directly again +// sTotalAutofirePenalty. + + if(sTotalAutofirePenalty > 0){ + INT16 sChanceLimit = min(gGameExternalOptions.ubCTHBumpPerTracer, ((iRange-(gGameExternalOptions.ubMinRangeTracerEffect*CELL_X_SIZE)) / CELL_X_SIZE) * gGameExternalOptions.ubRangeDifficultyAimingWithTracers); + sChanceLimit = max(0, sChanceLimit); + iBonus = sChanceLimit * iTracersFired; + iBonus = min(iBonus, sTotalAutofirePenalty); + } + + //INT16 sChanceLimit = __min(0, sTotalAutofirePenalty+(((iRange-100) / CELL_X_SIZE) * gGameExternalOptions.ubRangeDifficultyAimingWithTracers)); + + //INT16 sBaseChance = iChance + sTotalAutofirePenalty; + + // We don't want to enforce a limit unless the tracers have actually put us over the original CtH. +// if (sBaseChance <= iChance+iBonus) // Base_Chance without AutoPen, less or equal to Current_Chance plus tracer bumps +// { +// // store lowest: Chance+Tracer bumps, or Range-enforced limit +// INT16 sChanceLimit = __min(iChance+iBonus, sBaseChance+(((iRange-100) / CELL_X_SIZE) * gGameExternalOptions.ubRangeDifficultyAimingWithTracers)); +// // store highest: Chance Delta or base CtH +// //sChanceDelta = __max(sChanceDelta, sBaseChance); +// +// // iBonus is the distance between the enforced limit (if any) and the current chance with all penalties so far. +// // But it can't be negative, 'cause it's a bonus. +// iBonus = __max(0,sChanceLimit - iChance); +// // Add autopenalty since last tracer +// if (iBulletsSinceLastTracer < iBulletsPerTracer) +// { +// iBonus -= ubAutoPenaltySinceLastTracer; +// } +// +// } + iChance += iBonus; + } + } + ///////////////////////////////////////////////////////////////////////////////////////// + + // adjust for roof/not on roof + if ( pSoldier->pathing.bLevel == 0 ) + { + if ( pSoldier->bTargetLevel > 0 ) + { + // penalty for firing up + iChance -= AIM_PENALTY_FIRING_UP; + } + } + else // pSoldier->pathing.bLevel > 0 ) + { + if ( pSoldier->bTargetLevel == 0 ) + { + iChance += AIM_BONUS_FIRING_DOWN; + } + } + + + pTarget = SimpleFindSoldier( sGridNo, pSoldier->bTargetLevel ); + //CHRISL: A target's stance should have no impact on an aimed, headshot. The head doesn't get any smaller just because the target is crouching down. + if (pTarget != NULL && ubAimPos != AIM_SHOT_HEAD) + { + // targeting a merc + // adjust for crouched/prone target + switch( gAnimControl[ pTarget->usAnimState ].ubHeight ) + { + case ANIM_CROUCH: + if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE ) + { + // 13% penalty per tile closer than min range + iChance -= 13 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ); + } + else + { + // at anything other than point-blank range + if (iRange > POINT_BLANK_RANGE + 10 * (AIM_PENALTY_TARGET_CROUCHED / 3) ) + { + iChance -= AIM_PENALTY_TARGET_CROUCHED; + } + else if (iRange > POINT_BLANK_RANGE) + { + // at close range give same bonus as prone, up to maximum of AIM_PENALTY_TARGET_CROUCHED + iChance -= 3 * ((iRange - POINT_BLANK_RANGE) / CELL_X_SIZE); // penalty -3%/tile + } + } + break; + case ANIM_PRONE: + if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE ) + { + // 25% penalty per tile closer than min range + iChance -= 25 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ); + } + else + { + // at anything other than point-blank range + if (iRange > POINT_BLANK_RANGE) + { + // reduce chance to hit with distance to the prone/immersed target + iPenalty = 3 * ((iRange - POINT_BLANK_RANGE) / CELL_X_SIZE); // penalty -3%/tile + iPenalty = __min( iPenalty, AIM_PENALTY_TARGET_PRONE ); + + iChance -= iPenalty; + } + } + break; + case ANIM_STAND: + // if we are prone and at close range, then penalize shots to the torso or head! + if ( iRange <= MIN_PRONE_RANGE && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) + { + if ( ubAimPos == AIM_SHOT_RANDOM || ubAimPos == AIM_SHOT_GLAND ) + { + ubAdjAimPos = AIM_SHOT_TORSO; + } + else + { + ubAdjAimPos = ubAimPos; + } + // lose 10% per height difference, lessened by distance + // e.g. 30% to aim at head at range 1, only 10% at range 3 + // or 20% to aim at torso at range 1, no penalty at range 3 + // NB torso aim position is 2, so (5-aimpos) is 3, for legs it's 2, for head 4 + iChance -= (5 - ubAdjAimPos - iRange / CELL_X_SIZE) * 10; + } + break; + default: + break; + } + + // penalty for amount that enemy has moved + // HEADROCK HAM B2.6: Externalized the value + iPenalty = __min( (UINT16)((float)pTarget->bTilesMoved * (float)gGameExternalOptions.iMovementEffectOnAiming), 30 ); + /////////////////////////////////////////////////////////////////////////////////// + // SANDRO - fearless characters do not even take their head down no matter what + if ( gGameOptions.fNewTraitSystem && pTarget->ubProfile != NO_PROFILE ) + { + if ( gMercProfiles[ pTarget->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + iPenalty -= (iPenalty * 2 / 3); // two thirds only + } + /////////////////////////////////////////////////////////////////////////////////// iChance -= iPenalty; // if target sees us, he may have a chance to dodge before the gun goes off @@ -4442,7 +7979,8 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, // This won't cause the bullet to be off to the left or right, only make it // drop in flight. - iChance /= 2; + //iChance /= 2; //ddd + iChance /= gGameExternalOptions.fOutOfGunRangeOrSight; } if ( iSightRange > (sDistVis * CELL_X_SIZE) ) { @@ -4450,6 +7988,51 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, iChance /= 2; } + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Bonus CtH for Militia + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sGreenMilitiaCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sRegularMilitiaCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); + // bonus for enemy + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyEliteCtHBonusPercent) /100); + ////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - option to make special NPCs stronger - chance to hit + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( pSoldier->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + iChance += (iChance * gGameExternalOptions.usSpecialNPCStronger / 100); + break; + } + } + //////////////////////////////////////////////////////////////////////////////////// + // MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS // HEADROCK: (HAM) Altered so called "Defined Limits" to accept external arguments. // The divisor argument only works when the minimum is set to 0. It has a chance of 1 in X to @@ -4486,7 +8069,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, // NumMessage("ChanceToHit = ",chance); DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CalcChanceToHitGun: ichance = %d",iChance)); - return (iChance); + return (iChance);*/ } UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ) @@ -4499,6 +8082,49 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim pSoldier->usAnimState = STANDING; uiChance = CalcChanceToHitGun( pSoldier, sGridNo, ubAimTime, ubAimPos ); pSoldier->usAnimState = usTrueState; + if(UsingNewCTHSystem() == true) + { + //////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: NCTH calculation + // + // In the new CTH system, the value returned by CalcChanceToHitGun is not an actual + // chance to hit the target. In fact, it is simply a measure of how well the gun is + // aimed. To get a good idea of whether or not a shot is likely to hit the target, + // we need to take other factors into consideration. + + FLOAT d2DDistance = (FLOAT) PythSpacesAway( pSoldier->sGridNo, sGridNo ) * 10.0f; + FLOAT dMagFactor = CalcMagFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance, (UINT8)ubAimTime ); + FLOAT dDistanceFactor = (d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); + + uiChance = (UINT32)((uiChance * dMagFactor) / dDistanceFactor); + + FLOAT dBasicAperture = CalcBasicAperture( ); + FLOAT dAperture = (dBasicAperture * (100-uiChance)) / 100.0f; + + if (dAperture == 0) + { + return 100; + } + else + { + FLOAT dTargetArea = 28.26f; // Calculated area of a target given known homan body size. + FLOAT dApertureArea = (FLOAT)(PI * (dAperture * dAperture)); + + uiChance = (UINT32)__min(100, (dTargetArea / dApertureArea) * 100); + } + + FLOAT dGunRange = (FLOAT)(GunRange( &(pSoldier->inv[pSoldier->ubAttackingHand]), pSoldier ) ); + if ( (dGunRange * 1.1f) < d2DDistance) + { + // Weapon out of conceivable hit range. Reduce chance to hit to 0! + return (0); + } + else if ( dGunRange < d2DDistance) + { + // Just outside range. Reduce considerably! + return (uiChance / 2); + } + } return( uiChance ); } @@ -4662,7 +8288,7 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u if (pArmour->exists() == true) { for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) { - if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 ) + if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists()) { // bullet got through jacket; apply ceramic plate armour iTotalProtection += ArmourProtection( pTarget, Item[iter->usItem].ubClassIndex, &((*iter)[0]->data.objectStatus), iImpact, ubAmmoType, &plateHit ); @@ -4692,7 +8318,7 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u { //Madd: put any attachments that someone might have added to the armour in the merc's inventory for (attachmentList::iterator iter = (*pArmour)[0]->attachments.begin(); iter != (*pArmour)[0]->attachments.end(); ++iter) { - if ( !AutoPlaceObject( pTarget, &(*iter), FALSE ) ) + if ( !AutoPlaceObject( pTarget, &(*iter), FALSE ) && iter->exists()) { // put it on the ground AddItemToPool( pTarget->sGridNo, &(*iter), 1, pTarget->pathing.bLevel, 0 , -1 ); } @@ -4710,7 +8336,7 @@ INT32 TotalArmourProtection( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 u INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocation, INT32 iOrigImpact, INT16 sHitBy, UINT8 * pubSpecial ) { INT32 iImpact, iFluke, iBonus, iImpactForCrits = 0; - INT8 bStatLoss; + INT8 bStatLoss = 0; UINT8 ubAmmoType; // NOTE: reduction of bullet impact due to range and obstacles is handled @@ -4821,6 +8447,81 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat // iImpact = AMMO_DAMAGE_ADJUSTMENT_HP( iImpact ); //} + //////////////////////////////////////////////////////////////////////////////////// + if ( gGameOptions.fNewTraitSystem ) // new traits bonuses - SANDRO + { + // Throwing skill increases damage of knives here + if ( (ubAmmoType == AMMO_KNIFE) && HAS_SKILL_TRAIT( pFirer, THROWING_NT )) + { + iImpact += (INT32)(iImpact * (gSkillTraitValues.ubTHBladesDamageBonus + (gSkillTraitValues.ubTHBladesDamageBonusPerClick * pFirer->aiData.bAimTime))/100); + } + + // Sniper trait adds bonus damage per aim click + if (HAS_SKILL_TRAIT( pFirer, SNIPER_NT ) && (pFirer->aiData.bAimTime >= gSkillTraitValues.ubSNDamageBonusFromNumClicks)) + { + iImpact += (INT32)(iImpact * (pFirer->aiData.bAimTime - gSkillTraitValues.ubSNDamageBonusFromNumClicks + 1) * gSkillTraitValues.ubSNDamageBonusPerClick * NUM_SKILL_TRAITS( pFirer, SNIPER_NT ))/100; // +5% per trait + } + } + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Damage resistance for Militia + if (!IsAutoResolveActive()) + { + if (pTarget->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.bGreenMilitiaDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.bRegularMilitiaDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.bVeteranMilitiaDamageResistance) /100); + // bonus for enemy too + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.sEnemyAdminDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.sEnemyRegularDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.sEnemyEliteDamageResistance) /100); + + + iImpact = max( 1, iImpact); + } + ////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - option to make special NPCs stronger - damage resistance + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( pTarget->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + // Only 1/2 of the bonus + iImpact -= (INT32)(iImpact * gGameExternalOptions.usSpecialNPCStronger / 200); + iImpact = max( 1, iImpact); + break; + } + } + //////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - Bodybuilding damage resistance + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pTarget, BODYBUILDING_NT ) ) + iImpact = max( 1, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100)); + //////////////////////////////////////////////////////////////////////////////////// + AdjustImpactByHitLocation( iImpact, ubHitLocation, &iImpact, &iImpactForCrits ); switch( ubHitLocation ) @@ -4835,7 +8536,11 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat { // blow to the head is so deadly that it causes instant death; // the target has more life than iImpact so we increase it - iImpact = pTarget->stats.bLife + Random( 10 ); + if( iImpact < pTarget->stats.bLife ) // Added check here to see the real impact in game if bigger than life - SANDRO + iImpact = pTarget->stats.bLife + Random( 10 ); + else + iImpact += Random( 10 ); + iImpactForCrits = iImpact; } @@ -4884,13 +8589,21 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat { // blow to the chest is so deadly that it causes instant death; // the target has more life than iImpact so we increase it - iImpact = pTarget->stats.bLife + Random( 10 ); + if( iImpact < pTarget->stats.bLife ) // Added check here to see the real impact in game if bigger than life - SANDRO + iImpact = pTarget->stats.bLife + Random( 10 ); + else + iImpact += Random( 10 ); + iImpactForCrits = iImpact; } // special thing for hitting chest - allow cumulative damage to count else if ( (iImpact + pTarget->sDamage) > (MIN_DAMAGE_FOR_BLOWN_AWAY + MIN_DAMAGE_FOR_INSTANT_KILL) ) { - iImpact = pTarget->stats.bLife + Random( 10 ); + if( iImpact < pTarget->stats.bLife ) // Added check here to see the real impact in game if bigger than life - SANDRO + iImpact = pTarget->stats.bLife + Random( 10 ); + else + iImpact += Random( 10 ); + iImpactForCrits = iImpact; } @@ -4919,168 +8632,295 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat if ( AmmoTypes[ubAmmoType].knife && pFirer->aiData.bOppList[ pTarget->ubID ] == SEEN_CURRENTLY ) { // is this a stealth attack? - if ( pTarget->aiData.bOppList[ pFirer->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget ) && (ubHitLocation == AIM_SHOT_HEAD || ubHitLocation == AIM_SHOT_TORSO ) ) + if ( pTarget->aiData.bOppList[ pFirer->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget ) + && (ubHitLocation == AIM_SHOT_HEAD || ubHitLocation == AIM_SHOT_TORSO ) && (pTarget->aiData.bAlertStatus < STATUS_RED || !gGameExternalOptions.fEnhancedCloseCombatSystem) ) // Added check if enemy is alerted - SANDRO { - if ( PreRandom( 100 ) < (UINT32)(sHitBy + 10 * NUM_SKILL_TRAITS( pFirer, THROWING )) ) + // HEADROCK HAM 4: With the original CTH system, the HitBy value represented a randomal margin by + // which the shooter surpassed his CTH value. Therefore, only a high CTH shot which randomly succeeded + // by a wide margin could reach values of 80 and above, and even then they were rare. + // In the new system, HitBy represents a shooter's effort to make his shot more accurate, so shots + // done with large amounts of aiming and skill would always result in high HitBy values (up to ~70-80% + // regularly for the average shooting using maximum aiming). This means that high HitBy values are now + // somewhat more common. + // With regards to this bit of code, an increase in average HitBy means that its effect on the formula + // should be lessened a little to maintain the same ratio of instant-deaths as in JA2. However, I am + // reluctant to make any changes, mainly because I think there's no problem with stealth knife hits + // being deadlier. If, however, it is discovered that stealth insta-kills are too common and too powerful, + // reduce the effect of this sHitBy, possibly by dividing it here. + + ////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if( !gGameOptions.fNewTraitSystem ) { - // instant death! - iImpact = pTarget->stats.bLife + Random( 10 ); - iImpactForCrits = iImpact; + if ( PreRandom( 100 ) < (UINT32)(sHitBy + 10 * NUM_SKILL_TRAITS( pFirer, THROWING_OT )) ) + { + // instant death! + if( iImpact < pTarget->stats.bLife ) // Added check here to see the real impact in game if bigger than life - SANDRO + iImpact = pTarget->stats.bLife + Random( 10 ); + else + iImpact += Random( 10 ); + + iImpactForCrits = iImpact; + } } + else + { + // Throwing trait increases chance to silent critical hit + if ( PreRandom( 100 ) < (UINT32)(sHitBy + (HAS_SKILL_TRAIT( pFirer, THROWING_NT ) ? gSkillTraitValues.ubTHBladesSilentCriticalHitChance : 0)) ) + { + // No no no, we don't want instant kill in this case, + // but rather tripled damage, so it also always matters what knife we use - SANDRO + iImpact *= ( 3 + gSkillTraitValues.ubTHBladesCriticalHitMultiplierBonus); + + iImpactForCrits = iImpact; + } + } + ////////////////////////////////////////////////////////////////////////////////// } } - if (iImpactForCrits > 0 && iImpactForCrits < pTarget->stats.bLife ) + if (iImpactForCrits > 0 && iImpactForCrits < pTarget->stats.bLife && !(pTarget->flags.uiStatusFlags & SOLDIER_MONSTER) ) // not to monsters - SANDRO { - if (PreRandom( iImpactForCrits / 2 + pFirer->aiData.bAimTime * 5) + 1 > CRITICAL_HIT_THRESHOLD) + UINT32 uiCritChance = (iImpactForCrits / 2) + (pFirer->aiData.bAimTime * 5); + BOOLEAN fMaliciousHit = FALSE; + // SANDRO - Malicious characters inflict stat loss more often + if ( gGameOptions.fNewTraitSystem && pFirer->ubProfile != NO_PROFILE ) + { + if ( gMercProfiles[ pFirer->ubProfile ].bCharacterTrait == CHAR_TRAIT_MALICIOUS ) + { + uiCritChance += 8; + fMaliciousHit = TRUE; + } + } + // SANDRO - with new traits, the chance for stat loss is higher as we are now able to repair it + if ((PreRandom( uiCritChance ) + 1) > (UINT8)(gGameOptions.fNewTraitSystem ? gSkillTraitValues.ubDamageNeededToLoseStats : CRITICAL_HIT_THRESHOLD)) { bStatLoss = (INT8) PreRandom( iImpactForCrits / 2 ) + 1; - switch( ubHitLocation ) + // SANDRO - malicious hit + if ( fMaliciousHit && Chance( max( 15, uiCritChance )) && ( ubHitLocation == AIM_SHOT_TORSO || ubHitLocation == AIM_SHOT_LEGS ) && + ( sHitBy >= 20 ) && ( pTarget->ubBodyType <= STOCKYMALE ) && ( gAnimControl[ pTarget->usAnimState ].ubHeight != ANIM_PRONE ) ) { - case AIM_SHOT_HEAD: - if (bStatLoss >= pTarget->stats.bWisdom) - { - bStatLoss = pTarget->stats.bWisdom - 1; - } - if ( bStatLoss > 0 ) - { - pTarget->stats.bWisdom -= bStatLoss; + // no stats to lose, but drain breath a lot + DeductPoints( pTarget, 0, (5 * APBPConstants[BP_GET_HIT]) ); + SoldierCollapse( pTarget ); - if (pTarget->ubProfile != NO_PROFILE) + if (pTarget->name[0] && pTarget->bVisible == TRUE) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_SOLDIER_HIT_TO_GROIN], pTarget->name ); + } + // Gain morale for inflicting critical hit + HandleMoraleEvent( pFirer, MORALE_MALICIOUS_HIT, pFirer->sSectorX, pFirer->sSectorY, pFirer->bSectorZ ); + + } + else + { + switch( ubHitLocation ) + { + case AIM_SHOT_HEAD: + if (bStatLoss >= pTarget->stats.bWisdom) { - gMercProfiles[ pTarget->ubProfile ].bWisdom = pTarget->stats.bWisdom; - } - - - if (pTarget->name[0] && pTarget->bVisible == TRUE) - { - // make stat RED for a while... - pTarget->timeChanges.uiChangeWisdomTime = GetJA2Clock(); - pTarget->usValueGoneUp &= ~( WIS_INCREASE ); - - if (bStatLoss == 1) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_WISDOM], pTarget->name ); - } - else - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_WISDOM], pTarget->name, bStatLoss ); - } - } - } - else if ( pTarget->bNumPelletsHitBy == 0 ) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_HEAD_HIT], pTarget->name ); - } - - // HEADROCK HAM 3.2: Critical headshots may now cause blindness, based on shot damage. - if (gGameExternalOptions.ubChanceBlindedByHeadshot) - { - if (__min(100,(PreRandom(100)+1 + iImpact)) <= gGameExternalOptions.ubChanceBlindedByHeadshot) - { - if (pTarget->bBlindedCounter < iImpact / 10 ) - pTarget->bBlindedCounter = iImpact / 10; - } - } - - break; - case AIM_SHOT_TORSO: - if (PreRandom( 1 ) == 0 && !(pTarget->flags.uiStatusFlags & SOLDIER_MONSTER) ) - { - if (bStatLoss >= pTarget->stats.bDexterity) - { - bStatLoss = pTarget->stats.bDexterity - 1; + bStatLoss = pTarget->stats.bWisdom - 1; } if ( bStatLoss > 0 ) { - pTarget->stats.bDexterity -= bStatLoss; + pTarget->stats.bWisdom -= bStatLoss; + // SANDRO - added this for healing lost stats feature + pTarget->ubCriticalStatDamage[DAMAGED_STAT_WISDOM] += bStatLoss; if (pTarget->ubProfile != NO_PROFILE) { - gMercProfiles[ pTarget->ubProfile ].bDexterity = pTarget->stats.bDexterity; + gMercProfiles[ pTarget->ubProfile ].bWisdom = pTarget->stats.bWisdom; } if (pTarget->name[0] && pTarget->bVisible == TRUE) { // make stat RED for a while... - pTarget->timeChanges.uiChangeDexterityTime = GetJA2Clock(); - pTarget->usValueGoneUp &= ~( DEX_INCREASE ); + pTarget->timeChanges.uiChangeWisdomTime = GetJA2Clock(); + pTarget->usValueGoneUp &= ~( WIS_INCREASE ); if (bStatLoss == 1) { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_DEX], pTarget->name ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_WISDOM], pTarget->name ); } else { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_DEX], pTarget->name, bStatLoss ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_WISDOM], pTarget->name, bStatLoss ); } } } - } - else - { - if (bStatLoss >= pTarget->stats.bStrength) + else if ( pTarget->bNumPelletsHitBy == 0 ) { - bStatLoss = pTarget->stats.bStrength - 1; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_HEAD_HIT], pTarget->name ); + } + + // HEADROCK HAM 3.2: Critical headshots may now cause blindness, based on shot damage. + if (gGameExternalOptions.ubChanceBlindedByHeadshot) + { + if (PreRandom(gGameExternalOptions.ubChanceBlindedByHeadshot) == 0) + { + if (pTarget->bBlindedCounter < iImpact / 10 ) + pTarget->bBlindedCounter = iImpact / 10; + } + } + + break; + case AIM_SHOT_TORSO: + // SANDRO - added a 20% chance to loose maximum health + if ( PreRandom( 5 ) == 0 ) + { + if (bStatLoss >= (pTarget->stats.bLifeMax - OKLIFE)) + { + bStatLoss = pTarget->stats.bLifeMax - OKLIFE - 1; + } + if ( bStatLoss > iImpact) + { + bStatLoss = iImpact; + } + if ( bStatLoss > 0 ) + { + pTarget->stats.bLifeMax -= bStatLoss; + // SANDRO - added this for healing lost stats feature + pTarget->ubCriticalStatDamage[DAMAGED_STAT_HEALTH] += bStatLoss; + + if (pTarget->ubProfile != NO_PROFILE) + { + gMercProfiles[ pTarget->ubProfile ].bLifeMax = pTarget->stats.bLifeMax; + } + + if (pTarget->name[0] && pTarget->bVisible == TRUE) + { + // make stat RED for a while... + pTarget->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pTarget->usValueGoneUp &= ~( HEALTH_INCREASE ); + + if (bStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_LOSES_ONE_POINT_MAX_HEALTH], pTarget->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_LOSES_X_POINTS_MAX_HEALTH], pTarget->name, bStatLoss ); + } + } + } + } + else + { + // 50:50 to lose strength or dexterity + if (PreRandom( 3 ) < 4 ) + { + if (bStatLoss >= pTarget->stats.bDexterity) + { + bStatLoss = pTarget->stats.bDexterity - 1; + } + if ( bStatLoss > 0 ) + { + pTarget->stats.bDexterity -= bStatLoss; + // SANDRO - added this for healing lost stats feature + pTarget->ubCriticalStatDamage[DAMAGED_STAT_DEXTERITY] += bStatLoss; + + if (pTarget->ubProfile != NO_PROFILE) + { + gMercProfiles[ pTarget->ubProfile ].bDexterity = pTarget->stats.bDexterity; + } + + if (pTarget->name[0] && pTarget->bVisible == TRUE) + { + // make stat RED for a while... + pTarget->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pTarget->usValueGoneUp &= ~( DEX_INCREASE ); + + if (bStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_DEX], pTarget->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_DEX], pTarget->name, bStatLoss ); + } + } + } + } + else + { + if (bStatLoss >= pTarget->stats.bStrength) + { + bStatLoss = pTarget->stats.bStrength - 1; + } + if ( bStatLoss > 0 ) + { + pTarget->stats.bStrength -= bStatLoss; + // SANDRO - added this for healing lost stats feature + pTarget->ubCriticalStatDamage[DAMAGED_STAT_STRENGTH] += bStatLoss; + + if (pTarget->ubProfile != NO_PROFILE) + { + gMercProfiles[ pTarget->ubProfile ].bStrength = pTarget->stats.bStrength; + } + + if (pTarget->name[0] && pTarget->bVisible == TRUE) + { + // make stat RED for a while... + pTarget->timeChanges.uiChangeStrengthTime = GetJA2Clock(); + pTarget->usValueGoneUp &= ~( STRENGTH_INCREASE ); + + if (bStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_STRENGTH], pTarget->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_STRENGTH], pTarget->name, bStatLoss ); + } + } + } + } + } + break; + case AIM_SHOT_LEGS: + if (bStatLoss >= pTarget->stats.bAgility) + { + bStatLoss = pTarget->stats.bAgility - 1; } if ( bStatLoss > 0 ) { - pTarget->stats.bStrength -= bStatLoss; + pTarget->stats.bAgility -= bStatLoss; + // SANDRO - added this for healing lost stats feature + pTarget->ubCriticalStatDamage[DAMAGED_STAT_AGILITY] += bStatLoss; if (pTarget->ubProfile != NO_PROFILE) { - gMercProfiles[ pTarget->ubProfile ].bStrength = pTarget->stats.bStrength; + gMercProfiles[ pTarget->ubProfile ].bAgility = pTarget->stats.bAgility; } if (pTarget->name[0] && pTarget->bVisible == TRUE) { // make stat RED for a while... - pTarget->timeChanges.uiChangeStrengthTime = GetJA2Clock(); - pTarget->usValueGoneUp &= ~( STRENGTH_INCREASE ); + pTarget->timeChanges.uiChangeAgilityTime = GetJA2Clock(); + pTarget->usValueGoneUp &= ~( AGIL_INCREASE ); if (bStatLoss == 1) { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_STRENGTH], pTarget->name ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_AGIL], pTarget->name ); } else { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_STRENGTH], pTarget->name, bStatLoss ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_AGIL], pTarget->name, bStatLoss ); } } } - } - break; - case AIM_SHOT_LEGS: - if (bStatLoss >= pTarget->stats.bAgility) - { - bStatLoss = pTarget->stats.bAgility - 1; - } - if ( bStatLoss > 0 ) - { - pTarget->stats.bAgility -= bStatLoss; + break; + } - if (pTarget->ubProfile != NO_PROFILE) - { - gMercProfiles[ pTarget->ubProfile ].bAgility = pTarget->stats.bAgility; - } + // SANDRO - Gain morale for inflicting critical hit if malicious character + if ( fMaliciousHit ) + { + HandleMoraleEvent( pFirer, MORALE_MALICIOUS_HIT, pFirer->sSectorX, pFirer->sSectorY, pFirer->bSectorZ ); + } - if (pTarget->name[0] && pTarget->bVisible == TRUE) - { - // make stat RED for a while... - pTarget->timeChanges.uiChangeAgilityTime = GetJA2Clock(); - pTarget->usValueGoneUp &= ~( AGIL_INCREASE ); - - if (bStatLoss == 1) - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_AGIL], pTarget->name ); - } - else - { - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_AGIL], pTarget->name, bStatLoss ); - } - } - } - break; + // SANDRO - new merc records - times stat damaged + if ( bStatLoss > 0 && pTarget->ubProfile != NO_PROFILE ) + gMercProfiles[ pTarget->ubProfile ].records.usTimesStatDamaged++; } } else if ( ubHitLocation == AIM_SHOT_HEAD && pTarget->bNumPelletsHitBy == 0 ) @@ -5095,6 +8935,10 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubHitLocat INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BOOLEAN fBladeAttack ) { + //////////////////////////////////////////// + // SANDRO - this all was somehow messed up + //////////////////////////////////////////// + INT32 iImpact, iFluke, iBonus; if (fBladeAttack) @@ -5113,29 +8957,55 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO iImpact = ( EffectiveExpLevel( pSoldier ) / 2); // 0 to 4 for level iImpact += EffectiveStrength( pSoldier ) / 5; // 0 to 20 for strength, adjusted by damage taken - // NB martial artists don't get a bonus for using brass knuckles! - if (pSoldier->usAttackingWeapon && !( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS ) ) ) + // NB martial artists don't get a bonus for using brass knuckles! - oh, they do in STOMP - SANDRO + if (pSoldier->usAttackingWeapon ) { - iImpact += GetDamage(&pSoldier->inv[HANDPOS]); - - if ( AM_A_ROBOT( pTarget ) ) + if ( gGameOptions.fNewTraitSystem ) { - iImpact /= 2; + iImpact += GetDamage(&pSoldier->inv[HANDPOS]); + + if ( AM_A_ROBOT( pTarget ) ) + { + iImpact /= 2; + } + } + else + { + if (!HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT )) + { + iImpact += GetDamage(&pSoldier->inv[HANDPOS]); + } + if ( AM_A_ROBOT( pTarget ) ) + { + iImpact /= 2; + } } } else { // base HTH damage - iImpact += 5; + // Enhanced Close Combat System - Slightly reduced for we can now attack to head for bigger damage + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + iImpact += 4; + } + else + { + iImpact += 5; + } + + // Add melee damage multiplier to HtH attacks as well - SANDRO + // actually I make the influence a little lesser, because to the blades and so, + // only the item impact is multiplied, not the level and strength bonus, but here it does + iImpact = (INT32)(iImpact * gGameExternalOptions.iMeleeDamageModifier / 100 ); + if ( AM_A_ROBOT( pTarget ) ) { iImpact = 0; } } - } - iFluke = PreRandom( 51 ) - 25; // +/-25% bonus due to random factors iBonus = iHitBy / 2; // up to 50% extra impact for accurate attacks @@ -5143,22 +9013,165 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO if (!fBladeAttack) { - // add bonuses for hand-to-hand and martial arts - if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS ) ) + if ( gGameOptions.fNewTraitSystem ) { - iImpact = iImpact * ( 100 + gbSkillTraitBonus[MARTIALARTS] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS ) ) / 100; - if (pSoldier->usAnimState == NINJA_SPINKICK) + if (!pSoldier->usAttackingWeapon || Item[pSoldier->inv[HANDPOS].usItem].brassknuckles) { - iImpact *= 2; + // add bonuses for martial arts + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + { + iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); + + // The Spinning kicks or aimed punch bonus - SANDRO + if (pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6))) + { + iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); // +75% damage per trait + } + } + } + else + { + // +30% damage of blunt weapons for melee character + if (HAS_SKILL_TRAIT( pSoldier, MELEE_NT )) + { + iImpact = (INT32)(iImpact * (100 + gSkillTraitValues.ubMEDamageBonusBlunt)/100); + + if (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6)) + { + iImpact = (INT32)(iImpact * (100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus) / 100); // 50% incresed damage if focused melee attack + } + } } } - if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND ) ) + else // original code { - // SPECIAL - give TRIPLE bonus for damage for hand-to-hand trait - // because the HTH bonus is half that of martial arts, and gets only 1x for to-hit bonus - iImpact = iImpact * ( 100 + 3 * gbSkillTraitBonus[HANDTOHAND] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND ) ) / 100; + // add bonuses for hand-to-hand and martial arts + if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) ) + { + iImpact = iImpact * ( 100 + gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ) ) / 100; + if (pSoldier->usAnimState == NINJA_SPINKICK) + { + iImpact *= 2; + } + } + if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) ) + { + // SPECIAL - give TRIPLE bonus for damage for hand-to-hand trait + // because the HTH bonus is half that of martial arts, and gets only 1x for to-hit bonus + iImpact = iImpact * ( 100 + 3 * gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND_OT ) ) / 100; + } + } + + // Enhanced Close Combat System - aiming at body parts makes difference + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + if (pSoldier->bAimShotLocation == AIM_SHOT_HEAD) + { + iImpact = (INT32)((iImpact * 125 / 100) + 0.5); // Punch or kick to head deal more damage (as bonus for -20% accuracy ) + } + else if ( pSoldier->bAimShotLocation == AIM_SHOT_LEGS ) + { + // Punch or kick to legs deal less damage but takes some AP per damage out of target adjusted by AP_MAXIMUM + // NO, better to make hit to legs have a much better chance to hit, while only 50% damage + iImpact = (INT32)((iImpact * 60 / 100) + 0.5); + //DeductPoints( pTarget, (APBPConstants[AP_MAXIMUM] / 10), 0 ); + } + else if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE) + { + iImpact = (INT32)((iImpact * 130 / 100) + 0.5); // 30% incresed damage to lying characters + } + + // Surprising attack deals more damage + if (pTarget->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget ) ) + { + iImpact = (INT32)((iImpact * 140 / 100) + 0.5); // 30% incresed damage on suprising attacks + } } } + // DAMAGE BONUS TO KNIFE ATTACK WITH MELEE SKILL + else + { + if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && ( gGameOptions.fNewTraitSystem )) + { + iImpact = (INT32)(iImpact * ( 100 + gSkillTraitValues.ubMEDamageBonusBlades ) / 100); // +30% damage + + if (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6)) + { + iImpact = (INT32)(iImpact * ( 100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus ) / 100); // 50% incresed damage if focused melee attack + } + } + // Enhanced Close Combat System + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE) + { + iImpact = (INT32)(iImpact * 125 / 100); // 40% incresed damage to lying characters + } + } + } + + // bonus damage for aggressive characters + if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) + { + iImpact = (INT32)((iImpact * 11 / 10) + 0.5); // +10% + } + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Damage resistance for Militia + if (!IsAutoResolveActive()) + { + if (pTarget->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.bGreenMilitiaDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.bRegularMilitiaDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.bVeteranMilitiaDamageResistance) /100); + // bonus for enemy too + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.sEnemyAdminDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.sEnemyRegularDamageResistance) /100); + else if (pTarget->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0) + iImpact -= ((iImpact * gGameExternalOptions.sEnemyEliteDamageResistance) /100); + + iImpact = max( 1, iImpact); + } + ////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - option to make special NPCs stronger - damage resistance + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( pTarget->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + iImpact -= (INT32)(iImpact * gGameExternalOptions.usSpecialNPCStronger / 200); + iImpact = max( 1, iImpact); + break; + } + } + //////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - Bodybuilding damage resistance + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pTarget, BODYBUILDING_NT ) ) + iImpact = max( 1, (INT32)(iImpact * (100 - gSkillTraitValues.ubBBDamageResistance) / 100)); + //////////////////////////////////////////////////////////////////////////////////// return( iImpact ); } @@ -5238,12 +9251,12 @@ void ShotMiss( UINT8 ubAttackerID, INT32 iBullet ) UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAimTime, UINT8 ubMode ) { - UINT16 usInHand; + UINT16 usInHand; UINT8 ubBandaged; - INT32 iAttRating, iDefRating; + INT32 iAttRating, iDefRating; INT32 iChance; - usInHand = pAttacker->usAttackingWeapon; + usInHand = pAttacker->usAttackingWeapon; if ( (usInHand != CREATURE_QUEEN_TENTACLES ) && (pDefender->stats.bLife < OKLIFE || pDefender->bBreath < OKBREATH) ) { @@ -5270,14 +9283,28 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi } } - // CALCULATE ATTACKER'S CLOSE COMBAT RATING (1-100) + // CALCULATE ATTACKER'S CLOSE COMBAT RATING (1-100) if (ubMode == HTH_MODE_STEAL) { - // this is more of a brute force strength-vs-strength check - iAttRating = ( EffectiveDexterity( pAttacker ) + // coordination, accuracy - EffectiveAgility( pAttacker ) + // speed & reflexes - 3 * pAttacker->stats.bStrength + // physical strength (TRIPLED!) - (10 * EffectiveExpLevel( pAttacker ) ) ); // experience, knowledge + /////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Enhanced Close Combat System - different calculation for stealing + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + // We need to be agile and dexterous + iAttRating = ( 2 * EffectiveDexterity( pAttacker ) + // coordination, accuracy * + 2 * EffectiveAgility( pAttacker ) + // speed & reflexes + pAttacker->stats.bStrength + // physical strength + (10 * EffectiveExpLevel( pAttacker ) ) ); // experience, knowledge + } + else + { + // this is more of a brute force strength-vs-strength check + iAttRating = ( EffectiveDexterity( pAttacker ) + // coordination, accuracy + EffectiveAgility( pAttacker ) + // speed & reflexes + 3 * pAttacker->stats.bStrength + // physical strength (TRIPLED!) + (10 * EffectiveExpLevel( pAttacker ) ) ); // experience, knowledge + } + /////////////////////////////////////////////////////////////////////////////////////// } else { @@ -5287,10 +9314,10 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi (10 * EffectiveExpLevel( pAttacker ) ) ); // experience, knowledge } - iAttRating /= 6; // convert from 6-600 to 1-100 + iAttRating /= 6; // convert from 6-600 to 1-100 - // psycho bonus - if ( pAttacker->ubProfile != NO_PROFILE && gMercProfiles[ pAttacker->ubProfile ].bPersonalityTrait == PSYCHO ) + // psycho bonus - only with old traits - SANDRO + if ( !( gGameOptions.fNewTraitSystem ) && pAttacker->ubProfile != NO_PROFILE && gMercProfiles[ pAttacker->ubProfile ].bDisability == PSYCHO ) { iAttRating += AIM_BONUS_PSYCHO; } @@ -5301,87 +9328,163 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi // modify for fatigue iAttRating -= GetSkillCheckPenaltyForFatigue( pAttacker, iAttRating ); - // if attacker spent some extra time aiming - if (ubAimTime) - { - // use only HALF of the normal aiming bonus for knife aiming. - // since there's no range penalty, the bonus is otherwise too generous - iAttRating += ((AIM_BONUS_PER_AP * ubAimTime) / 2); //bonus for aiming - } - - if (! (pAttacker->flags.uiStatusFlags & SOLDIER_PC) ) // if attacker is a computer AI controlled enemy + // if attacker spent some extra time aiming + if (ubAimTime) { - iAttRating += gbDiff[ DIFF_ENEMY_TO_HIT_MOD ][ SoldierDifficultyLevel( pAttacker ) ]; + // use only HALF of the normal aiming bonus for knife aiming. + // since there's no range penalty, the bonus is otherwise too generous + // SANDRO - Enhanced Close Combat System - Because you can only aim once, I've rather put here a flat number + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + iAttRating += 20; + else + iAttRating += ((AIM_BONUS_PER_AP * ubAimTime) / 2); //bonus for aiming } - // if attacker is being affected by gas - if ( pAttacker->flags.uiStatusFlags & SOLDIER_GASSED ) - iAttRating -= AIM_PENALTY_GASSED; - - // if attacker is being bandaged at the same time, his concentration is off - if (pAttacker->ubServiceCount > 0) - iAttRating -= AIM_PENALTY_GETTINGAID; - - // if attacker is still in shock - if (pAttacker->aiData.bShock) - iAttRating -= (pAttacker->aiData.bShock * AIM_PENALTY_PER_SHOCK); - -/* - // if the attacker is an A.I.M. mercenary - if (pAttacker->characternum < MAX_AIM_MERCS) // exclude Gus - iAttRating += AdjustChanceForProfile(pAttacker,pDefender); -*/ - - // If attacker injured, reduce chance accordingly (by up to 2/3rds) - if ((iAttRating > 0) && (pAttacker->stats.bLife < pAttacker->stats.bLifeMax)) - { - // if bandaged, give 1/2 of the bandaged life points back into equation - ubBandaged = pAttacker->stats.bLifeMax - pAttacker->stats.bLife - pAttacker->bBleeding; - - iAttRating -= (2 * iAttRating * (pAttacker->stats.bLifeMax - pAttacker->stats.bLife + (ubBandaged / 2))) / - (3 * pAttacker->stats.bLifeMax); - } - - // If attacker tired, reduce chance accordingly (by up to 1/2) - if ((iAttRating > 0) && (pAttacker->bBreath < 100)) - iAttRating -= (iAttRating * (100 - pAttacker->bBreath)) / 200; - - if (pAttacker->ubProfile != NO_PROFILE) + if (! (pAttacker->flags.uiStatusFlags & SOLDIER_PC) ) // if attacker is a computer AI controlled enemy { - if (ubMode == HTH_MODE_STAB) + iAttRating += gbDiff[ DIFF_ENEMY_TO_HIT_MOD ][ SoldierDifficultyLevel( pAttacker ) ]; + } + + // if attacker is being affected by gas + if ( pAttacker->flags.uiStatusFlags & SOLDIER_GASSED ) + iAttRating -= AIM_PENALTY_GASSED; + + // if attacker is being bandaged at the same time, his concentration is off + if (pAttacker->ubServiceCount > 0) + iAttRating -= AIM_PENALTY_GETTINGAID; + + // if attacker is still in shock + if (pAttacker->aiData.bShock) + iAttRating -= (pAttacker->aiData.bShock * AIM_PENALTY_PER_SHOCK); + + // if the attacker is an A.I.M. mercenary + //if (pAttacker->characternum < MAX_AIM_MERCS) // exclude Gus + // iAttRating += AdjustChanceForProfile(pAttacker,pDefender); + + // If attacker injured, reduce chance accordingly (by up to 2/3rds) + if ((iAttRating > 0) && (pAttacker->stats.bLife < pAttacker->stats.bLifeMax)) + { + // if bandaged, give 1/2 of the bandaged life points back into equation + ubBandaged = pAttacker->stats.bLifeMax - pAttacker->stats.bLife - pAttacker->bBleeding; + + iAttRating -= (2 * iAttRating * (pAttacker->stats.bLifeMax - pAttacker->stats.bLife + (ubBandaged / 2))) / (3 * pAttacker->stats.bLifeMax); + } + + // If attacker tired, reduce chance accordingly (by up to 1/2) + if ((iAttRating > 0) && (pAttacker->bBreath < 100)) + iAttRating -= (iAttRating * (100 - pAttacker->bBreath)) / 200; + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if (ubMode == HTH_MODE_STAB) + { + // add bonus for melee/knifing + if ( gGameOptions.fNewTraitSystem ) { - if (HAS_SKILL_TRAIT( pAttacker, KNIFING )) + iAttRating += gSkillTraitValues.bCtHModifierKnifeAttack; // Make melee attacks a little more problematic for untrained mercs + + if (HAS_SKILL_TRAIT( pAttacker, MELEE_NT )) { - iAttRating += gbSkillTraitBonus[KNIFING] * NUM_SKILL_TRAITS( pAttacker, KNIFING ); + iAttRating += gSkillTraitValues.ubMECtHBladesBonus; } } + else if (HAS_SKILL_TRAIT( pAttacker, KNIFING_OT )) + { + iAttRating += gbSkillTraitBonus[KNIFING_OT] * NUM_SKILL_TRAITS( pAttacker, KNIFING_OT ); + } + } + else + { + // add bonus for martial arts/melee + if ( gGameOptions.fNewTraitSystem ) + { + iAttRating += gSkillTraitValues.bCtHModifierHtHAttack; // Make HtH attacks a little more problematic for untrained mercs + + // bare hands - bonus for Martial arts + if (!pAttacker->usAttackingWeapon && HAS_SKILL_TRAIT( pAttacker, MARTIAL_ARTS_NT )) + { + iAttRating += gSkillTraitValues.ubMABonusCtHBareHands * NUM_SKILL_TRAITS( pAttacker, MARTIAL_ARTS_NT ); + } + // brass knuckles - bonus for Martial Arts (but a little lesser) + else if (Item[pAttacker->inv[HANDPOS].usItem].brassknuckles && HAS_SKILL_TRAIT( pAttacker, MARTIAL_ARTS_NT )) + { + iAttRating += gSkillTraitValues.ubMABonusCtHBrassKnuckles * NUM_SKILL_TRAITS( pAttacker, MARTIAL_ARTS_NT ); + } + // blunt melee weapons - bonus for Melee + else if (HAS_SKILL_TRAIT( pAttacker, MELEE_NT )) + { + iAttRating += gSkillTraitValues.ubMECtHBluntBonus; + } + } + else // original code + { + if (HAS_SKILL_TRAIT( pAttacker, MARTIALARTS_OT )) + { + iAttRating += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pAttacker, MARTIALARTS_OT ); + } + if ( HAS_SKILL_TRAIT( pAttacker, HANDTOHAND_OT ) ) + { + iAttRating += gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pAttacker, HANDTOHAND_OT ); + } + } + } + + // Added character traits influence + if ( gGameOptions.fNewTraitSystem && pAttacker->ubProfile != NO_PROFILE ) + { + // Sociable - better performance in groups + if ( gMercProfiles[ pAttacker->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pAttacker->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs > 2 ) + iAttRating += 5; + else if ( bNumMercs > 0 ) + iAttRating += 2; + } + // Loner - better performance when alone + else if ( gMercProfiles[ pAttacker->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pAttacker->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs == 0 ) + iAttRating += 5; + else if ( bNumMercs <= 1 ) + iAttRating += 2; + } + // Show-off - better performance if some babes around to impress + else if ( gMercProfiles[ pAttacker->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pAttacker->ubProfile, CHAR_TRAIT_SHOWOFF ); + if ( bNumMercs > 1 ) + iAttRating += 5; + else if ( bNumMercs > 0 ) + iAttRating += 2; + } + } + //////////////////////////////////////////////////////////////////////////////////// + + if (iAttRating < 1) + iAttRating = 1; + + + // CALCULATE DEFENDER'S CLOSE COMBAT RATING (0-100) + if (ubMode == HTH_MODE_STEAL) + { + // SANDRO - Enhanced Close Combat System - stealing defence based on dexterity and strength + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + iDefRating = ( EffectiveAgility( pDefender )) + // speed & reflexes + 2 * EffectiveDexterity( pDefender ) + // coordination, accuracy + 2 * pDefender->stats.bStrength + // physical strength + (10 * EffectiveExpLevel( pDefender ) ); // experience, knowledge + } else { - // add bonuses for hand-to-hand and martial arts - if (HAS_SKILL_TRAIT( pAttacker, MARTIALARTS )) - { - iAttRating += gbSkillTraitBonus[MARTIALARTS] * NUM_SKILL_TRAITS( pAttacker, MARTIALARTS ); - } - if ( HAS_SKILL_TRAIT( pAttacker, HANDTOHAND ) ) - { - iAttRating += gbSkillTraitBonus[HANDTOHAND] * NUM_SKILL_TRAITS( pAttacker, HANDTOHAND ); - } + iDefRating = (EffectiveAgility( pDefender )) + // speed & reflexes + EffectiveDexterity( pDefender ) + // coordination, accuracy + 3 * pDefender->stats.bStrength + // physical strength (TRIPLED!) + (10 * EffectiveExpLevel( pDefender ) ); // experience, knowledge } } - - - if (iAttRating < 1) - iAttRating = 1; - - - // CALCULATE DEFENDER'S CLOSE COMBAT RATING (0-100) - if (ubMode == HTH_MODE_STEAL) - { - iDefRating = (EffectiveAgility( pDefender )) + // speed & reflexes - EffectiveDexterity( pDefender ) + // coordination, accuracy - 3 * pDefender->stats.bStrength + // physical strength (TRIPLED!) - (10 * EffectiveExpLevel( pDefender ) ); // experience, knowledge - } else { iDefRating = (3 * EffectiveAgility( pDefender ) ) + // speed & reflexes (TRIPLED!) @@ -5390,7 +9493,7 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi (10 * EffectiveExpLevel( pDefender ) ); // experience, knowledge } - iDefRating /= 6; // convert from 6-600 to 1-100 + iDefRating /= 6; // convert from 6-600 to 1-100 // modify chance to dodge by morale iDefRating += GetMoraleModifier( pDefender ); @@ -5398,38 +9501,30 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi // modify for fatigue iDefRating -= GetSkillCheckPenaltyForFatigue( pDefender, iDefRating ); - // if attacker is being affected by gas - if ( pDefender->flags.uiStatusFlags & SOLDIER_GASSED ) - iDefRating -= AIM_PENALTY_GASSED; + // if attacker is being affected by gas + if ( pDefender->flags.uiStatusFlags & SOLDIER_GASSED ) + iDefRating -= AIM_PENALTY_GASSED; - // if defender is being bandaged at the same time, his concentration is off + // if defender is being bandaged at the same time, his concentration is off if (pDefender->ubServiceCount > 0) - iDefRating -= AIM_PENALTY_GETTINGAID; + iDefRating -= AIM_PENALTY_GETTINGAID; - // if defender is still in shock - if (pDefender->aiData.bShock) - iDefRating -= (pDefender->aiData.bShock * AIM_PENALTY_PER_SHOCK); + // if defender is still in shock + if (pDefender->aiData.bShock) + iDefRating -= (pDefender->aiData.bShock * AIM_PENALTY_PER_SHOCK); -/* - // if the defender is an A.I.M. mercenary - if (pDefender->characternum < MAX_AIM_MERCS) // exclude Gus - iDefRating += AdjustChanceForProfile(pDefender,pAttacker); -*/ + // If defender injured, reduce chance accordingly (by up to 2/3rds) + if ((iDefRating > 0) && (pDefender->stats.bLife < pDefender->stats.bLifeMax)) + { + // if bandaged, give 1/2 of the bandaged life points back into equation + ubBandaged = pDefender->stats.bLifeMax - pDefender->stats.bLife - pDefender->bBleeding; - // If defender injured, reduce chance accordingly (by up to 2/3rds) - if ((iDefRating > 0) && (pDefender->stats.bLife < pDefender->stats.bLifeMax)) - { - // if bandaged, give 1/2 of the bandaged life points back into equation - ubBandaged = pDefender->stats.bLifeMax - pDefender->stats.bLife - pDefender->bBleeding; + iDefRating -= (2 * iDefRating * (pDefender->stats.bLifeMax - pDefender->stats.bLife + (ubBandaged / 2))) / (3 * pDefender->stats.bLifeMax); + } - iDefRating -= (2 * iDefRating * (pDefender->stats.bLifeMax - pDefender->stats.bLife + (ubBandaged / 2))) / - (3 * pDefender->stats.bLifeMax); - - } - - // If defender tired, reduce chance accordingly (by up to 1/2) - if ((iDefRating > 0) && (pDefender->bBreath < 100)) - iDefRating -= (iDefRating * (100 - pDefender->bBreath)) / 200; + // If defender tired, reduce chance accordingly (by up to 1/2) + if ((iDefRating > 0) && (pDefender->bBreath < 100)) + iDefRating -= (iDefRating * (100 - pDefender->bBreath)) / 200; if ( usInHand == CREATURE_QUEEN_TENTACLES && pDefender->ubBodyType == LARVAE_MONSTER || pDefender->ubBodyType == INFANT_MONSTER ) { @@ -5463,71 +9558,175 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi } } - - if (pDefender->ubProfile != NO_PROFILE) + ////////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if (ubMode == HTH_MODE_STAB) { - if (ubMode == HTH_MODE_STAB) + if ( gGameOptions.fNewTraitSystem ) { - if (Item[pDefender->inv[HANDPOS].usItem].usItemClass == IC_BLADE) + iDefRating += gSkillTraitValues.bModifierDodgeKnifeChance; // Make HtH dodging a little more problematic for untrained mercs + + // Give bonus to dodge melee blade to MA and/or Melee trait - SANDRO + // Note that it is no longer dependant on what you have in hands + if (HAS_SKILL_TRAIT( pDefender, MARTIAL_ARTS_NT )) { - if ( HAS_SKILL_TRAIT( pDefender, KNIFING ) ) - { - // good with knives, got one, so we're good at parrying - iDefRating += gbSkillTraitBonus[KNIFING] * NUM_SKILL_TRAITS( pDefender, KNIFING ); - } - if (HAS_SKILL_TRAIT( pDefender, MARTIALARTS )) - { - // the knife gets in the way but we're still better than nobody - iDefRating += ( gbSkillTraitBonus[MARTIALARTS] * NUM_SKILL_TRAITS( pDefender, MARTIALARTS ) ) / 3; - } + iDefRating += ( gSkillTraitValues.ubMAChanceToDodgeMelee * NUM_SKILL_TRAITS( pDefender, MARTIAL_ARTS_NT ) ); } - else + if (HAS_SKILL_TRAIT( pDefender, MELEE_NT )) { - if ( HAS_SKILL_TRAIT( pDefender, KNIFING ) ) + iDefRating += gSkillTraitValues.ubMEDodgeBladesBonus; + + if (Item[pDefender->inv[HANDPOS].usItem].usItemClass == IC_BLADE) { - // good with knives, don't have one, but we know a bit about dodging - iDefRating += ( gbSkillTraitBonus[KNIFING] * NUM_SKILL_TRAITS( pDefender, KNIFING ) ) / 3; - } - if (HAS_SKILL_TRAIT( pDefender, MARTIALARTS )) - { - // bonus for dodging knives - iDefRating += ( gbSkillTraitBonus[MARTIALARTS] * NUM_SKILL_TRAITS( pDefender, MARTIALARTS ) )/ 2; + // knife-to-knife combat, we are the best around at this + iDefRating += gSkillTraitValues.ubMECtDBladesOnTopWithBladeInHands; } } } else - { // punch/hand-to-hand/martial arts attack/steal - if (Item[pDefender->inv[HANDPOS].usItem].usItemClass == IC_BLADE && ubMode != HTH_MODE_STEAL) + { + if ( HAS_SKILL_TRAIT( pDefender, KNIFING_OT ) ) { - if (HAS_SKILL_TRAIT( pDefender, KNIFING )) + if (Item[pDefender->inv[HANDPOS].usItem].usItemClass == IC_BLADE) { - // with our knife, we get some bonus at defending from HTH attacks - iDefRating += ( gbSkillTraitBonus[KNIFING] * NUM_SKILL_TRAITS( pDefender, KNIFING ) ) / 2; + // good with knives, got one, so we're good at parrying + iDefRating += gbSkillTraitBonus[KNIFING_OT] * NUM_SKILL_TRAITS( pDefender, KNIFING_OT ); + } + else + { + // good with knives, don't have one, but we know a bit about dodging + iDefRating += ( gbSkillTraitBonus[KNIFING_OT] * NUM_SKILL_TRAITS( pDefender, KNIFING_OT ) ) / 3; + } + } + if (HAS_SKILL_TRAIT( pDefender, MARTIALARTS_OT )) + { + // bonus for dodging knives + iDefRating += ( gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pDefender, MARTIALARTS_OT ) )/ 2; + } + } + } + else + { // punch/hand-to-hand/martial arts attack/steal + if ( gGameOptions.fNewTraitSystem ) + { + iDefRating += gSkillTraitValues.bModifierDodgeHtHChance; // Make HtH dodging a little more problematic for untrained mercs + + if ( !pAttacker->usAttackingWeapon || Item[pAttacker->inv[HANDPOS].usItem].brassknuckles ) + { + if (HAS_SKILL_TRAIT( pDefender, MARTIAL_ARTS_NT )) + { + // Bonus to dodge to MA trait - SANDRO + // Note that it no longer depends on whatever having in hands, because before + // you would have unlogicaly lesser chance to dodge with a knife in hands than with a gun + iDefRating += gSkillTraitValues.ubMAChanceToDodgeHtH * NUM_SKILL_TRAITS( pDefender, MARTIAL_ARTS_NT ); // +35% per trait + + if ( !pDefender->inv[HANDPOS].exists() ) + { + iDefRating += ( gSkillTraitValues.ubMAOnTopCTDHtHBareHanded * NUM_SKILL_TRAITS( pDefender, MARTIAL_ARTS_NT ) ); + } + else if ( Item[pDefender->inv[HANDPOS].usItem].brassknuckles ) + { + iDefRating += ( gSkillTraitValues.ubMAOnTopCTDHtHBrassKnuckles * NUM_SKILL_TRAITS( pDefender, MARTIAL_ARTS_NT ) ); + } } } else { - if (HAS_SKILL_TRAIT( pDefender, MARTIALARTS )) + if (HAS_SKILL_TRAIT( pDefender, MARTIAL_ARTS_NT )) { - iDefRating += gbSkillTraitBonus[MARTIALARTS] * NUM_SKILL_TRAITS( pDefender, MARTIALARTS ); + iDefRating += gSkillTraitValues.ubMAChanceToDodgeMelee * NUM_SKILL_TRAITS( pDefender, MARTIAL_ARTS_NT ); // +35% per trait } - if (HAS_SKILL_TRAIT( pDefender, HANDTOHAND )) + if (HAS_SKILL_TRAIT( pDefender, MELEE_NT )) { - iDefRating += gbSkillTraitBonus[HANDTOHAND] * NUM_SKILL_TRAITS( pDefender, HANDTOHAND ); + iDefRating += gSkillTraitValues.ubMEDodgeBluntBonus; + + if (Item[pDefender->inv[HANDPOS].usItem].usItemClass == IC_BLADE) + { + // bonus, when we have our knife in hands + iDefRating += gSkillTraitValues.ubMECtDBluntOnTopWithBladeInHands; + } } } } + else + { + // SANDRO - this is so idiotic, it actiually means, that martial artists and HtH + // soldiers do not get their dodging bonus if they have a knife in hands, but do + // have it if having anything else! I just had to change it, for it is a bug more + // than an intended feature + if (HAS_SKILL_TRAIT( pDefender, KNIFING_OT ) && Item[pDefender->inv[HANDPOS].usItem].usItemClass == IC_BLADE && ubMode != HTH_MODE_STEAL) + { + // with our knife, we get some bonus at defending from HTH attacks + iDefRating += ( gbSkillTraitBonus[KNIFING_OT] * NUM_SKILL_TRAITS( pDefender, KNIFING_OT ) ) / 2; + + } + if (HAS_SKILL_TRAIT( pDefender, MARTIALARTS_OT )) + { + // now the bonus depends on what we have in hands + if ( pDefender->inv[HANDPOS].exists() ) + { + // if we have something in hands, the chance is reduced + iDefRating += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pDefender, MARTIALARTS_OT )*2/3; + } + else + { + // else we are unbeatable + iDefRating += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pDefender, MARTIALARTS_OT ); + } + } + if (HAS_SKILL_TRAIT( pDefender, HANDTOHAND_OT )) + { + iDefRating += gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pDefender, HANDTOHAND_OT ); + } + } } - if (iDefRating < 1) - iDefRating = 1; + // Added character traits influence + if ( gGameOptions.fNewTraitSystem && pDefender->ubProfile != NO_PROFILE ) + { + // Sociable - better performance in groups + if ( gMercProfiles[ pDefender->ubProfile ].bCharacterTrait == CHAR_TRAIT_SOCIABLE ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pDefender->ubProfile, CHAR_TRAIT_SOCIABLE ); + if ( bNumMercs > 2 ) + iDefRating += 5; + else if ( bNumMercs > 0 ) + iDefRating += 2; + } + // Loner - better performance when alone + else if ( gMercProfiles[ pDefender->ubProfile ].bCharacterTrait == CHAR_TRAIT_LONER ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pDefender->ubProfile, CHAR_TRAIT_LONER ); + if ( bNumMercs == 0 ) + iDefRating += 5; + else if ( bNumMercs <= 1 ) + iDefRating += 2; + } + // Show-off - better performance if some babes around to impress + else if ( gMercProfiles[ pDefender->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) + { + INT8 bNumMercs = CheckMercsNearForCharTraits( pDefender->ubProfile, CHAR_TRAIT_SHOWOFF ); + if ( bNumMercs > 1 ) + iDefRating += 5; + else if ( bNumMercs > 0 ) + iDefRating += 2; + } + else if ( gMercProfiles[ pDefender->ubProfile ].bCharacterTrait == CHAR_TRAIT_DAUNTLESS ) + { + iDefRating -= 5; + } + } + ////////////////////////////////////////////////////////////////////////////////////////////////////// + + if (iDefRating < 1) + iDefRating = 1; - //NumMessage("CalcChanceToStab - Attacker's Rating = ",iAttRating); - //NumMessage("CalcChanceToStab - Defender's Rating = ",iDefRating); + //NumMessage("CalcChanceToStab - Attacker's Rating = ",iAttRating); + //NumMessage("CalcChanceToStab - Defender's Rating = ",iDefRating); - // calculate chance to hit by comparing the 2 opponent's ratings -// iChance = (100 * iAttRating) / (iAttRating + iDefRating); + // calculate chance to hit by comparing the 2 opponent's ratings + // iChance = (100 * iAttRating) / (iAttRating + iDefRating); if (ubMode == HTH_MODE_STEAL) @@ -5541,14 +9740,53 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi // Changed from DG by CJC to give higher chances of hitting with a stab or punch iChance = 67 + (iAttRating - iDefRating) / 3; - if ( pAttacker->bAimShotLocation == AIM_SHOT_HEAD ) + // SANDRO - Enhanced Close Combat System - chances to hit for punches aimed at body parts + if (gGameExternalOptions.fEnhancedCloseCombatSystem) { - // make this harder! - iChance -= 20; - } + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pAttacker, MARTIAL_ARTS_NT ) && + ((pAttacker->usAnimState == NINJA_SPINKICK) || (pAttacker->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6))) ) + { + // spinning kick or focused punch modifier + iChance += gSkillTraitValues.bMAAimedPunchCtHModifier * NUM_SKILL_TRAITS( pAttacker, MARTIAL_ARTS_NT ); + } + if ( pAttacker->bAimShotLocation == AIM_SHOT_HEAD ) + { + // Harder to hit head (but higher damage there) + iChance -= 20; + } + else if( pAttacker->bAimShotLocation == AIM_SHOT_LEGS ) + { + // easy to hit legs (but low damage there) + iChance += 25; + } + } + else + { + if ( pAttacker->bAimShotLocation == AIM_SHOT_HEAD ) + { + // make this harder! + iChance -= 20; + } + } } + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Bonus CtH for Militia + if (pAttacker->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sGreenMilitiaCtHBonusPercent) /100); + else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sRegularMilitiaCtHBonusPercent) /100); + else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); + // bonus for enemy + else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); + else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); + else if (pAttacker->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyEliteCtHBonusPercent) /100); + ////////////////////////////////////////////////////////////////////////////////////// // MAKE SURE CHANCE TO HIT IS WITHIN DEFINED LIMITS // HEADROCK: I urinate on your Defined Limits! Power Rangers, Externalize! @@ -5764,7 +10002,7 @@ INT32 CalcMaxTossRange( SOLDIERTYPE * pSoldier, UINT16 usItem, BOOLEAN fArmed ) if ( EXPLOSIVE_GUN( usItem ) ) { // oops! return value in weapons table - return( Weapon[ usItem ].usRange / CELL_X_SIZE ); + return( GetModifiedGunRange(usItem) / CELL_X_SIZE ); } // if item's fired mechanically @@ -5779,7 +10017,7 @@ INT32 CalcMaxTossRange( SOLDIERTYPE * pSoldier, UINT16 usItem, BOOLEAN fArmed ) if ( Item[ usItem ].usItemClass == IC_LAUNCHER && fArmed ) { // this function returns range in tiles so, stupidly, we have to divide by 10 here - iRange = Weapon[usItem].usRange / CELL_X_SIZE; + iRange = GetModifiedGunRange(usItem) / CELL_X_SIZE; } else { @@ -5807,11 +10045,30 @@ INT32 CalcMaxTossRange( SOLDIERTYPE * pSoldier, UINT16 usItem, BOOLEAN fArmed ) // adjust for thrower's remaining breath (lose up to 1/2 of range) iRange -= (iRange * (100 - pSoldier->bBreath)) / 200; - if ( HAS_SKILL_TRAIT( pSoldier, THROWING ) ) + //////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if( gGameOptions.fNewTraitSystem ) { - // better max range due to expertise - iRange = iRange * (100 + gbSkillTraitBonus[THROWING] * NUM_SKILL_TRAITS( pSoldier, THROWING ) ) / 100; + if ( (Item[ usItem ].usItemClass == IC_THROWING_KNIFE) && (HAS_SKILL_TRAIT( pSoldier, THROWING_NT )) ) + { + // better max range due to expertise + iRange += ((iRange * gSkillTraitValues.ubTHBladesMaxRange ) / 100); + } + else if ( (Item[ usItem ].usItemClass == IC_GRENADE) && (HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT )) ) + { + // better max range due to expertise + iRange += ((iRange * gSkillTraitValues.ubDEMaxRangeToThrowGrenades) / 100); + } } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, THROWING_OT ) ) + { + // better max range due to expertise + iRange = iRange * (100 + gbSkillTraitBonus[THROWING_OT] * NUM_SKILL_TRAITS( pSoldier, THROWING_OT ) ) / 100; + } + } + //////////////////////////////////////////////////////////////////////////////////////////////// // Adjust for thrower's stance if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight < ANIM_STAND) @@ -5863,11 +10120,32 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi // PHYSICALLY THROWN arced projectile (ie. grenade) // for lack of anything better, base throwing accuracy on dex & marskmanship iChance = ( EffectiveDexterity( pSoldier ) + EffectiveMarksmanship( pSoldier ) ) / 2; - // throwing trait helps out - if ( HAS_SKILL_TRAIT( pSoldier, THROWING ) ) + //////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if ( gGameOptions.fNewTraitSystem ) { - iChance += gbSkillTraitBonus[THROWING] * NUM_SKILL_TRAITS( pSoldier, THROWING ); + // throwing trait helps out on grenades and knives + if ( Item[ usHandItem ].usItemClass == IC_THROWING_KNIFE ) + { + iChance += gSkillTraitValues.bCtHModifierThrowingKnives; // -15% for untrained mercs + + if ( HAS_SKILL_TRAIT( pSoldier, THROWING_NT ) ) + iChance += (gSkillTraitValues.ubTHBladesCtHBonus + (gSkillTraitValues.ubTHBladesCtHBonusPerClick * pSoldier->aiData.bAimTime) ); + } + else + { + iChance += gSkillTraitValues.bCtHModifierThrowingGrenades; // -10% for untrained mercs + + if ( HAS_SKILL_TRAIT( pSoldier, DEMOLITIONS_NT ) ) + iChance += gSkillTraitValues.ubDECtHWhenThrowingGrenades; // +30% chance + } } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, THROWING_OT ) ) + iChance += gbSkillTraitBonus[THROWING_OT] * NUM_SKILL_TRAITS( pSoldier, THROWING_OT ); + } + //////////////////////////////////////////////////////////////////////////////////////////////// } else { @@ -5875,24 +10153,68 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi // MECHANICALLY FIRED arced projectile (ie. mortar), need brains & know-how iChance = ( EffectiveDexterity( pSoldier ) + EffectiveMarksmanship( pSoldier ) + EffectiveWisdom( pSoldier ) + pSoldier->stats.bExpLevel ) / 4; - // heavy weapons trait helps out - if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPS )) + //////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if ( gGameOptions.fNewTraitSystem ) { - iChance += gbSkillTraitBonus[HEAVY_WEAPS] * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS ); + if ( Item[ usHandItem ].mortar ) + { + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT )) + iChance += (gSkillTraitValues.sCtHModifierMortar * max( 0, ((100 - gSkillTraitValues.ubHWMortarCtHPenaltyReduction * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ))/100))); + else + iChance += gSkillTraitValues.sCtHModifierMortar; // -60% for untrained mercs + } + else + { + iChance += gSkillTraitValues.bCtHModifierGrenadeLaunchers; // -25% for untrained mercs + + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPONS_NT )) + iChance += gSkillTraitValues.ubHWBonusCtHGrenadeLaunchers * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPONS_NT ); // +25% per trait - SANDRO + } } + else + { + // This feature is available only if not having new traits on - SANDRO + // Also.. this was moved here before the Heavy Weapons bonus + // HEADROCK HAM 3.2: External divisor for CTH with mortars, now that they are more prevalent in the battlefield. + if ( Item[ usHandItem ].mortar ) + { + iChance = iChance / gGameExternalOptions.ubMortarCTHDivisor; + } + + // heavy weapons trait helps out + if (HAS_SKILL_TRAIT( pSoldier, HEAVY_WEAPS_OT )) + { + iChance += gbSkillTraitBonus[HEAVY_WEAPS_OT] * NUM_SKILL_TRAITS( pSoldier, HEAVY_WEAPS_OT ); + } + } + //////////////////////////////////////////////////////////////////////////////////////////////// } - if ( pSoldier->bDoBurst ) + if ( UsingNewCTHSystem() == false && pSoldier->bDoBurst ) { int iPenalty = ( Weapon[usHandItem].ubBurstPenalty - GetBurstToHitBonus(&pSoldier->inv[HANDPOS], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) ) * (pSoldier->bDoBurst - 1); // halve the penalty for people with the autofire trait - if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS ) ) + ///////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if ( gGameOptions.fNewTraitSystem ) { - iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS ); + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPONS_NT ) ) + { + iPenalty = max(0, ((iPenalty * (100 - gSkillTraitValues.ubAWAutoFirePenaltyReduction * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPONS_NT )))/100)); + } } + else + { + if ( HAS_SKILL_TRAIT( pSoldier, AUTO_WEAPS_OT ) ) + { + iPenalty /= 2 * NUM_SKILL_TRAITS( pSoldier, AUTO_WEAPS_OT ); + } + } + ///////////////////////////////////////////////////////////////////////// iChance -= iPenalty; } @@ -6020,10 +10342,28 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi iChance = (iChance * WEAPON_STATUS_MOD(pSoldier->inv[HANDPOS][0]->data.objectStatus)) / 100; // HEADROCK HAM 3.2: External divisor for CTH with mortars, now that they are more prevalent in the battlefield. - if ( Item[ usHandItem ].mortar ) - { - iChance = iChance / gGameExternalOptions.ubMortarCTHDivisor; - } + // SANDRO - moved this up + //if ( Item[ usHandItem ].mortar ) + //{ + // iChance = iChance / gGameExternalOptions.ubMortarCTHDivisor; + //} + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Bonus CtH for Militia + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sGreenMilitiaCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sRegularMilitiaCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sVeteranMilitiaCtHBonusPercent) /100); + // bonus for enemy + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyAdminCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyRegularCtHBonusPercent) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteCtHBonusPercent != 0) + iChance += ((iChance * gGameExternalOptions.sEnemyEliteCtHBonusPercent) /100); + ////////////////////////////////////////////////////////////////////////////////////// // What's with all these defined limits? Let's think out of the box for a minute, shall we? // HEADROCK (HAM): externalized, effective immediately. @@ -6115,8 +10455,10 @@ void DishoutQueenSwipeDamage( SOLDIERTYPE *pQueenSoldier ) // ATE: Ok, lets check for some basic things here! if ( pSoldier->stats.bLife >= OKLIFE && !TileIsOutOfBounds(pSoldier->sGridNo) && pSoldier->bActive && pSoldier->bInSector ) { + UINT16 usRange = GetModifiedGunRange(CREATURE_QUEEN_TENTACLES); + // Get Pyth spaces away.... - if ( GetRangeInCellCoordsFromGridNoDiff( pQueenSoldier->sGridNo, pSoldier->sGridNo ) <= Weapon[ CREATURE_QUEEN_TENTACLES].usRange ) + if ( GetRangeInCellCoordsFromGridNoDiff( pQueenSoldier->sGridNo, pSoldier->sGridNo ) <= usRange ) { // get direction bDir = (INT8)GetDirectionFromGridNo( pSoldier->sGridNo, pQueenSoldier ); @@ -6135,6 +10477,10 @@ void DishoutQueenSwipeDamage( SOLDIERTYPE *pQueenSoldier ) { // Hit! iImpact = HTHImpact( pQueenSoldier, pSoldier, iHitBy, TRUE ); + // SANDRO - new merc records - well, crepitus queen's tentackles are brutal, count them as "stabbed" + if ( pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesWoundedStabbed++; + pSoldier->EVENT_SoldierGotHit( CREATURE_QUEEN_TENTACLES, (INT16) iImpact, (INT16) iImpact, gOppositeDirection[ bDir ], 50, pQueenSoldier->ubID, 0, ANIM_CROUCH, 0, 0 ); } } @@ -6181,27 +10527,66 @@ UINT8 GetDamage ( OBJECTTYPE *pObj ) if ( Item[pObj->usItem].usItemClass == IC_BLADE || Item[pObj->usItem].usItemClass == IC_PUNCH || Item[pObj->usItem].usItemClass == IC_TENTACLES ) { + UINT8 ubDamage; // HEADROCK HAM 3.6: Can now take a negative modifier - UINT8 ubDamage = (UINT8)GetModifiedMeleeDamage( Weapon[ pObj->usItem ].ubImpact ); - ubDamage += GetMeleeDamageBonus(pObj); - //return min(255, (UINT8)( (ubDamage) + ( (double)ubDamage / 100) * gGameExternalOptions.ubMeleeDamageMultiplier ) ); + if(UsingNewCTHSystem() == true) + { + ubDamage = Weapon[ pObj->usItem ].ubImpact; + ubDamage += GetMeleeDamageBonus(pObj); + ubDamage = (UINT8)GetModifiedMeleeDamage( ubDamage ); + } + else + { + ubDamage = (UINT8)GetModifiedMeleeDamage( Weapon[ pObj->usItem ].ubImpact ); + ubDamage += GetMeleeDamageBonus(pObj); + } + //return min(255, (UINT8)( (ubDamage) + ( (double)ubDamage / 100) * gGameExternalOptions.iMeleeDamageModifier ) ); return min(255, (UINT8)ubDamage); } else { + UINT8 ubDamage; // HEADROCK HAM 3.6: Can now take a negative modifier - UINT8 ubDamage = (UINT8)GetModifiedMeleeDamage( Weapon[ pObj->usItem ].ubImpact ); - - // WTF? Why do only small weapons get their damage bonus?! - if (FitsInSmallPocket(pObj) == true) + if(UsingNewCTHSystem() == true) { - ubDamage += GetDamageBonus(pObj); + ubDamage = Weapon[ pObj->usItem ].ubImpact; + // HEADROCK HAM 4: I've decided to remove this condition. It makes no friggin sense. + //if (FitsInSmallPocket(pObj) == true) + //{ + ubDamage += GetDamageBonus(pObj); + //} + ubDamage = (UINT8)GetModifiedGunDamage( ubDamage ); + } + else + { + ubDamage = (UINT8)GetModifiedGunDamage( Weapon[ pObj->usItem ].ubImpact ); + + // WTF? Why do only small weapons get their damage bonus?! + if (FitsInSmallPocket(pObj) == true) + { + ubDamage += GetDamageBonus(pObj); + } } return min(255, (UINT8)ubDamage ); } } - +// HEADROCK HAM 4: Same function as above, but without modifiers from attached items. +UINT8 GetBasicDamage ( OBJECTTYPE *pObj ) +{ + if ( Item[pObj->usItem].usItemClass == IC_BLADE || Item[pObj->usItem].usItemClass == IC_PUNCH || Item[pObj->usItem].usItemClass == IC_TENTACLES ) + { + // HEADROCK HAM 3.6: Can now take a negative modifier + UINT8 ubDamage = (UINT8)GetModifiedMeleeDamage( Weapon[ pObj->usItem ].ubImpact ); + return ubDamage; + } + else + { + // HEADROCK HAM 3.6: Can now take a negative modifier + UINT8 ubDamage = (UINT8)GetModifiedGunDamage( Weapon[ pObj->usItem ].ubImpact ); + return ubDamage; + } +} UINT8 GetShotsPerBurst( OBJECTTYPE *pObj ) { @@ -6232,6 +10617,42 @@ UINT8 GetAutoPenalty( OBJECTTYPE *pObj, BOOLEAN fProneStance ) return Weapon[ pObj->usItem ].AutoPenalty - bns; } + +// HEADROCK HAM 4: This determines whether the previous bullet in a volley was a tracer bullet. +BOOLEAN WasPrevBulletATracer( SOLDIERTYPE *pSoldier, OBJECTTYPE *pWeapon ) +{ + + if (!AmmoTypes[ (*pWeapon)[0]->data.gun.ubGunAmmoType ].tracerEffect) + { + // Not a tracer magazine + return (FALSE); + } + if (pSoldier->bDoBurst == 0) + { + // No volley? Tracers are irrelevant + return (FALSE); + } + + if (gGameExternalOptions.ubRealisticTracers == 0 || gGameExternalOptions.ubNumBulletsPerTracer == 1) + { + // All bullets are tracers anyway. + return (TRUE); + } + + UINT16 usShotsLeft = (*pWeapon)[0]->data.gun.ubGunShotsLeft; + UINT16 usMagSize = GetMagSize(pWeapon); + UINT16 usBulletsFired = usMagSize-usShotsLeft; + UINT16 usBulletsSinceTracer = (usBulletsFired+1)%gGameExternalOptions.ubNumBulletsPerTracer; + if (usBulletsSinceTracer == 1) + { + return (TRUE); + } + else + { + return (FALSE); + } + } + UINT8 GetAutofireShotsPerFiveAPs( OBJECTTYPE *pObj ) { // DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("GetAutofireShotsPerFiveAPs")); @@ -6239,18 +10660,34 @@ UINT8 GetAutofireShotsPerFiveAPs( OBJECTTYPE *pObj ) // HEADROCK HAM B2.6: Added overall modifier if (Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP > 0) { - return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.bAutofireBulletsPer5APModifier), 0); + // WANNE: Fix by Headrock + // Weapons shouldn't ever lose their Bp5AP due to this modifier. + return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.bAutofireBulletsPer5APModifier), 1); + + //return __max((Weapon[ pObj->usItem ].bAutofireShotsPerFiveAP + gGameExternalOptions.bAutofireBulletsPer5APModifier), 0); } else return 0; } -UINT16 GetMagSize( OBJECTTYPE *pObj ) +UINT16 GetMagSize( OBJECTTYPE *pObj, UINT8 subObject ) { // DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("GetMagSize")); - return Weapon[ pObj->usItem ].ubMagSize + GetMagSizeBonus(pObj); + return Weapon[ pObj->usItem ].ubMagSize + GetMagSizeBonus(pObj, subObject); +} +UINT16 GetExpMagSize( OBJECTTYPE *pObj ) +{ +// DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("GetMagSize")); + UINT8 magSize = 0; + if(Item[pObj->usItem].usItemClass & IC_EXPLOSV) + magSize = Explosive[Item[pObj->usItem].ubClassIndex].ubMagSize; + else + magSize = Weapon[pObj->usItem].ubMagSize; + + //return Weapon[ pObj->usItem ].ubMagSize + GetMagSizeBonus(pObj); + return magSize; } // HEADROCK HAM 3.3: Function to get a weapon's current ammotype. @@ -6265,6 +10702,10 @@ bool WeaponReady(SOLDIERTYPE * pSoldier) if ( AM_A_ROBOT( pSoldier) ) return true; #endif + if (gbForceWeaponNotReady) + return false; + if (gbForceWeaponReady) + return true; if ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) ) return true; @@ -6317,7 +10758,7 @@ void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ) } // Is this Soldier a psycho? - if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == PSYCHO ) + if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bDisability == PSYCHO ) { fPsycho = TRUE; } @@ -6417,3 +10858,48 @@ void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ) return; } + +// HEADROCK HAM 4: Calculate the ratio between current Mag Factor and Target Factor. Used for the CTH bars. +void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTime ) +{ + OBJECTTYPE *pWeapon = &(pSoldier->inv[pSoldier->ubAttackingHand]); + + FLOAT iActualMagFactor = 0; + FLOAT iHighestMagFactor = 0; + FLOAT iScopeFactor = 0; + FLOAT iProjectionFactor = 0; + FLOAT iTargetMagFactor = 0; + BOOLEAN isScopeBetter = FALSE; + + // Calculate the optimal magnification that would be required for the target's current distance. + iTargetMagFactor = d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE; + + if (bAimTime > 0) + { + iScopeFactor = GetBestScopeMagnificationFactor( pWeapon, (UINT32)d2DDistance ); + // Set a display variable + gCTHDisplay.ScopeMagFactor = iScopeFactor; + + iScopeFactor = __min(iScopeFactor, iTargetMagFactor); + iProjectionFactor = GetProjectionFactor( pWeapon ); + + // Set a display variable + gCTHDisplay.ProjectionFactor = iProjectionFactor; + + // The final factor is the largest of the two. + + if (iScopeFactor > iProjectionFactor) + isScopeBetter=TRUE; + + iHighestMagFactor = __max( iScopeFactor, iProjectionFactor ); + } + else + { + gCTHDisplay.ScopeMagFactor = 1.0; + gCTHDisplay.ProjectionFactor = 1.0; + iHighestMagFactor = 1.0; + } + + gCTHDisplay.FinalMagFactor = iHighestMagFactor; + +} diff --git a/Tactical/Weapons.h b/Tactical/Weapons.h index d1d57b6a..98443c8f 100644 --- a/Tactical/Weapons.h +++ b/Tactical/Weapons.h @@ -250,7 +250,7 @@ enum #define AIM_PENALTY_TARGET_PRONE 40 #define AIM_PENALTY_BLIND 80 #define AIM_PENALTY_FIRING_UP 25 -#define HIGH_POWER_SCOPE 14 +//#define HIGH_POWER_SCOPE 14 //Externalized #define MAX_WEAPON_NAME_LENGTH 20 @@ -268,7 +268,8 @@ typedef struct UINT8 ubBulletSpeed; // bullet's travelling speed UINT8 ubImpact; // weapon's max damage impact (size & speed) UINT8 ubDeadliness; // comparative ratings of guns - INT8 bAccuracy; // accuracy or penalty + INT8 bAccuracy; // accuracy or penalty used by OCTH + INT8 nAccuracy; // accuracy or penalty used by NCTH UINT8 ubMagSize; UINT16 usRange; UINT16 usReloadDelay; @@ -294,6 +295,17 @@ typedef struct INT16 sAniDelay; // Lesh: for burst animation delay UINT8 APsToReloadManually; UINT16 ManualReloadSound; + BOOLEAN EasyUnjam; // Guns where each bullet has its own chamber (like revolvers) are easyer to unjam + + INT8 bRecoilX; // HEADROCK HAM 4: Recoil now measured in points of muzzle deviation X and Y. + INT8 bRecoilY; // Positive values indicated upwards (Y) and rightwards (X). Negatives are down (-Y) and left (-X). + // Note that each value is an array. Each item in the array determines recoil + // for a different bullet in the sequence. Not all values have to be filled, + // but the last filled value will determine the recoil for longer volleys. + UINT8 ubRecoilDelay; + + UINT8 ubAimLevels; // HEADROCK HAM 4: Dictates how many aiming levels this gun supports. If 0, the program + // chooses automatically based on the type of gun (see AllowedAimingLevels() ). } WEAPONTYPE; typedef struct @@ -326,6 +338,7 @@ typedef struct UINT32 uiIndex; UINT16 ubDuration; UINT16 ubStartRadius; + UINT8 ubMagSize; } EXPLOSIVETYPE; //GLOBALS @@ -340,6 +353,9 @@ extern AMMOTYPE AmmoTypes[MAXITEMS]; extern BOOLEAN ReadInWeaponStats(STR fileName); extern BOOLEAN WriteWeaponStats(); +extern bool gbForceWeaponNotReady; +extern bool gbForceWeaponReady; + extern INT32 EffectiveArmour( OBJECTTYPE * pObj ); extern INT8 ArmourVersusExplosivesPercent( SOLDIERTYPE * pSoldier ); extern BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ); @@ -350,6 +366,7 @@ extern INT32 BulletImpact( SOLDIERTYPE *pFirer, SOLDIERTYPE * pTarget, UINT8 ubH extern BOOLEAN InRange( SOLDIERTYPE *pSoldier, INT32 sGridNo ); extern void ShotMiss( UINT8 ubAttackerID, INT32 iBullet ); extern UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ); +extern UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ); extern UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ); extern UINT32 CalcChanceToPunch(SOLDIERTYPE *pAttacker, SOLDIERTYPE * pDefender, INT16 ubAimTime); extern UINT32 CalcChanceToStab(SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAimTime); @@ -382,15 +399,18 @@ void DishoutQueenSwipeDamage( SOLDIERTYPE *pQueenSoldier ); INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BOOLEAN fBladeAttack ); -UINT16 GunRange( OBJECTTYPE * pObj ); +UINT16 GunRange( OBJECTTYPE * pObj, SOLDIERTYPE * pSoldier ); // SANDRO - added argument BOOLEAN IsWeapon ( UINT16 itemIndex ); UINT8 GetDamage ( OBJECTTYPE *pObj ); +// HEADROCK HAM 4: Same function as above, but without modifiers from attached items. +UINT8 GetBasicDamage ( OBJECTTYPE *pObj ); UINT8 GetAutofireShotsPerFiveAPs( OBJECTTYPE *pObj ); UINT8 GetBaseAutoFireCost( OBJECTTYPE *pObj ); UINT8 GetBurstPenalty( OBJECTTYPE *pObj, BOOLEAN fProneStance = FALSE ); UINT8 GetAutoPenalty( OBJECTTYPE *pObj, BOOLEAN fProneStance = FALSE ); UINT8 GetShotsPerBurst( OBJECTTYPE *pObj ); -UINT16 GetMagSize( OBJECTTYPE *pObj ); +UINT16 GetMagSize( OBJECTTYPE *pObj, UINT8 subObject = 0 ); +UINT16 GetExpMagSize( OBJECTTYPE *pObj ); UINT8 GetAmmoType( OBJECTTYPE *pObj ); bool WeaponReady(SOLDIERTYPE * pSoldier); INT8 GetAPsToReload( OBJECTTYPE *pObj ); @@ -400,5 +420,9 @@ INT8 GetAPsToReload( OBJECTTYPE *pObj ); void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ); extern CHAR16 gBulletCount[10]; +// HEADROCK HAM 4: This function generates a mag-factor bar percentage. +void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTime ); +// HEADROCK HAM 4: This gets the Z of a target regardless of what's there. +FLOAT GetTargetZPos( SOLDIERTYPE *pShooter, INT32 sTargetGridNo ); #endif diff --git a/Tactical/World Items.h b/Tactical/World Items.h index 3f69b753..1be0dc4c 100644 --- a/Tactical/World Items.h +++ b/Tactical/World Items.h @@ -43,6 +43,7 @@ public: bool operator<(WORLDITEM& compare); BOOLEAN Save( HWFILE hFile, bool fSavingMap ); BOOLEAN Load( HWFILE hFile ); + BOOLEAN Load( HWFILE hFile, float dMajorMapVersion, UINT8 ubMinorMapVersion ); BOOLEAN Load( INT8** hBuffer, float dMajorMapVersion, UINT8 ubMinorMapVersion ); void initialize(); BOOLEAN fExists; diff --git a/Tactical/XML.h b/Tactical/XML.h index 584262ed..e2761513 100644 --- a/Tactical/XML.h +++ b/Tactical/XML.h @@ -4,7 +4,10 @@ #include "armsdealerinvinit.h" #include "EnemyItemDrops.h" #include "Loading Screen.h" - +#include "faces.h" +#include "Interface.h" +#include "XML_SenderNameList.h" +#include "qarray.h" //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; @@ -16,6 +19,8 @@ enum ELEMENT_LIST, ELEMENT, ELEMENT_PROPERTY, + ELEMENT_SUBLIST, + ELEMENT_SUBLIST_PROPERTY, // For new merchant inventory MERCHANT_CONTROL, @@ -37,7 +42,7 @@ typedef PARSE_STAGE; #define POLISH_PREFIX "Polish." #define FRENCH_PREFIX "French." #define ITALIAN_PREFIX "Italian." -#define TAIWANESE_PREFIX "Tiawanese." +#define TAIWANESE_PREFIX "Taiwanese." #define CHINESE_PREFIX "Chinese." #define ATTACHMENTSFILENAME "Attachments.xml" @@ -54,6 +59,7 @@ typedef PARSE_STAGE; #define AMMOFILENAME "AmmoStrings.xml" #define AMMOTYPESFILENAME "AmmoTypes.xml" #define INCOMPATIBLEATTACHMENTSFILENAME "IncompatibleAttachments.xml" +#define ATTACHMENTSLOTSFILENAME "AttachmentSlots.xml" #define ENEMYGUNCHOICESFILENAME "EnemyGunChoices.xml" #define ENEMYITEMCHOICESFILENAME "EnemyItemChoices.xml" #define IMPITEMCHOICESFILENAME "IMPItemChoices.xml" @@ -69,7 +75,7 @@ typedef PARSE_STAGE; #define KEITHINVENTORYFILENAME "NPCInventory\\KeithInventory.xml" #define SAMINVENTORYFILENAME "NPCInventory\\SamInventory.xml" #define JAKEINVENTORYFILENAME "NPCInventory\\JakeInventory.xml" -#define HOWARDINVENTORYFILENAME "NPCInventory\\HowardInventory.xml" +#define HOWARDINVENTORYFILENAME "NPCInventory\\HowardInventory.xml" #define GABBYINVENTORYFILENAME "NPCInventory\\GabbyInventory.xml" #define FRANKINVENTORYFILENAME "NPCInventory\\FrankInventory.xml" #define ELGININVENTORYFILENAME "NPCInventory\\ElginInventory.xml" @@ -78,16 +84,16 @@ typedef PARSE_STAGE; #define PETERINVENTORYFILENAME "NPCInventory\\PeterInventory.xml" #define ALBERTOINVENTORYFILENAME "NPCInventory\\AlbertoInventory.xml" #define CARLOINVENTORYFILENAME "NPCInventory\\CarloInventory.xml" -#define MICKEYINVENTORYFILENAME "NPCInventory\\MickeyInventory.xml" +#define MICKEYINVENTORYFILENAME "NPCInventory\\MickeyInventory.xml" #define ARNIEINVENTORYFILENAME "NPCInventory\\ArnieInventory.xml" #define PERKOINVENTORYFILENAME "NPCInventory\\PerkoInventory.xml" #define FREDOINVENTORYFILENAME "NPCInventory\\FredoInventory.xml" -#define BOBBYRAYSTRINGSFILENAME "BobbyRayStrings.xml" +#define BOBBYRAYSTRINGSFILENAME "BobbyRayStrings.xml" #define AMMOCALIBERSTRINGSFILENAME "AmmoCaliberStrings.xml" #define SOUNDSFILENAME "Sounds\\Sounds.xml" -#define BURSTSOUNDSFILENAME "Sounds\\BurstSounds.xml" +#define BURSTSOUNDSFILENAME "Sounds\\BurstSounds.xml" #define EXPLOSIONDATAFILENAME "ExplosionData.xml" @@ -96,20 +102,17 @@ typedef PARSE_STAGE; #define ALTSECTORSFILENAME "Map\\AltSectors.xml" #define SAMSITESFILENAME "Map\\SamSites.xml" #define ROAMINGMILITIAFILENAME "Map\\RestrictedRoamingMilitia.xml" -#define EXTRAITEMSFILENAME "Map\\A9_0_ExtraItems.xml" -#define EXTRAITEMSFILENAME2 "Map\\A11_0_ExtraItems.xml" - -// Gotthard: Strategic Text Files [2007-10-19] -#define STRATEGICSECTORNAMETEXTFILENAME "Map\\SectorNames.xml" +#define EXTRAITEMSFILENAME "Map\\A9_0_ExtraItems" // ".xml" will be added @runtime +#define EXTRAITEMSFILENAME2 "Map\\A11_0_ExtraItems" // ".xml" will be added @runtime #define GARRISONFILENAME "Army\\GarrisonGroups.xml" #define PATROLFILENAME "Army\\PatrolGroups.xml" -#define COMPOSITIONFILENAME "Army\\ArmyComposition.xml" +#define COMPOSITIONFILENAME "Army\\ArmyComposition.xml" // WANNE: drops filename #define ENEMYWEAPONDROPSFILENAME "EnemyWeaponDrops.xml" #define ENEMYAMMODROPSFILENAME "EnemyAmmoDrops.xml" -#define ENEMYEXPLOSIVEDROPSFILENAME "EnemyExplosiveDrops.xml" +#define ENEMYEXPLOSIVEDROPSFILENAME "EnemyExplosiveDrops.xml" #define ENEMYARMOURDROPSFILENAME "EnemyArmourDrops.xml" #define ENEMYMISCDROPSFILENAME "EnemyMiscDrops.xml" @@ -117,7 +120,7 @@ typedef PARSE_STAGE; #define SECTORLOADSCREENSFILENAME "Map\\SectorLoadscreens.xml" //zilpin: pellet spread patterns externalized in XML -#define SPREADPATTERNSFILENAME "SpreadPatterns.xml" +#define SPREADPATTERNSFILENAME "SpreadPatterns.xml" #define DELIVERYMETHODSFILENAME "Map\\DeliveryMethods.xml" // Dealtar: Shipping destinations and delivery methods @@ -147,10 +150,45 @@ typedef PARSE_STAGE; // HEADROCK PROFEX: Merc Opinions [2009-07-27] #define MERCOPINIONSFILENAME "MercOpinions.xml" // HEADROCK HAM 3.6: Bloodcat Placements [2009-07-31] -#define BLOODCATPLACEMENTSFILENAME "Map\\BloodcatPlacements.xml" +#define BLOODCATPLACEMENTSFILENAME "Map\\BloodcatPlacements.xml" // HEADROCK HAM 3.6: Uniform Colors [2009-09-29] #define UNIFORMCOLORSFILENAME "Army\\UniformColors.xml" +//SMALL FACES +#define RPCFACESSMALLFILENAME "RPCFacesSmall.xml" + +//Hidden Names +#define HIDDENNAMESFILENAME "HiddenNames.xml" + +//Enemy Names +#define ENEMYNAMESFILENAME "EnemyNames.xml" + +//Enemy RANK +#define ENEMYRANKFILENAME "EnemyRank.xml" + +//CIV Names +#define CIVGROUPNAMESFILENAME "CivGroupNames.xml" + +//Sender Name List +#define SENDERNAMELISTFILENAME "SenderNameList.xml" + + +#define IMPPORTRAITS "IMPPortraits.xml" + +#define SOUNDPROFILE "SoundsProfiles.xml" + +#define RANDOMSTATS "RandomStats.xml" + +#define SECTORLEVEL1NAMESFILENAME "Map\\SectorNamesLevel_1.xml" +#define SECTORLEVEL2NAMESFILENAME "Map\\SectorNamesLevel_2.xml" +#define SECTORLEVEL3NAMESFILENAME "Map\\SectorNamesLevel_3.xml" + +#define MERCAVAILABILITY "MercAvailability.xml" + +#define AIMAVAILABILITY "AimAvailability.xml" + +#define QUOTEARRAYFILENAME "MercQuote.xml" + extern BOOLEAN ReadInItemStats(STR fileName, BOOLEAN localizedVersion); extern BOOLEAN WriteItemStats(); @@ -199,6 +237,9 @@ extern BOOLEAN WriteAmmoStats(); extern BOOLEAN WriteIncompatibleAttachmentStats(); extern BOOLEAN ReadInIncompatibleAttachmentStats(STR fileName); +//WarmSteel - for New Attachment System +extern BOOLEAN WriteAttachmentSlotsStats(); +extern BOOLEAN ReadInAttachmentSlotsStats(STR fileName); extern BOOLEAN WriteExtendedArmyGunChoicesStats(); extern BOOLEAN ReadInExtendedArmyGunChoicesStats(STR fileName); @@ -294,13 +335,13 @@ extern BOOLEAN ReadInSectorFacilities(STR fileName); extern BOOLEAN ReadInDynamicRoamingRestrictions(STR fileName); // HEADROCK HAM 3.5: Facility Types and bonuses -extern BOOLEAN ReadInFacilityTypes(STR fileName); +extern BOOLEAN ReadInFacilityTypes(STR fileName, BOOLEAN localizedVersion); // HEADROCK HAM 3.6: Customized Sector Names -extern BOOLEAN ReadInSectorNames(STR fileName); +extern BOOLEAN ReadInSectorNames(STR fileName, BOOLEAN localizedVersion, INT8 Level ); // HEADROCK PROFEX: Merc Profiles -extern BOOLEAN ReadInMercProfiles(STR fileName); +extern BOOLEAN ReadInMercProfiles(STR fileName, BOOLEAN localizedVersion); // HEADROCK PROFEX: Merc Opinions extern BOOLEAN ReadInMercOpinions(STR fileName); @@ -311,4 +352,41 @@ extern BOOLEAN ReadInBloodcatPlacements(STR fileName); // HEADROCK HAM 3.6: Customized Uniform Colors extern BOOLEAN ReadInUniforms(STR fileName); +//Jazz Small Faces +extern BOOLEAN ReadInSmallFacesStats(RPC_SMALL_FACE_VALUES *pSmallFaces, STR fileName); +extern BOOLEAN WriteSmallFacesStats(RPC_SMALL_FACE_VALUES *pSmallFaces, STR fileName); + +//Hidden Names +extern BOOLEAN ReadInHiddenNamesStats(HIDDEN_NAMES_VALUES *pHiddenNames, STR fileName); +extern BOOLEAN WriteHiddenNamesStats(HIDDEN_NAMES_VALUES *pHiddenNames, STR fileName); +extern void LoadHiddenNames(); + +extern BOOLEAN ReadInEnemyNames(STR fileName, BOOLEAN localizedVersion); +extern BOOLEAN ReadInCivGroupNamesStats(STR fileName, BOOLEAN localizedVersion); + +// the list of email sender names by Jazz +extern BOOLEAN ReadInSenderNameList(STR fileName, BOOLEAN localizedVersion); +extern BOOLEAN ReadInEnemyRank(STR fileName, BOOLEAN localizedVersion); +extern BOOLEAN WriteEnemyRank( STR fileName); +extern BOOLEAN ReadInIMPPortraits(STR fileName, BOOLEAN localizedVersion); +extern void LoadIMPPortraitsTEMP(); + +//Enabled\Disabled profile sound by Jazz +extern BOOLEAN ReadInSoundProfile( STR fileName ); +extern BOOLEAN WriteSoundProfile( STR fileName ); + +//Random stats by Jazz +extern BOOLEAN WriteRandomStats( STR fileName ); +extern BOOLEAN ReadInRandomStats( STR fileName ); + +//new profiles by Jazz +extern BOOLEAN ReadInMercAvailability(STR fileName, BOOLEAN localizedVersion); +extern BOOLEAN WriteMercAvailability(STR fileName); + +extern BOOLEAN ReadInAimAvailability(STR fileName, BOOLEAN localizedVersion); +extern BOOLEAN WriteAimAvailability(STR fileName); + +extern BOOLEAN WriteQarray(QARRAY_VALUES *pQarray, STR fileName); +extern BOOLEAN ReadInQarray(QARRAY_VALUES *pQarray, STR fileName); + #endif diff --git a/Tactical/XML_AttachmentSlots.cpp b/Tactical/XML_AttachmentSlots.cpp new file mode 100644 index 00000000..63ed4db9 --- /dev/null +++ b/Tactical/XML_AttachmentSlots.cpp @@ -0,0 +1,264 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "overhead.h" + #include "weapons.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" +#endif + +UINT16 LAST_SLOT_INDEX = 0; + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + + AttachmentSlotStruct curAttachmentSlot; + AttachmentSlotStruct * curArray; + + UINT32 maxArraySize; + + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef attachmentslotParseData; + +static void XMLCALL +attachmentslotStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + attachmentslotParseData * pData = (attachmentslotParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "ATTACHMENTSLOTLIST") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + memset(pData->curArray,0,sizeof(AttachmentSlotStruct)*pData->maxArraySize); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "ATTACHMENTSLOT") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + memset(&pData->curAttachmentSlot,0,sizeof(AttachmentSlotStruct)); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiSlotIndex") == 0 || + strcmp(name, "szSlotName") == 0 || + strcmp(name, "nasAttachmentClass") == 0 || + strcmp(name, "nasLayoutClass") == 0 || + strcmp(name, "usDescPanelPosX") == 0 || + strcmp(name, "usDescPanelPosY") == 0 || + strcmp(name, "fMultiShot") == 0 || + strcmp(name, "fBigSlot") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +attachmentslotCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + attachmentslotParseData * pData = (attachmentslotParseData *)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 +attachmentslotEndElementHandle(void *userData, const XML_Char *name) +{ + attachmentslotParseData * pData = (attachmentslotParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "ATTACHMENTSLOTLIST") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "ATTACHMENTSLOT") == 0) + { + pData->curElement = ELEMENT_LIST; + + if(pData->curAttachmentSlot.uiSlotIndex < pData->maxArraySize) + { + pData->curArray[pData->curAttachmentSlot.uiSlotIndex] = pData->curAttachmentSlot; //write the attachmentinfo into the table + //Save the highest known index up till now. + if(LAST_SLOT_INDEX < pData->curAttachmentSlot.uiSlotIndex){ + LAST_SLOT_INDEX = (UINT16) pData->curAttachmentSlot.uiSlotIndex; + } + } + } + else if(strcmp(name, "uiSlotIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.uiSlotIndex = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "szSlotName") == 0) + { + pData->curElement = ELEMENT; + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curAttachmentSlot.szSlotName, sizeof(pData->curAttachmentSlot.szSlotName)/sizeof(pData->curAttachmentSlot.szSlotName[0]) ); + pData->curAttachmentSlot.szSlotName[sizeof(pData->curAttachmentSlot.szSlotName)/sizeof(pData->curAttachmentSlot.szSlotName[0]) - 1] = '\0'; + } + else if(strcmp(name, "nasAttachmentClass") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.nasAttachmentClass = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "nasLayoutClass") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.nasLayoutClass = (UINT128) atol(pData->szCharData); + } + else if(strcmp(name, "usDescPanelPosX") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.usDescPanelPosX = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "usDescPanelPosY") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.usDescPanelPosY = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "fMultiShot") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.fMultiShot = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "fBigSlot") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachmentSlot.fBigSlot = (BOOLEAN) atol(pData->szCharData); + } + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + +BOOLEAN ReadInAttachmentSlotsStats(STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + attachmentslotParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading AttachmentSlots.xml" ); + + // Open attachmentinfo 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, attachmentslotStartElementHandle, attachmentslotEndElementHandle); + XML_SetCharacterDataHandler(parser, attachmentslotCharacterDataHandle); + + + // This should fix the crash in a Release Version with VS 2008 + //memset(&pData,0,sizeof(pData)); + pData.curElement = ELEMENT_NONE; + pData.szCharData[0] = 0; + pData.currentDepth = 0; + pData.maxReadDepth = 0; + pData.curArray = AttachmentSlots; + pData.maxArraySize = MAXITEMS; + + + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in AttachmentSlots.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + +BOOLEAN WriteAttachmentSlotsStats() +{ + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"writeattachmentslotstats"); + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( "TABLEDATA\\AttachmentSlots out.xml", FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < MAXITEMS;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].uiSlotIndex ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].szSlotName ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].nasAttachmentClass ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].nasLayoutClass ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].usDescPanelPosX ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].usDescPanelPosY ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].fMultiShot ); + FilePrintf(hFile,"\t\t%d\r\n", AttachmentSlots[cnt].fBigSlot ); + + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} diff --git a/Tactical/XML_Attachments.cpp b/Tactical/XML_Attachments.cpp index 2de3fa94..edda40d1 100644 --- a/Tactical/XML_Attachments.cpp +++ b/Tactical/XML_Attachments.cpp @@ -16,7 +16,7 @@ struct CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; - UINT16 curAttachment[3]; + UINT16 curAttachment[4]; UINT32 maxArraySize; UINT32 curIndex; UINT32 currentDepth; @@ -51,6 +51,7 @@ attachmentStartElementHandle(void *userData, const XML_Char *name, const XML_Cha else if(pData->curElement == ELEMENT && (strcmp(name, "attachmentIndex") == 0 || strcmp(name, "APCost") == 0 || + strcmp(name, "NASOnly") == 0 || strcmp(name, "itemIndex") == 0 )) { pData->curElement = ELEMENT_PROPERTY; @@ -117,6 +118,11 @@ attachmentEndElementHandle(void *userData, const XML_Char *name) pData->curAttachment[2] = (UINT16) atol(pData->szCharData); pData->curAttachment[2] = (UINT16)DynamicAdjustAPConstants(pData->curAttachment[2], pData->curAttachment[2]); } + else if(strcmp(name, "NASOnly") == 0) + { + pData->curElement = ELEMENT; + pData->curAttachment[3] = (UINT16) atol(pData->szCharData); + } pData->maxReadDepth--; } @@ -209,6 +215,7 @@ BOOLEAN WriteAttachmentStats() FilePrintf(hFile,"\t\t%d\r\n", Attachment[cnt][0]); FilePrintf(hFile,"\t\t%d\r\n", Attachment[cnt][1]); FilePrintf(hFile,"\t\t%d\r\n", Attachment[cnt][2]); + FilePrintf(hFile,"\t\t%d\r\n", Attachment[cnt][3]); FilePrintf(hFile,"\t\r\n"); } diff --git a/Tactical/XML_CivGroupNames.cpp b/Tactical/XML_CivGroupNames.cpp new file mode 100644 index 00000000..ea38ff61 --- /dev/null +++ b/Tactical/XML_CivGroupNames.cpp @@ -0,0 +1,206 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" + #include "EditorMercs.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + CIV_NAMES_VALUES curCivGroupNames; + CIV_NAMES_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef civGroupNamesParseData; + +BOOLEAN CivGroupNames_TextOnly; + +static void XMLCALL +civGroupNamesStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + civGroupNamesParseData * pData = (civGroupNamesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "CIV_GROUP_NAMES") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "NAME") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "Enabled") == 0 || + strcmp(name, "Loyalty") == 0 || + strcmp(name, "AddToBattle") == 0 || + strcmp(name, "szGroup") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +civGroupNamesCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + civGroupNamesParseData * pData = (civGroupNamesParseData *)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 +civGroupNamesEndElementHandle(void *userData, const XML_Char *name) +{ + civGroupNamesParseData * pData = (civGroupNamesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "CIV_GROUP_NAMES") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "NAME") == 0) + { + pData->curElement = ELEMENT_LIST; + + if (!CivGroupNames_TextOnly) + { + wcscpy(zCivGroupName[pData->curCivGroupNames.uiIndex].szCurGroup, pData->curCivGroupNames.szCurGroup); + zCivGroupName[pData->curCivGroupNames.uiIndex].Enabled = pData->curCivGroupNames.Enabled; + + zCivGroupName[pData->curCivGroupNames.uiIndex].AddToBattle = pData->curCivGroupNames.AddToBattle; + zCivGroupName[pData->curCivGroupNames.uiIndex].Loyalty = pData->curCivGroupNames.Loyalty; + } + else + { + wcscpy(zCivGroupName[pData->curCivGroupNames.uiIndex].szCurGroup, pData->curCivGroupNames.szCurGroup); + } + + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curCivGroupNames.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Enabled") == 0) + { + pData->curElement = ELEMENT; + pData->curCivGroupNames.Enabled = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "Loyalty") == 0) + { + pData->curElement = ELEMENT; + pData->curCivGroupNames.Loyalty = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "AddToBattle") == 0) + { + pData->curElement = ELEMENT; + pData->curCivGroupNames.AddToBattle = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "szGroup") == 0 ) + { + pData->curElement = ELEMENT; + + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curCivGroupNames.szCurGroup, sizeof(pData->curCivGroupNames.szCurGroup)/sizeof(pData->curCivGroupNames.szCurGroup[0]) ); + pData->curCivGroupNames.szCurGroup[sizeof(pData->curCivGroupNames.szCurGroup)/sizeof(pData->curCivGroupNames.szCurGroup[0]) - 1] = '\0'; + + #ifdef JA2EDITOR + wcscpy(gszCivGroupNames[pData->curCivGroupNames.uiIndex], pData->curCivGroupNames.szCurGroup); + #endif + + } + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInCivGroupNamesStats( STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + civGroupNamesParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading CivGroupNames.xml" ); + + CivGroupNames_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, civGroupNamesStartElementHandle, civGroupNamesEndElementHandle); + XML_SetCharacterDataHandler(parser, civGroupNamesCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in CivGroupNames.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 ); +} \ No newline at end of file diff --git a/Tactical/XML_EnemyNames.cpp b/Tactical/XML_EnemyNames.cpp new file mode 100644 index 00000000..8eb16beb --- /dev/null +++ b/Tactical/XML_EnemyNames.cpp @@ -0,0 +1,205 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + ENEMY_NAMES_VALUES curEnemyNames; + ENEMY_NAMES_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; + CHAR16 gzEnemyNames[MAX_ENEMY_NAMES_CHARS]; +} +typedef enemyNamesParseData; + +BOOLEAN EnemyName_TextOnly; + +static void XMLCALL +enemyNamesStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + enemyNamesParseData * pData = (enemyNamesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "ENEMY_NAMES") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "NAME") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "Sector") == 0 || + strcmp(name, "Enabled") == 0 || + strcmp(name, "szGroup") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +enemyNamesCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + enemyNamesParseData * pData = (enemyNamesParseData *)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 +enemyNamesEndElementHandle(void *userData, const XML_Char *name) +{ + enemyNamesParseData * pData = (enemyNamesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "ENEMY_NAMES") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "NAME") == 0) + { + pData->curElement = ELEMENT_LIST; + + if (!EnemyName_TextOnly) + { + wcscpy(zEnemyName[pData->curEnemyNames.uiIndex].szCurGroup, pData->curEnemyNames.szCurGroup); + zEnemyName[pData->curEnemyNames.uiIndex].Enabled = pData->curEnemyNames.Enabled; + zEnemyName[pData->curEnemyNames.uiIndex].SectorX = pData->curEnemyNames.SectorX; + zEnemyName[pData->curEnemyNames.uiIndex].SectorY = pData->curEnemyNames.SectorY; + } + else + { + wcscpy(zEnemyName[pData->curEnemyNames.uiIndex].szCurGroup, pData->curEnemyNames.szCurGroup); + } + + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyNames.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Enabled") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyNames.Enabled = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "Sector") == 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->curEnemyNames.SectorX = x; + pData->curEnemyNames.SectorY = y; + } + } + else if(strcmp(name, "szGroup") == 0 ) + { + pData->curElement = ELEMENT; + + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curEnemyNames.szCurGroup, sizeof(pData->curEnemyNames.szCurGroup)/sizeof(pData->curEnemyNames.szCurGroup[0]) ); + pData->curEnemyNames.szCurGroup[sizeof(pData->curEnemyNames.szCurGroup)/sizeof(pData->curEnemyNames.szCurGroup[0]) - 1] = '\0'; + } + pData->maxReadDepth--; + } + pData->currentDepth--; +} + + + + +BOOLEAN ReadInEnemyNames(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + enemyNamesParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading EnemyNames.xml" ); + + EnemyName_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, enemyNamesStartElementHandle, enemyNamesEndElementHandle); + XML_SetCharacterDataHandler(parser, enemyNamesCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in EnemyNames.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_EnemyRank.cpp b/Tactical/XML_EnemyRank.cpp new file mode 100644 index 00000000..9980970b --- /dev/null +++ b/Tactical/XML_EnemyRank.cpp @@ -0,0 +1,247 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + ENEMY_RANK_VALUES curEnemyRank; + ENEMY_RANK_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; + CHAR16 gzEnemyRank[MAX_ENEMY_NAMES_CHARS]; +} +typedef enemyRankParseData; + +BOOLEAN EnemyRank_TextOnly; + +static void XMLCALL +enemyRankStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + enemyRankParseData * pData = (enemyRankParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "ENEMY_RANK") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "RANK") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "ExpLevel") == 0 || + strcmp(name, "Stats") == 0 || + strcmp(name, "StatsMin") == 0 || + strcmp(name, "StatsMax") == 0 || + strcmp(name, "Enabled") == 0 || + strcmp(name, "szRank") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +enemyRankCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + enemyRankParseData * pData = (enemyRankParseData *)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 +enemyRankEndElementHandle(void *userData, const XML_Char *name) +{ + enemyRankParseData * pData = (enemyRankParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "ENEMY_RANK") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "RANK") == 0) + { + pData->curElement = ELEMENT_LIST; + + if (!EnemyRank_TextOnly) + { + wcscpy(zEnemyRank[pData->curEnemyRank.uiIndex].szCurRank, pData->curEnemyRank.szCurRank); + zEnemyRank[pData->curEnemyRank.uiIndex].Enabled = pData->curEnemyRank.Enabled; + zEnemyRank[pData->curEnemyRank.uiIndex].Stats = pData->curEnemyRank.Stats; + zEnemyRank[pData->curEnemyRank.uiIndex].StatsMax = pData->curEnemyRank.StatsMax; + zEnemyRank[pData->curEnemyRank.uiIndex].StatsMin = pData->curEnemyRank.StatsMin; + zEnemyRank[pData->curEnemyRank.uiIndex].ExpLevel = pData->curEnemyRank.ExpLevel; + } + else + { + wcscpy(zEnemyRank[pData->curEnemyRank.uiIndex].szCurRank, pData->curEnemyRank.szCurRank); + } + + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyRank.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Enabled") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyRank.Enabled = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "ExpLevel") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyRank.ExpLevel = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Stats") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyRank.Stats = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "StatsMax") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyRank.StatsMax = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "StatsMin") == 0) + { + pData->curElement = ELEMENT; + pData->curEnemyRank.StatsMin = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "szRank") == 0 ) + { + pData->curElement = ELEMENT; + + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curEnemyRank.szCurRank, sizeof(pData->curEnemyRank.szCurRank)/sizeof(pData->curEnemyRank.szCurRank[0]) ); + pData->curEnemyRank.szCurRank[sizeof(pData->curEnemyRank.szCurRank)/sizeof(pData->curEnemyRank.szCurRank[0]) - 1] = '\0'; + } + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInEnemyRank(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + enemyRankParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading EnemyRank.xml" ); + + EnemyRank_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, enemyRankStartElementHandle, enemyRankEndElementHandle); + XML_SetCharacterDataHandler(parser, enemyRankCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in EnemyRank.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + + +BOOLEAN WriteEnemyRank( STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < 500;cnt++) + { + FilePrintf(hFile,"\t\r\n"); + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t%d\r\n", zEnemyRank[cnt].Enabled); + FilePrintf(hFile,"\t\t%d\r\n", zEnemyRank[cnt].ExpLevel); + FilePrintf(hFile,"\t\t%d\r\n", zEnemyRank[cnt].Stats); + FilePrintf(hFile,"\t\t%d\r\n", zEnemyRank[cnt].StatsMax); + FilePrintf(hFile,"\t\t%d\r\n", zEnemyRank[cnt].StatsMin); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} diff --git a/Tactical/XML_Explosive.cpp b/Tactical/XML_Explosive.cpp index cc1a7a68..2ff644b2 100644 --- a/Tactical/XML_Explosive.cpp +++ b/Tactical/XML_Explosive.cpp @@ -55,6 +55,7 @@ explosiveStartElementHandle(void *userData, const XML_Char *name, const XML_Char strcmp(name, "ubVolume") == 0 || strcmp(name, "ubVolatility") == 0 || strcmp(name, "ubStartRadius") == 0 || + strcmp(name, "ubMagSize") == 0 || strcmp(name, "ubDuration") == 0 || strcmp(name, "ubAnimationID") == 0 )) { @@ -148,6 +149,11 @@ explosiveEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curExplosive.ubStartRadius = (UINT8) atol(pData->szCharData); } + else if(strcmp(name, "ubMagSize") == 0) + { + pData->curElement = ELEMENT; + pData->curExplosive.ubMagSize = (UINT8) atol(pData->szCharData); + } else if(strcmp(name, "ubDuration") == 0) { pData->curElement = ELEMENT; @@ -255,6 +261,7 @@ BOOLEAN WriteExplosiveStats() FilePrintf(hFile,"\t\t%d\r\n", Explosive[cnt].ubAnimationID ); FilePrintf(hFile,"\t\t%d\r\n", Explosive[cnt].ubDuration ); FilePrintf(hFile,"\t\t%d\r\n", Explosive[cnt].ubStartRadius ); + FilePrintf(hFile,"\t\t%d\r\n", Explosive[cnt].ubMagSize ); FilePrintf(hFile,"\t\r\n"); } diff --git a/Tactical/XML_HiddenNames.cpp b/Tactical/XML_HiddenNames.cpp new file mode 100644 index 00000000..b072905b --- /dev/null +++ b/Tactical/XML_HiddenNames.cpp @@ -0,0 +1,219 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + HIDDEN_NAMES_VALUES curHiddenNames; + HIDDEN_NAMES_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef hiddenNamesParseData; + +static void XMLCALL +hiddenNamesStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + hiddenNamesParseData * pData = (hiddenNamesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "HIDDENNAMES") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + memset(pData->curArray,0,sizeof(HIDDEN_NAMES_VALUES)*pData->maxArraySize); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "NAME") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + memset(&pData->curHiddenNames,0,sizeof(HIDDEN_NAMES_VALUES)); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "Hidden") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +hiddenNamesCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + hiddenNamesParseData * pData = (hiddenNamesParseData *)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 +hiddenNamesEndElementHandle(void *userData, const XML_Char *name) +{ + hiddenNamesParseData * pData = (hiddenNamesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "HIDDENNAMES") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "NAME") == 0) + { + pData->curElement = ELEMENT_LIST; + + if(pData->curHiddenNames.uiIndex < pData->maxArraySize) + { + pData->curArray[pData->curHiddenNames.uiIndex] = pData->curHiddenNames; //write the hidden names into the table + } + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curHiddenNames.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Hidden") == 0) + { + pData->curElement = ELEMENT; + pData->curHiddenNames.Hidden = (BOOLEAN) atol(pData->szCharData); + } + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + + + +BOOLEAN ReadInHiddenNamesStats(HIDDEN_NAMES_VALUES *pHiddenNames, STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + hiddenNamesParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading HiddenNames.xml" ); + + // Open 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, hiddenNamesStartElementHandle, hiddenNamesEndElementHandle); + XML_SetCharacterDataHandler(parser, hiddenNamesCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + pData.curArray = pHiddenNames; + pData.maxArraySize = 500; + + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in HiddenNames.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + +BOOLEAN WriteHiddenNamesStats(HIDDEN_NAMES_VALUES *pHiddenNames, STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < 500;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t%d\r\n", pHiddenNames[cnt].Hidden); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} + +//Restart Game and New Game +void LoadHiddenNames() +{ + char fileName[MAX_PATH]; + + strcpy(fileName, TABLEDATA_DIRECTORY); + strcat(fileName, HIDDENNAMESFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInHiddenNamesStats(zHiddenNames,fileName), HIDDENNAMESFILENAME); +} \ No newline at end of file diff --git a/Tactical/XML_MercStartingGear.cpp b/Tactical/XML_MercStartingGear.cpp index e8e15b6b..99496899 100644 --- a/Tactical/XML_MercStartingGear.cpp +++ b/Tactical/XML_MercStartingGear.cpp @@ -16,7 +16,9 @@ struct CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; MERCPROFILEGEAR curMercStartingGear; - MERCPROFILEGEAR * curArray; + MERCPROFILEGEAR (*curArray)[NUM_MERCSTARTINGGEAR_KITS]; + UINT8 curIndex; // Holds the number of the current profile for whom we're reading gear. + UINT8 curGears; // Holds the number of gears read so far for one index number. UINT32 maxArraySize; UINT32 currentDepth; @@ -39,6 +41,8 @@ MercStartingGearStartElementHandle(void *userData, const XML_Char *name, const X //memset(pData->curArray,0,sizeof(MERCPROFILEGEAR)*pData->maxArraySize); pData->maxReadDepth++; //we are not skipping this element + + pData->curIndex = 0; } else if(strcmp(name, "MERCGEAR") == 0 && pData->curElement == ELEMENT_LIST) { @@ -48,10 +52,25 @@ MercStartingGearStartElementHandle(void *userData, const XML_Char *name, const X //memset(&pData->curMercStartingGear,0,sizeof(MERCPROFILEGEAR)); pData->maxReadDepth++; //we are not skipping this element + + pData->curGears = 0; } else if(pData->curElement == ELEMENT && - (strcmp(name, "mIndex") == 0 || - strcmp(name, "mName") == 0 || + (strcmp(name, "mIndex") == 0 || + strcmp(name, "mName") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; + } + else if(strcmp(name, "GEARKIT") == 0 && pData->curElement == ELEMENT) + { + pData->curElement = ELEMENT_SUBLIST; + + pData->maxReadDepth++; + } + else if(pData->curElement == ELEMENT_SUBLIST && + (strcmp(name, "mPriceMod") == 0 || strcmp(name, "mHelmet") == 0 || strcmp(name, "mHelmetStatus") == 0 || strcmp(name, "mHelmetDrop") == 0 || @@ -115,7 +134,7 @@ MercStartingGearStartElementHandle(void *userData, const XML_Char *name, const X strcmp(name, "lBPack") == 0 || strcmp(name, "lBPackStatus") == 0 )) { - pData->curElement = ELEMENT_PROPERTY; + pData->curElement = ELEMENT_SUBLIST_PROPERTY; pData->maxReadDepth++; //we are not skipping this element } @@ -155,16 +174,12 @@ MercStartingGearEndElementHandle(void *userData, const XML_Char *name) else if(strcmp(name, "MERCGEAR") == 0) { pData->curElement = ELEMENT_LIST; - - if(pData->curMercStartingGear.mIndex < pData->maxArraySize) - { - pData->curArray[pData->curMercStartingGear.mIndex] = pData->curMercStartingGear; //write the armour into the table - } } else if(strcmp(name, "mIndex") == 0) { pData->curElement = ELEMENT; pData->curMercStartingGear.mIndex = (UINT16) atol(pData->szCharData); + pData->curIndex = (UINT8) atol(pData->szCharData); } else if(strcmp(name, "mName") == 0) { @@ -183,314 +198,331 @@ MercStartingGearEndElementHandle(void *userData, const XML_Char *name) //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("itemEndElementHandle: itemname[%d] = %s, temp = %s",i,&pData->curItem.szItemName[i],&temp)); } } + else if(strcmp(name, "GEARKIT") == 0 ) + { + // Write the gear into memory. + if(pData->curIndex < pData->maxArraySize && pData->curGears < NUM_MERCSTARTINGGEAR_KITS) + { + pData->curArray[pData->curIndex][pData->curGears] = pData->curMercStartingGear; //write the armour into the table + } + + pData->curElement = ELEMENT; + // Increase the number of gears read. + pData->curGears++; + } + else if(strcmp(name, "mPriceMod") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curMercStartingGear.PriceModifier = (int) atol(pData->szCharData); + } else if(strcmp(name, "mHelmet") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[HELMETPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mVest") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[VESTPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mLeg") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[LEGPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mWeapon") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[HANDPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig0") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[BIGPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig1") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[BIGPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig2") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[BIGPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig3") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[BIGPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall0") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall1") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall2") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall3") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall4") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK5POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall5") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK6POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall6") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK7POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall7") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.inv[SMALLPOCK8POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mHelmetStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[HELMETPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mVestStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[VESTPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mLegStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[LEGPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mWeaponStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[HANDPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig0Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[BIGPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig1Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[BIGPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig2Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[BIGPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig3Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[BIGPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall0Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall1Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall2Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall3Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall4Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK5POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall5Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK6POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall6Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK7POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall7Status") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iStatus[SMALLPOCK8POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mHelmetDrop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[HELMETPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mVestDrop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[VESTPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mLegDrop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[LEGPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mWeaponDrop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[HANDPOS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig0Drop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[BIGPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig1Drop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[BIGPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig2Drop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[BIGPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig3Drop") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iDrop[BIGPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig0Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[BIGPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig1Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[BIGPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig2Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[BIGPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mBig3Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[BIGPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall0Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK1POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall1Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK2POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall2Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK3POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall3Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK4POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall4Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK5POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall5Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK6POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall6Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK7POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "mSmall7Quantity") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.iNumber[SMALLPOCK8POS] = (int) atol(pData->szCharData); } else if(strcmp(name, "lVest") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lbe[0] = (int) atol(pData->szCharData); } else if(strcmp(name, "lLeftThigh") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lbe[1] = (int) atol(pData->szCharData); } else if(strcmp(name, "lRightThigh") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lbe[2] = (int) atol(pData->szCharData); } else if(strcmp(name, "lCPack") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lbe[3] = (int) atol(pData->szCharData); } else if(strcmp(name, "lBPack") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lbe[4] = (int) atol(pData->szCharData); } else if(strcmp(name, "lVestStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lStatus[0] = (int) atol(pData->szCharData); } else if(strcmp(name, "lLeftThighStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lStatus[1] = (int) atol(pData->szCharData); } else if(strcmp(name, "lRightThighStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lStatus[2] = (int) atol(pData->szCharData); } else if(strcmp(name, "lCPackStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lStatus[3] = (int) atol(pData->szCharData); } else if(strcmp(name, "lBPackStatus") == 0) { - pData->curElement = ELEMENT; + pData->curElement = ELEMENT_SUBLIST; pData->curMercStartingGear.lStatus[4] = (int) atol(pData->szCharData); } @@ -540,14 +572,19 @@ BOOLEAN ReadInMercStartingGearStats(STR fileName) memset(&pData,0,sizeof(pData)); + pData.curArray = gMercProfileGear; + pData.maxArraySize = NUM_PROFILES; XML_SetUserData(parser, &pData); for(int i=0; i\r\n"); @@ -588,18 +627,17 @@ BOOLEAN WriteMercStartingGearStats() { FilePrintf(hFile,"\t\r\n"); - FilePrintf(hFile,"\t\t%d\r\n", cnt ); -// FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].mName ); + //FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].mName ); int j = -1; for (int i=0;i<80;i++) { j++; - if ( i<(int)strlen(gMercProfileGear[cnt].mName)) + if ( i<(int)strlen(gMercProfileGear[cnt][gearkit].mName)) { - str[i] = gMercProfileGear[cnt].mName [j]; + str[i] = gMercProfileGear[cnt][gearkit].mName [j]; } else { @@ -651,69 +689,71 @@ BOOLEAN WriteMercStartingGearStats() } } FilePrintf(hFile,"\r\n"); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[HELMETPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[VESTPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[LEGPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[HANDPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[HELMETPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[VESTPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[LEGPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[HANDPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[HELMETPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[VESTPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[LEGPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[HANDPOS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[BIGPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[BIGPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[BIGPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[BIGPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[BIGPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[BIGPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[BIGPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[BIGPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[BIGPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[BIGPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[BIGPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[BIGPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[BIGPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[BIGPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[BIGPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iDrop[BIGPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK5POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK6POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK7POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].inv[SMALLPOCK8POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK5POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK6POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK7POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iNumber[SMALLPOCK8POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK1POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK2POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK3POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK4POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK5POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK6POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK7POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].iStatus[SMALLPOCK8POS] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lbe[0] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lbe[1] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lbe[2] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lbe[3] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lbe[4] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lStatus[0] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lStatus[1] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lStatus[2] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lStatus[3] ); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt].lStatus[4] ); - + for(gearkit = 0; gearkit < NUM_MERCSTARTINGGEAR_KITS; gearkit++) + { + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[HELMETPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[VESTPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[LEGPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[HANDPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[HELMETPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[VESTPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[LEGPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[HANDPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[HELMETPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[VESTPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[LEGPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[HANDPOS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[BIGPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[BIGPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[BIGPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[BIGPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[BIGPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[BIGPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[BIGPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[BIGPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[BIGPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[BIGPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[BIGPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[BIGPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[BIGPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[BIGPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[BIGPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iDrop[BIGPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK5POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK6POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK7POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].inv[SMALLPOCK8POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK5POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK6POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK7POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iNumber[SMALLPOCK8POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK1POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK2POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK3POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK4POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK5POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK6POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK7POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].iStatus[SMALLPOCK8POS] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lbe[0] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lbe[1] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lbe[2] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lbe[3] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lbe[4] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lStatus[0] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lStatus[1] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lStatus[2] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lStatus[3] ); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfileGear[cnt][gearkit].lStatus[4] ); + } FilePrintf(hFile,"\t\r\n"); } FilePrintf(hFile,"\r\n"); @@ -722,3 +762,4 @@ BOOLEAN WriteMercStartingGearStats() return( TRUE ); } +*/ diff --git a/Tactical/XML_Profiles.cpp b/Tactical/XML_Profiles.cpp index 189eaaec..e2a2f65b 100644 --- a/Tactical/XML_Profiles.cpp +++ b/Tactical/XML_Profiles.cpp @@ -20,7 +20,7 @@ #include "XML.h" #include "Soldier Profile.h" #endif - + #include "Soldier Profile.h" //#define MAX_PROFILE_NAME_LENGTH 30 struct @@ -39,7 +39,7 @@ typedef profileParseData; TEMPPROFILETYPE tempProfiles[NUM_PROFILES+1]; - +BOOLEAN MercProfiles_TextOnly; static void XMLCALL profileStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) @@ -87,7 +87,8 @@ profileStartElementHandle(void *userData, const XML_Char *name, const XML_Char * strcmp(name, "ubBodyType") == 0 || strcmp(name, "uiBodyTypeSubFlags") == 0 || strcmp(name, "bAttitude") == 0 || - strcmp(name, "bPersonalityTrait") == 0 || + strcmp(name, "bCharacterTrait") == 0 || // added by SANDRO + strcmp(name, "bDisability") == 0 || strcmp(name, "ubNeedForSleep") == 0 || strcmp(name, "bReputationTolerance") == 0 || strcmp(name, "bDeathRate") == 0 || @@ -104,8 +105,40 @@ profileStartElementHandle(void *userData, const XML_Char *name, const XML_Char * strcmp(name, "bMechanical") == 0 || strcmp(name, "bExpLevel") == 0 || strcmp(name, "bEvolution") == 0 || - strcmp(name, "bSkillTrait") == 0 || - strcmp(name, "bSkillTrait2") == 0 || + // added by SANDRO + strcmp(name, "bOldSkillTrait") == 0 || + strcmp(name, "bOldSkillTrait2") == 0 || + strcmp(name, "bNewSkillTrait1") == 0 || + strcmp(name, "bNewSkillTrait2") == 0 || + strcmp(name, "bNewSkillTrait3") == 0 || + strcmp(name, "bNewSkillTrait4") == 0 || + strcmp(name, "bNewSkillTrait5") == 0 || + strcmp(name, "bNewSkillTrait6") == 0 || + strcmp(name, "bNewSkillTrait7") == 0 || + strcmp(name, "bNewSkillTrait8") == 0 || + strcmp(name, "bNewSkillTrait9") == 0 || + strcmp(name, "bNewSkillTrait10") == 0 || + strcmp(name, "bNewSkillTrait11") == 0 || + strcmp(name, "bNewSkillTrait12") == 0 || + strcmp(name, "bNewSkillTrait13") == 0 || + strcmp(name, "bNewSkillTrait14") == 0 || + strcmp(name, "bNewSkillTrait15") == 0 || + strcmp(name, "bNewSkillTrait16") == 0 || + strcmp(name, "bNewSkillTrait17") == 0 || + strcmp(name, "bNewSkillTrait18") == 0 || + strcmp(name, "bNewSkillTrait19") == 0 || + strcmp(name, "bNewSkillTrait20") == 0 || + strcmp(name, "bNewSkillTrait21") == 0 || + strcmp(name, "bNewSkillTrait22") == 0 || + strcmp(name, "bNewSkillTrait23") == 0 || + strcmp(name, "bNewSkillTrait24") == 0 || + strcmp(name, "bNewSkillTrait25") == 0 || + strcmp(name, "bNewSkillTrait26") == 0 || + strcmp(name, "bNewSkillTrait27") == 0 || + strcmp(name, "bNewSkillTrait28") == 0 || + strcmp(name, "bNewSkillTrait29") == 0 || + strcmp(name, "bNewSkillTrait30") == 0 || + strcmp(name, "bBuddy1") == 0 || strcmp(name, "bBuddy2") == 0 || strcmp(name, "bBuddy3") == 0 || @@ -137,7 +170,17 @@ profileStartElementHandle(void *userData, const XML_Char *name, const XML_Char * strcmp(name, "usApproachFactorFriendly") == 0 || strcmp(name, "usApproachFactorDirect") == 0 || strcmp(name, "usApproachFactorThreaten") == 0 || - strcmp(name, "usApproachFactorRecruit") == 0 + strcmp(name, "usApproachFactorRecruit") == 0 || + + //new tag + strcmp(name, "Type") == 0 || + strcmp(name, "sSectorX") == 0 || + strcmp(name, "sSectorY") == 0 || + strcmp(name, "sSectorZ") == 0 || + strcmp(name, "ubCivilianGroup") == 0 || + strcmp(name, "bTown") == 0 || + strcmp(name, "bTownAttachment") == 0 + )) { pData->curElement = ELEMENT_PROPERTY; @@ -182,75 +225,126 @@ profileEndElementHandle(void *userData, const XML_Char *name) if(pData->curIndex < pData->maxArraySize) { - // Write data into a temporary array that holds profiles. We will later copy data from that // temp array into the REAL profile array, one item at a time, replacing PROF.DAT data. - wcscpy(tempProfiles[pData->curIndex].zName, pData->curProfile.zName); - wcscpy(tempProfiles[pData->curIndex].zNickname, pData->curProfile.zNickname); - - tempProfiles[pData->curIndex].ubFaceIndex = pData->curProfile.ubFaceIndex; - tempProfiles[pData->curIndex].usEyesX = pData->curProfile.usEyesX; - tempProfiles[pData->curIndex].usEyesY = pData->curProfile.usEyesY; - tempProfiles[pData->curIndex].usMouthX = pData->curProfile.usMouthX; - tempProfiles[pData->curIndex].usMouthY = pData->curProfile.usMouthY; - tempProfiles[pData->curIndex].uiEyeDelay = pData->curProfile.uiEyeDelay; - tempProfiles[pData->curIndex].uiMouthDelay = pData->curProfile.uiMouthDelay; - tempProfiles[pData->curIndex].uiBlinkFrequency = pData->curProfile.uiBlinkFrequency; - tempProfiles[pData->curIndex].uiExpressionFrequency = pData->curProfile.uiExpressionFrequency; + + if (!MercProfiles_TextOnly) + { + wcscpy(tempProfiles[pData->curIndex].zName, pData->curProfile.zName); + wcscpy(tempProfiles[pData->curIndex].zNickname, pData->curProfile.zNickname); + + tempProfiles[pData->curIndex].ubFaceIndex = pData->curProfile.ubFaceIndex; + tempProfiles[pData->curIndex].usEyesX = pData->curProfile.usEyesX; + tempProfiles[pData->curIndex].usEyesY = pData->curProfile.usEyesY; + tempProfiles[pData->curIndex].usMouthX = pData->curProfile.usMouthX; + tempProfiles[pData->curIndex].usMouthY = pData->curProfile.usMouthY; + tempProfiles[pData->curIndex].uiEyeDelay = pData->curProfile.uiEyeDelay; + tempProfiles[pData->curIndex].uiMouthDelay = pData->curProfile.uiMouthDelay; + tempProfiles[pData->curIndex].uiBlinkFrequency = pData->curProfile.uiBlinkFrequency; + tempProfiles[pData->curIndex].uiExpressionFrequency = pData->curProfile.uiExpressionFrequency; - memcpy( &(tempProfiles[pData->curIndex].PANTS), &(pData->curProfile.PANTS), sizeof(PaletteRepID) ); - memcpy( &(tempProfiles[pData->curIndex].VEST), &(pData->curProfile.VEST), sizeof(PaletteRepID) ); - memcpy( &(tempProfiles[pData->curIndex].SKIN), &(pData->curProfile.SKIN), sizeof(PaletteRepID) ); - memcpy( &(tempProfiles[pData->curIndex].HAIR), &(pData->curProfile.HAIR), sizeof(PaletteRepID) ); + memcpy( &(tempProfiles[pData->curIndex].PANTS), &(pData->curProfile.PANTS), sizeof(PaletteRepID) ); + memcpy( &(tempProfiles[pData->curIndex].VEST), &(pData->curProfile.VEST), sizeof(PaletteRepID) ); + memcpy( &(tempProfiles[pData->curIndex].SKIN), &(pData->curProfile.SKIN), sizeof(PaletteRepID) ); + memcpy( &(tempProfiles[pData->curIndex].HAIR), &(pData->curProfile.HAIR), sizeof(PaletteRepID) ); - tempProfiles[pData->curIndex].bSex = pData->curProfile.bSex; - tempProfiles[pData->curIndex].ubBodyType = pData->curProfile.ubBodyType; - tempProfiles[pData->curIndex].uiBodyTypeSubFlags = pData->curProfile.uiBodyTypeSubFlags; + tempProfiles[pData->curIndex].bSex = pData->curProfile.bSex; + tempProfiles[pData->curIndex].ubBodyType = pData->curProfile.ubBodyType; + tempProfiles[pData->curIndex].uiBodyTypeSubFlags = pData->curProfile.uiBodyTypeSubFlags; - tempProfiles[pData->curIndex].bAttitude = pData->curProfile.bAttitude; - tempProfiles[pData->curIndex].bPersonalityTrait = pData->curProfile.bPersonalityTrait; - tempProfiles[pData->curIndex].ubNeedForSleep = pData->curProfile.ubNeedForSleep; - tempProfiles[pData->curIndex].bReputationTolerance = pData->curProfile.bReputationTolerance; - tempProfiles[pData->curIndex].bDeathRate = pData->curProfile.bDeathRate; + tempProfiles[pData->curIndex].bAttitude = pData->curProfile.bAttitude; + tempProfiles[pData->curIndex].bCharacterTrait = pData->curProfile.bCharacterTrait; // added by SANDRO + tempProfiles[pData->curIndex].bDisability = pData->curProfile.bDisability; + tempProfiles[pData->curIndex].ubNeedForSleep = pData->curProfile.ubNeedForSleep; + tempProfiles[pData->curIndex].bReputationTolerance = pData->curProfile.bReputationTolerance; + tempProfiles[pData->curIndex].bDeathRate = pData->curProfile.bDeathRate; - tempProfiles[pData->curIndex].bLifeMax = pData->curProfile.bLifeMax; - tempProfiles[pData->curIndex].bLife = pData->curProfile.bLife; - tempProfiles[pData->curIndex].bStrength = pData->curProfile.bStrength; - tempProfiles[pData->curIndex].bAgility = pData->curProfile.bAgility; - tempProfiles[pData->curIndex].bDexterity = pData->curProfile.bDexterity; - tempProfiles[pData->curIndex].bWisdom = pData->curProfile.bWisdom; - tempProfiles[pData->curIndex].bMarksmanship = pData->curProfile.bMarksmanship; - tempProfiles[pData->curIndex].bExplosive = pData->curProfile.bExplosive; - tempProfiles[pData->curIndex].bLeadership = pData->curProfile.bLeadership; - tempProfiles[pData->curIndex].bMedical = pData->curProfile.bMedical; - tempProfiles[pData->curIndex].bMechanical = pData->curProfile.bMechanical; - tempProfiles[pData->curIndex].bExpLevel = pData->curProfile.bExpLevel; + tempProfiles[pData->curIndex].bLifeMax = pData->curProfile.bLifeMax; + tempProfiles[pData->curIndex].bLife = pData->curProfile.bLife; + tempProfiles[pData->curIndex].bStrength = pData->curProfile.bStrength; + tempProfiles[pData->curIndex].bAgility = pData->curProfile.bAgility; + tempProfiles[pData->curIndex].bDexterity = pData->curProfile.bDexterity; + tempProfiles[pData->curIndex].bWisdom = pData->curProfile.bWisdom; + tempProfiles[pData->curIndex].bMarksmanship = pData->curProfile.bMarksmanship; + tempProfiles[pData->curIndex].bExplosive = pData->curProfile.bExplosive; + tempProfiles[pData->curIndex].bLeadership = pData->curProfile.bLeadership; + tempProfiles[pData->curIndex].bMedical = pData->curProfile.bMedical; + tempProfiles[pData->curIndex].bMechanical = pData->curProfile.bMechanical; + tempProfiles[pData->curIndex].bExpLevel = pData->curProfile.bExpLevel; - tempProfiles[pData->curIndex].bEvolution = pData->curProfile.bEvolution; - tempProfiles[pData->curIndex].bSkillTrait = pData->curProfile.bSkillTrait; - tempProfiles[pData->curIndex].bSkillTrait2 = pData->curProfile.bSkillTrait2; + tempProfiles[pData->curIndex].bEvolution = pData->curProfile.bEvolution; + // added by SANDRO + tempProfiles[pData->curIndex].bOldSkillTrait = pData->curProfile.bOldSkillTrait; + tempProfiles[pData->curIndex].bOldSkillTrait2 = pData->curProfile.bOldSkillTrait2; + tempProfiles[pData->curIndex].bNewSkillTrait1 = pData->curProfile.bNewSkillTrait1; + tempProfiles[pData->curIndex].bNewSkillTrait2 = pData->curProfile.bNewSkillTrait2; + tempProfiles[pData->curIndex].bNewSkillTrait3 = pData->curProfile.bNewSkillTrait3; + tempProfiles[pData->curIndex].bNewSkillTrait4 = pData->curProfile.bNewSkillTrait4; + tempProfiles[pData->curIndex].bNewSkillTrait5 = pData->curProfile.bNewSkillTrait5; + tempProfiles[pData->curIndex].bNewSkillTrait6 = pData->curProfile.bNewSkillTrait6; + tempProfiles[pData->curIndex].bNewSkillTrait7 = pData->curProfile.bNewSkillTrait7; + tempProfiles[pData->curIndex].bNewSkillTrait8 = pData->curProfile.bNewSkillTrait8; + tempProfiles[pData->curIndex].bNewSkillTrait9 = pData->curProfile.bNewSkillTrait9; + tempProfiles[pData->curIndex].bNewSkillTrait10 = pData->curProfile.bNewSkillTrait10; + tempProfiles[pData->curIndex].bNewSkillTrait11 = pData->curProfile.bNewSkillTrait11; + tempProfiles[pData->curIndex].bNewSkillTrait12 = pData->curProfile.bNewSkillTrait12; + tempProfiles[pData->curIndex].bNewSkillTrait13 = pData->curProfile.bNewSkillTrait13; + tempProfiles[pData->curIndex].bNewSkillTrait14 = pData->curProfile.bNewSkillTrait14; + tempProfiles[pData->curIndex].bNewSkillTrait15 = pData->curProfile.bNewSkillTrait15; + tempProfiles[pData->curIndex].bNewSkillTrait16 = pData->curProfile.bNewSkillTrait16; + tempProfiles[pData->curIndex].bNewSkillTrait17 = pData->curProfile.bNewSkillTrait17; + tempProfiles[pData->curIndex].bNewSkillTrait18 = pData->curProfile.bNewSkillTrait18; + tempProfiles[pData->curIndex].bNewSkillTrait19 = pData->curProfile.bNewSkillTrait19; + tempProfiles[pData->curIndex].bNewSkillTrait20 = pData->curProfile.bNewSkillTrait20; + tempProfiles[pData->curIndex].bNewSkillTrait21 = pData->curProfile.bNewSkillTrait21; + tempProfiles[pData->curIndex].bNewSkillTrait22 = pData->curProfile.bNewSkillTrait22; + tempProfiles[pData->curIndex].bNewSkillTrait23 = pData->curProfile.bNewSkillTrait23; + tempProfiles[pData->curIndex].bNewSkillTrait24 = pData->curProfile.bNewSkillTrait24; + tempProfiles[pData->curIndex].bNewSkillTrait25 = pData->curProfile.bNewSkillTrait25; + tempProfiles[pData->curIndex].bNewSkillTrait26 = pData->curProfile.bNewSkillTrait26; + tempProfiles[pData->curIndex].bNewSkillTrait27 = pData->curProfile.bNewSkillTrait27; + tempProfiles[pData->curIndex].bNewSkillTrait28 = pData->curProfile.bNewSkillTrait28; + tempProfiles[pData->curIndex].bNewSkillTrait29 = pData->curProfile.bNewSkillTrait29; + tempProfiles[pData->curIndex].bNewSkillTrait30 = pData->curProfile.bNewSkillTrait30; - memcpy( &(tempProfiles[pData->curIndex].bBuddy), &(pData->curProfile.bBuddy), 5 * sizeof (INT8)); - tempProfiles[pData->curIndex].bLearnToLike = pData->curProfile.bLearnToLike; - tempProfiles[pData->curIndex].bLearnToLikeTime = pData->curProfile.bLearnToLikeTime; - memcpy( &(tempProfiles[pData->curIndex].bHated), &(pData->curProfile.bHated), 5 * sizeof (INT8)); - memcpy( &(tempProfiles[pData->curIndex].bHatedTime), &(pData->curProfile.bHatedTime), 5 * sizeof (INT8)); - tempProfiles[pData->curIndex].bLearnToHate = pData->curProfile.bLearnToHate; - tempProfiles[pData->curIndex].bLearnToHateTime = pData->curProfile.bLearnToHateTime; + memcpy( &(tempProfiles[pData->curIndex].bBuddy), &(pData->curProfile.bBuddy), 5 * sizeof (INT8)); + tempProfiles[pData->curIndex].bLearnToLike = pData->curProfile.bLearnToLike; + tempProfiles[pData->curIndex].bLearnToLikeTime = pData->curProfile.bLearnToLikeTime; - tempProfiles[pData->curIndex].sSalary = pData->curProfile.sSalary; - tempProfiles[pData->curIndex].uiWeeklySalary = pData->curProfile.uiWeeklySalary; - tempProfiles[pData->curIndex].uiBiWeeklySalary = pData->curProfile.uiBiWeeklySalary; - tempProfiles[pData->curIndex].bMedicalDeposit = pData->curProfile.bMedicalDeposit; - tempProfiles[pData->curIndex].sMedicalDepositAmount = pData->curProfile.sMedicalDepositAmount; - tempProfiles[pData->curIndex].usOptionalGearCost = pData->curProfile.usOptionalGearCost; + memcpy( &(tempProfiles[pData->curIndex].bHated), &(pData->curProfile.bHated), 5 * sizeof (INT8)); + memcpy( &(tempProfiles[pData->curIndex].bHatedTime), &(pData->curProfile.bHatedTime), 5 * sizeof (INT8)); + tempProfiles[pData->curIndex].bLearnToHate = pData->curProfile.bLearnToHate; + tempProfiles[pData->curIndex].bLearnToHateTime = pData->curProfile.bLearnToHateTime; - tempProfiles[pData->curIndex].bArmourAttractiveness = pData->curProfile.bArmourAttractiveness; - tempProfiles[pData->curIndex].bMainGunAttractiveness = pData->curProfile.bMainGunAttractiveness; + tempProfiles[pData->curIndex].sSalary = pData->curProfile.sSalary; + tempProfiles[pData->curIndex].uiWeeklySalary = pData->curProfile.uiWeeklySalary; + tempProfiles[pData->curIndex].uiBiWeeklySalary = pData->curProfile.uiBiWeeklySalary; + tempProfiles[pData->curIndex].bMedicalDeposit = pData->curProfile.bMedicalDeposit; + tempProfiles[pData->curIndex].sMedicalDepositAmount = pData->curProfile.sMedicalDepositAmount; + tempProfiles[pData->curIndex].usOptionalGearCost = pData->curProfile.usOptionalGearCost; - tempProfiles[pData->curIndex].fGoodGuy = pData->curProfile.fGoodGuy; - memcpy( &(tempProfiles[pData->curIndex].usApproachFactor), &(pData->curProfile.usApproachFactor), 4 * sizeof (UINT16)); + tempProfiles[pData->curIndex].bArmourAttractiveness = pData->curProfile.bArmourAttractiveness; + tempProfiles[pData->curIndex].bMainGunAttractiveness = pData->curProfile.bMainGunAttractiveness; + + tempProfiles[pData->curIndex].Type = pData->curProfile.Type; + + tempProfiles[pData->curIndex].sSectorX = pData->curProfile.sSectorX; + tempProfiles[pData->curIndex].sSectorY = pData->curProfile.sSectorY; + tempProfiles[pData->curIndex].bSectorZ = pData->curProfile.bSectorZ; + tempProfiles[pData->curIndex].ubCivilianGroup = pData->curProfile.ubCivilianGroup; + tempProfiles[pData->curIndex].bTown = pData->curProfile.bTown; + tempProfiles[pData->curIndex].bTownAttachment = pData->curProfile.bTownAttachment; + + tempProfiles[pData->curIndex].fGoodGuy = pData->curProfile.fGoodGuy; + memcpy( &(tempProfiles[pData->curIndex].usApproachFactor), &(pData->curProfile.usApproachFactor), 4 * sizeof (UINT16)); + + } + else + { + wcscpy(tempProfiles[pData->curIndex].zName, pData->curProfile.zName); + wcscpy(tempProfiles[pData->curIndex].zNickname, pData->curProfile.zNickname); + } } } @@ -371,11 +465,17 @@ profileEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curProfile.bAttitude = (UINT32) atol(pData->szCharData); } - - else if(strcmp(name, "bPersonalityTrait") == 0) + // SANDRO - added Character Trait + else if(strcmp(name, "bCharacterTrait") == 0) { pData->curElement = ELEMENT; - pData->curProfile.bPersonalityTrait = (UINT32) atol(pData->szCharData); + pData->curProfile.bCharacterTrait = (UINT32) atol(pData->szCharData); + } + + else if(strcmp(name, "bDisability") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bDisability = (UINT32) atol(pData->szCharData); } else if(strcmp(name, "ubNeedForSleep") == 0) @@ -473,19 +573,172 @@ profileEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curProfile.bEvolution = (UINT32) atol(pData->szCharData); } - - else if(strcmp(name, "bSkillTrait") == 0) + //////////////////////////////////////////////////////////////////////////// + // SANDRO was here - messed this a bit + else if(strcmp(name, "bOldSkillTrait") == 0) { pData->curElement = ELEMENT; - pData->curProfile.bSkillTrait = (UINT32) atol(pData->szCharData); + pData->curProfile.bOldSkillTrait = (UINT32) atol(pData->szCharData); } - else if(strcmp(name, "bSkillTrait2") == 0) + else if(strcmp(name, "bOldSkillTrait2") == 0) { pData->curElement = ELEMENT; - pData->curProfile.bSkillTrait2 = (UINT32) atol(pData->szCharData); + pData->curProfile.bOldSkillTrait2 = (UINT32) atol(pData->szCharData); } + else if(strcmp(name, "bNewSkillTrait1") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait1 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait2") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait2 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait3") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait3 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait4") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait4 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait5") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait5 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait6") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait6 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait7") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait7 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait8") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait8 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait9") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait9 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait10") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait10 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait11") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait11 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait12") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait12 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait13") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait13 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait14") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait14 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait15") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait15 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait16") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait16 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait17") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait17 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait18") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait18 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait19") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait19 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait20") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait20 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait21") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait21 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait22") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait22 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait23") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait23 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait24") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait24 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait25") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait25 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait26") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait26 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait27") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait27 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait28") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait28 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait29") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait29 = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "bNewSkillTrait30") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bNewSkillTrait30 = (UINT32) atol(pData->szCharData); + } + //////////////////////////////////////////////////////////////////////////// + else if(strcmp(name, "bBuddy1") == 0) { pData->curElement = ELEMENT; @@ -686,6 +939,44 @@ profileEndElementHandle(void *userData, const XML_Char *name) // Sets new index for writing. pData->curIndex = (UINT32) atol(pData->szCharData); } + + else if(strcmp(name, "Type") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.Type = (UINT32) atol(pData->szCharData); + } + + else if(strcmp(name, "sSectorX") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.sSectorX = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "sSectorY") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.sSectorY = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "sSectorZ") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bSectorZ = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "ubCivilianGroup") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.ubCivilianGroup = (UINT8) atol(pData->szCharData); + } + else if(strcmp(name, "bTown") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bTown = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "bTownAttachment") == 0) + { + pData->curElement = ELEMENT; + pData->curProfile.bTownAttachment = (INT8) atol(pData->szCharData); + } + pData->maxReadDepth--; } @@ -696,7 +987,7 @@ profileEndElementHandle(void *userData, const XML_Char *name) -BOOLEAN ReadInMercProfiles(STR fileName) +BOOLEAN ReadInMercProfiles(STR fileName, BOOLEAN localizedVersion) { HWFILE hFile; UINT32 uiBytesRead; @@ -706,12 +997,13 @@ BOOLEAN ReadInMercProfiles(STR fileName) profileParseData pData; + MercProfiles_TextOnly = localizedVersion; DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading MercProfiles.xml" ); // Open merges file hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); if ( !hFile ) - return( FALSE ); + return( localizedVersion ); uiFSize = FileGetSize(hFile); lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); @@ -778,6 +1070,44 @@ BOOLEAN WriteMercProfiles() FilePrintf(hFile,"\t\r\n"); FilePrintf(hFile,"\t\t%d\r\n", cnt); + + if (cnt >= 0 && cnt < 40 ) + { + FilePrintf(hFile,"\t\t1\r\n"); + } + else if (cnt >= 40 && cnt < 51 ) + { + FilePrintf(hFile,"\t\t2\r\n"); + } + else if ( cnt >= FIRST_RPC && cnt < FIRST_NPC ) + { + FilePrintf(hFile,"\t\t3\r\n"); + } + else if ( cnt >= FIRST_NPC && cnt < 160 ) + { + FilePrintf(hFile,"\t\t4\r\n"); + } + else if ( cnt == 169 ) + { + FilePrintf(hFile,"\t\t4\r\n"); + } + else if ( cnt == 165 || cnt == 166 || cnt == 167 || cnt == 168 ) + { + FilePrintf(hFile,"\t\t2\r\n"); + } + else if ( cnt == 51 || cnt == 52 || cnt == 53 || cnt == 54 || cnt == 55 || cnt == 56 ) + { + FilePrintf(hFile,"\t\t6\r\n"); + } + else if ( cnt == 160 || cnt == 161 || cnt == 162 || cnt == 163 || cnt == 164 ) + { + FilePrintf(hFile,"\t\t5\r\n"); + } + else + { + FilePrintf(hFile,"\t\t0\r\n"); + } + ////////////////////////////// // Write Character Name @@ -1117,7 +1447,9 @@ BOOLEAN WriteMercProfiles() FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].uiBodyTypeSubFlags); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bAttitude); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bPersonalityTrait); + // Added by SANDRO + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bCharacterTrait); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bDisability); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].ubNeedForSleep); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bReputationTolerance); @@ -1136,8 +1468,30 @@ BOOLEAN WriteMercProfiles() FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bMechanical); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bExpLevel); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bEvolution); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTrait); - FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTrait2); + //////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - old/new traits + if (gGameOptions.fNewTraitSystem) + { + FilePrintf(hFile,"\t\t%d\r\n", 0); + FilePrintf(hFile,"\t\t%d\r\n", 0); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTraits[0]); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTraits[1]); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTraits[2]); + for ( INT8 bCnt2 = 3; bCnt2 < 30; bCnt2++ ) + { + if ( gMercProfiles[ cnt ].bSkillTraits[ bCnt2 ] > 0 ) + FilePrintf(hFile,"\t\t%d\r\n", (bCnt2+1), gMercProfiles[ cnt ].bSkillTraits[bCnt2], (bCnt2+1)); + } + } + else + { + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTraits[0]); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSkillTraits[1]); + FilePrintf(hFile,"\t\t%d\r\n", 0); + FilePrintf(hFile,"\t\t%d\r\n", 0); + FilePrintf(hFile,"\t\t%d\r\n", 0); + } + //////////////////////////////////////////////////////////////////////////////////////////// FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bBuddy[0]); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bBuddy[1]); @@ -1178,6 +1532,14 @@ BOOLEAN WriteMercProfiles() FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].usApproachFactor[1]); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].usApproachFactor[2]); FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].usApproachFactor[3]); + + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].sSectorX); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].sSectorY); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bSectorZ); + + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].ubCivilianGroup); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bTown); + FilePrintf(hFile,"\t\t%d\r\n", gMercProfiles[ cnt ].bTownAttachment); FilePrintf(hFile,"\t\r\n"); diff --git a/Tactical/XML_Qarray.cpp b/Tactical/XML_Qarray.cpp new file mode 100644 index 00000000..0e805b74 --- /dev/null +++ b/Tactical/XML_Qarray.cpp @@ -0,0 +1,258 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" + #include "qarray.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" + #include "qarray.h" +#endif + + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + QARRAY_VALUES curQarray; + QARRAY_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef qarrayParseData; + +static void XMLCALL +qarrayStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + qarrayParseData * pData = (qarrayParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "QARRAY") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + memset(pData->curArray,0,sizeof(QARRAY_VALUES)*pData->maxArraySize); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "PROFILE") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + memset(&pData->curQarray,0,sizeof(QARRAY_VALUES)); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "QuoteExpHeadShotOnly") == 0 || + strcmp(name, "QuoteExpTeamSpecific") == 0 || + strcmp(name, "QuoteExpGenderCode") == 0 || + strcmp(name, "QuoteExpGotGunOrUsedGun") == 0 || + strcmp(name, "QuoteExpPassingDislike") == 0 || + strcmp(name, "QuoteExpWitnessDeidrannaDeath") == 0 || + strcmp(name, "QuoteExpWitnessQueenBugDeath") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + + } + pData->currentDepth++; + } + + + +static void XMLCALL +qarrayCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + qarrayParseData * pData = (qarrayParseData *)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 +qarrayEndElementHandle(void *userData, const XML_Char *name) +{ + qarrayParseData * pData = (qarrayParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "QARRAY") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "PROFILE") == 0) + { + pData->curElement = ELEMENT_LIST; + + if(pData->curQarray.uiIndex < pData->maxArraySize) + { + pData->curArray[pData->curQarray.uiIndex] = pData->curQarray; + } + + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpHeadShotOnly") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpHeadShotOnly = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpTeamSpecific") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpTeamSpecific = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpGenderCode") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpGenderCode = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpGotGunOrUsedGun") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpGotGunOrUsedGun = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpPassingDislike") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpPassingDislike = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpWitnessDeidrannaDeath") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpWitnessDeidrannaDeath = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "QuoteExpWitnessQueenBugDeath") == 0) + { + pData->curElement = ELEMENT; + pData->curQarray.QuoteExpWitnessQueenBugDeath = (BOOLEAN) atol(pData->szCharData); + } + + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + +BOOLEAN ReadInQarray(QARRAY_VALUES *pQarray, STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + qarrayParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading Qarray.xml" ); + + + // Open 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, qarrayStartElementHandle, qarrayEndElementHandle); + XML_SetCharacterDataHandler(parser, qarrayCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + pData.curArray = pQarray; + pData.maxArraySize = NUM_PROFILES; + + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in Quotearray.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + + + +BOOLEAN WriteQarray(QARRAY_VALUES *pQarray, STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < NUM_PROFILES;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpHeadShotOnly); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpTeamSpecific); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpGenderCode); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpGotGunOrUsedGun); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpPassingDislike); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpWitnessQueenBugDeath); + FilePrintf(hFile,"\t\t%d\r\n", pQarray[cnt].QuoteExpWitnessDeidrannaDeath); + + + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} diff --git a/Tactical/XML_RPCFacesSmall.cpp b/Tactical/XML_RPCFacesSmall.cpp new file mode 100644 index 00000000..b0b3946b --- /dev/null +++ b/Tactical/XML_RPCFacesSmall.cpp @@ -0,0 +1,238 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "faces.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + RPC_SMALL_FACE_VALUES curSmallFaces; + RPC_SMALL_FACE_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef smallFacesParseData; + +static void XMLCALL +smallFacesStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + smallFacesParseData * pData = (smallFacesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "SMALLFACE") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + memset(pData->curArray,0,sizeof(RPC_SMALL_FACE_VALUES)*pData->maxArraySize); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "FACE") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + memset(&pData->curSmallFaces,0,sizeof(RPC_SMALL_FACE_VALUES)); + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "FaceIndex") == 0 || + strcmp(name, "EyesX") == 0 || + strcmp(name, "EyesY") == 0 || + strcmp(name, "MouthX") == 0 || + strcmp(name, "MouthY") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +smallFacesCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + smallFacesParseData * pData = (smallFacesParseData *)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 +smallFacesEndElementHandle(void *userData, const XML_Char *name) +{ + smallFacesParseData * pData = (smallFacesParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "SMALLFACE") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "FACE") == 0) + { + pData->curElement = ELEMENT_LIST; + + if(pData->curSmallFaces.uiIndex < pData->maxArraySize) + { + pData->curArray[pData->curSmallFaces.uiIndex] = pData->curSmallFaces; //write the small faces into the table + } + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curSmallFaces.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "FaceIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curSmallFaces.FaceIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "EyesX") == 0) + { + pData->curElement = ELEMENT; + pData->curSmallFaces.bEyesX = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "EyesY") == 0) + { + pData->curElement = ELEMENT; + pData->curSmallFaces.bEyesY = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "MouthX") == 0) + { + pData->curElement = ELEMENT; + pData->curSmallFaces.bMouthX = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "MouthY") == 0) + { + pData->curElement = ELEMENT; + pData->curSmallFaces.bMouthY = (INT8) atol(pData->szCharData); + } + + + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + + + +BOOLEAN ReadInSmallFacesStats(RPC_SMALL_FACE_VALUES *pSmallFaces, STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + smallFacesParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading SmallFaces.xml" ); + + // Open 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, smallFacesStartElementHandle, smallFacesEndElementHandle); + XML_SetCharacterDataHandler(parser, smallFacesCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + pData.curArray = pSmallFaces; + pData.maxArraySize = 200; + + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in RPCFacesSmall.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + +BOOLEAN WriteSmallFacesStats(RPC_SMALL_FACE_VALUES *pSmallFaces, STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < 201;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t%d\r\n", pSmallFaces[cnt].FaceIndex); + FilePrintf(hFile,"\t\t%d\r\n", pSmallFaces[cnt].bEyesX); + FilePrintf(hFile,"\t\t%d\r\n", pSmallFaces[cnt].bEyesY); + FilePrintf(hFile,"\t\t%d\r\n", pSmallFaces[cnt].bMouthX); + FilePrintf(hFile,"\t\t%d\r\n", pSmallFaces[cnt].bMouthY); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} \ No newline at end of file diff --git a/Tactical/XML_RandomStats.cpp b/Tactical/XML_RandomStats.cpp new file mode 100644 index 00000000..75a9332a --- /dev/null +++ b/Tactical/XML_RandomStats.cpp @@ -0,0 +1,304 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" +#endif + +#include "soldier profile type.h" +#include "Soldier Profile.h" +#include "Random.h" + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + RANDOM_STATS_VALUES curRandomStats; + RANDOM_STATS_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef RandomStatsParseData; + +BOOLEAN RandomStats_TextOnly; + +static void XMLCALL +RandomStatsStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + RandomStatsParseData * pData = (RandomStatsParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "RANDOM_STATS") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "PROFIL") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + ( strcmp(name, "uiIndex") == 0 || + strcmp(name, "Enabled") == 0 || + strcmp(name, "BaseAttribute") == 0 || + strcmp(name, "ExpLevel") == 0 || + strcmp(name, "RandomLife") == 0 || + strcmp(name, "RandomAgility") == 0 || + strcmp(name, "RandomLeadership") == 0 || + strcmp(name, "RandomDexterity") == 0 || + strcmp(name, "RandomWisdom") == 0 || + strcmp(name, "RandomMarksmanship") == 0 || + strcmp(name, "RandomMedical") == 0 || + strcmp(name, "RandomMechanical") == 0 || + strcmp(name, "RandomExplosive") == 0 || + strcmp(name, "RandomScientific") == 0 || + strcmp(name, "RandomStrength") == 0 ) ) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +RandomStatsCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + RandomStatsParseData * pData = (RandomStatsParseData *)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 +RandomStatsEndElementHandle(void *userData, const XML_Char *name) +{ + RandomStatsParseData * pData = (RandomStatsParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "RANDOM_STATS") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "PROFIL") == 0) + { + pData->curElement = ELEMENT_LIST; + + gRandomStatsValue[pData->curRandomStats.uiIndex].Enabled = pData->curRandomStats.Enabled; + gRandomStatsValue[pData->curRandomStats.uiIndex].BaseAttribute = pData->curRandomStats.BaseAttribute; + gRandomStatsValue[pData->curRandomStats.uiIndex].ExpLevel = pData->curRandomStats.ExpLevel; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomLife = pData->curRandomStats.RandomLife; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomStrength = pData->curRandomStats.RandomStrength; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomAgility = pData->curRandomStats.RandomAgility; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomLeadership = pData->curRandomStats.RandomLeadership; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomDexterity = pData->curRandomStats.RandomDexterity; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomWisdom = pData->curRandomStats.RandomWisdom; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomMarksmanship = pData->curRandomStats.RandomMarksmanship; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomMedical = pData->curRandomStats.RandomMedical; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomMechanical = pData->curRandomStats.RandomMechanical; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomExplosive = pData->curRandomStats.RandomExplosive; + gRandomStatsValue[pData->curRandomStats.uiIndex].RandomScientific = pData->curRandomStats.RandomScientific; + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Enabled") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.Enabled = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "BaseAttribute") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.BaseAttribute = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "ExpLevel") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.ExpLevel = (INT8) atol(pData->szCharData); + } + else if(strcmp(name, "RandomLife") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomLife = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomAgility") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomAgility = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomLeadership") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomLeadership = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomDexterity") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomDexterity = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomWisdom") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomWisdom = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomMarksmanship") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomMarksmanship = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomMedical") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomMedical = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomMechanical") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomMechanical = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomExplosive") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomExplosive = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomScientific") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomScientific = (BOOLEAN) atol(pData->szCharData); + } + else if(strcmp(name, "RandomStrength") == 0) + { + pData->curElement = ELEMENT; + pData->curRandomStats.RandomStrength = (BOOLEAN) atol(pData->szCharData); + } + + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInRandomStats(STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + RandomStatsParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading RandomStats.xml" ); + +// RandomStats_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + //if ( !hFile ) + // return( localizedVersion ); + + 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, RandomStatsStartElementHandle, RandomStatsEndElementHandle); + XML_SetCharacterDataHandler(parser, RandomStatsCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in RandomStats.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + +BOOLEAN WriteRandomStats( STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for ( cnt = 0; cnt < NUM_PROFILES; cnt++ ) + { + FilePrintf(hFile,"\t\r\n"); + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].Enabled); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].BaseAttribute); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].ExpLevel); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomLife); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomAgility); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomLeadership); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomDexterity); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomWisdom); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomMarksmanship); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomMedical); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomMechanical); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomExplosive); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomScientific); + FilePrintf(hFile,"\t\t%d\r\n",gRandomStatsValue[cnt].RandomStrength); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} \ No newline at end of file diff --git a/Tactical/XML_SoundProfile.cpp b/Tactical/XML_SoundProfile.cpp new file mode 100644 index 00000000..e6fd46bc --- /dev/null +++ b/Tactical/XML_SoundProfile.cpp @@ -0,0 +1,200 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" +#endif + +#include "Dialogue Control.h" +#include "soldier profile type.h" + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + SOUND_PROFILE_VALUES curSoundProfile; + SOUND_PROFILE_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef SoundProfileParseData; + +static void XMLCALL +SoundProfileStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + SoundProfileParseData * pData = (SoundProfileParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "SOUNDPROFILE") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "PROFILE") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "EnabledSound") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +SoundProfileCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + SoundProfileParseData * pData = (SoundProfileParseData *)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 +SoundProfileEndElementHandle(void *userData, const XML_Char *name) +{ + SoundProfileParseData * pData = (SoundProfileParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "SOUNDPROFILE") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "PROFILE") == 0) + { + pData->curElement = ELEMENT_LIST; + + gSoundProfileValue[pData->curSoundProfile.uiIndex].EnabledSound = pData->curSoundProfile.EnabledSound; + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curSoundProfile.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "EnabledSound") == 0) + { + pData->curElement = ELEMENT; + pData->curSoundProfile.EnabledSound = (BOOLEAN) atol(pData->szCharData); + } + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + + + +BOOLEAN ReadInSoundProfile(STR fileName) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + SoundProfileParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading SoundsProfiles.xml" ); + + // Open 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, SoundProfileStartElementHandle, SoundProfileEndElementHandle); + XML_SetCharacterDataHandler(parser, SoundProfileCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in SoundsProfiles.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + +BOOLEAN WriteSoundProfile(STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0;cnt < NUM_PROFILES;cnt++) + { + + FilePrintf(hFile,"\t\r\n"); + + FilePrintf(hFile,"\t\t%d\r\n", cnt); + FilePrintf(hFile,"\t\t1\r\n"); + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} \ No newline at end of file diff --git a/Tactical/bullets.cpp b/Tactical/bullets.cpp index 1542fb60..2b83f7b1 100644 --- a/Tactical/bullets.cpp +++ b/Tactical/bullets.cpp @@ -29,8 +29,6 @@ #include "lighting.h" #include "Buildings.h" #endif -#include "test_space.h" - // Defines #define NUM_BULLET_SLOTS 50 @@ -366,7 +364,7 @@ void UpdateBullets( ) pNode->sRelativeZ = (INT16) CONVERT_HEIGHTUNITS_TO_PIXELS( FIXEDPT_TO_INT32( gBullets[ uiCount ].qCurrZ ) ); //afp-start - add new tail /tracer - if (gGameExternalOptions.gbBulletTracer) + if (gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS]) { if ((lastX != 0) || (lastY != 0)) { @@ -413,15 +411,15 @@ void UpdateBullets( ) //afp-end // Display shadow // afp - no more shadow if tracer enabled - if (!gGameExternalOptions.gbBulletTracer) + if (!gGameSettings.fOptions[TOPTION_ALTERNATE_BULLET_GRAPHICS]) { - pNode = AddStructToTail( gBullets[ uiCount ].sGridNo, BULLETTILE2 ); - pNode->ubShadeLevel=DEFAULT_SHADE_LEVEL; - pNode->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL; - pNode->uiFlags |= ( LEVELNODE_USEABSOLUTEPOS | LEVELNODE_IGNOREHEIGHT ); - pNode->sRelativeX = (INT16) FIXEDPT_TO_INT32( gBullets[ uiCount ].qCurrX ); - pNode->sRelativeY = (INT16) FIXEDPT_TO_INT32( gBullets[ uiCount ].qCurrY ); - pNode->sRelativeZ = (INT16)gpWorldLevelData[ gBullets[ uiCount ].sGridNo ].sHeight; + pNode = AddStructToTail( gBullets[ uiCount ].sGridNo, BULLETTILE2 ); + pNode->ubShadeLevel=DEFAULT_SHADE_LEVEL; + pNode->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL; + pNode->uiFlags |= ( LEVELNODE_USEABSOLUTEPOS | LEVELNODE_IGNOREHEIGHT ); + pNode->sRelativeX = (INT16) FIXEDPT_TO_INT32( gBullets[ uiCount ].qCurrX ); + pNode->sRelativeY = (INT16) FIXEDPT_TO_INT32( gBullets[ uiCount ].qCurrY ); + pNode->sRelativeZ = (INT16)gpWorldLevelData[ gBullets[ uiCount ].sGridNo ].sHeight; } } } diff --git a/Tactical/faces.h b/Tactical/faces.h index 184cdcfe..902df31e 100644 --- a/Tactical/faces.h +++ b/Tactical/faces.h @@ -17,6 +17,31 @@ struct audio_gap struct audio_gap *pNext; }; +typedef struct +{ + BOOLEAN gCamoface; + BOOLEAN gUrbanCamoface; + BOOLEAN gDesertCamoface; + BOOLEAN gSnowCamoface; +} CAMO_FACE; + +extern CAMO_FACE gCamoFace[255]; + + +typedef struct +{ + INT8 bEyesX; + INT8 bEyesY; + INT8 bMouthX; + INT8 bMouthY; + UINT16 uiIndex; // add + UINT16 FaceIndex; //add + +} RPC_SMALL_FACE_VALUES; + +extern RPC_SMALL_FACE_VALUES gRPCSmallFaceValues[200]; +extern UINT8 gubRPCSmallFaceProfileNum[200]; + #define FACE_AUTO_DISPLAY_BUFFER 0xFFFFF000 #define FACE_AUTO_RESTORE_BUFFER 0xFFFFFF00 #define FACE_NO_RESTORE_BUFFER 0xFFFFFFF0 @@ -240,7 +265,9 @@ BOOLEAN ExternRenderFaceFromSoldier( UINT32 uiBuffer, UINT8 ubSoldierID, INT16 s - +//legion2 Jazz +extern void FacesSmalllegion (); +extern void RecountFaces(void); diff --git a/Tactical/opplist.cpp b/Tactical/opplist.cpp index b73e0a5d..94c6127e 100644 --- a/Tactical/opplist.cpp +++ b/Tactical/opplist.cpp @@ -327,7 +327,17 @@ INT16 AdjustMaxSightRangeForEnvEffects( SOLDIERTYPE *pSoldier, INT8 bLightLevel, { //sNewDist = sNewDist * 70 / 100; //rain - sNewDist = sNewDist * ( 100 - min( gGameExternalOptions.ubVisDistDecreasePerRainIntensity * gbCurrentRainIntensity, 100) ) / 100; + //Added a feature reducing weather penalty for ranger trait - SANDRO + INT16 sWeatherPenalty = 0; // percent vision reduction 0-100% + sWeatherPenalty = min( (max( 0, (gGameExternalOptions.ubVisDistDecreasePerRainIntensity * gbCurrentRainIntensity))), 100) ; + if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, RANGER_NT ) ) + { + sWeatherPenalty = (sWeatherPenalty * ( 100 - (gSkillTraitValues.ubRAWeatherPenaltiesReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT ))) ) / 100; + sWeatherPenalty = min( (max( 0, sWeatherPenalty)), 100 ); // keep it in 0-100 range + } + + sNewDist = (sNewDist * ( 100 - sWeatherPenalty )) / 100; + //end rain } @@ -487,7 +497,8 @@ void HandleBestSightingPositionInRealtime( void ) if (gubBestToMakeSighting[ 1 ] == NOBODY) { // The_Bob - real time sneaking code 01/06/09 // if real time sneaking conditions are met... - if (gGameExternalOptions.fAllowRealTimeSneak && MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == OUR_TEAM && NobodyAlerted() ) + // this is now in the preferences window - SANDRO + if (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] && MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == OUR_TEAM && NobodyAlerted() ) { // get rid of the item under cursor (we gotta react FAST) CancelItemPointer(); @@ -870,11 +881,15 @@ void HandleSight(SOLDIERTYPE *pSoldier, UINT8 ubSightFlags) { // update our team's public knowledge RadioSightings(pSoldier,EVERYBODY, pSoldier->bTeam ); - +/* comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM); -#endif - +#endif*/ +//ddd{ +if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) +RadioSightings(pSoldier,EVERYBODY, MILITIA_TEAM); + +//ddd} // if it's our local player's merc if (PTR_OURTEAM) // revealing roofs and looking for items handled here, too @@ -1049,6 +1064,7 @@ INT16 TeamNoLongerSeesMan( UINT8 ubTeam, SOLDIERTYPE *pOpponent, UINT8 ubExclude return(FALSE); // that's all I need to know, get out of here } +/* comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if ( bIteration == 0 ) { @@ -1064,6 +1080,26 @@ INT16 TeamNoLongerSeesMan( UINT8 ubTeam, SOLDIERTYPE *pOpponent, UINT8 ubExclude } } #endif +*/ +//ddd +if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) +{ + if ( bIteration == 0 ) + { + if ( ubTeam == gbPlayerNum && gTacticalStatus.Team[ MILITIA_TEAM ].bTeamActive ) + { + // check militia team as well + return( TeamNoLongerSeesMan( MILITIA_TEAM, pOpponent, ubExcludeID, 1 ) ); + } + else if ( ubTeam == MILITIA_TEAM && gTacticalStatus.Team[ gbPlayerNum ].bTeamActive ) + { + // check player team as well + return( TeamNoLongerSeesMan( gbPlayerNum, pOpponent, ubExcludeID, 1 ) ); + } + } + +} +//ddd // none of my friends is currently seeing the guy, so return success return(TRUE); @@ -1257,7 +1293,9 @@ INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, sDistVisible += sDistVisible * GetTotalVisionRangeBonus(pSoldier, bLightLevel) / 100; // HEADROCK HAM 3.2: Further reduce sightrange for cowering characters. - if (gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 2) + // SANDRO - this calls many sub-functions over and over, we should at least skip this for civilians and such + if ((gGameExternalOptions.ubCoweringReducesSightRange == 1 || gGameExternalOptions.ubCoweringReducesSightRange == 2) && + IS_MERC_BODY_TYPE(pSoldier) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == MILITIA_TEAM || pSoldier->bTeam == gbPlayerNum) ) { INT8 bTolerance = CalcSuppressionTolerance( pSoldier ); @@ -1272,12 +1310,19 @@ INT16 DistanceVisible( SOLDIERTYPE *pSoldier, INT8 bFacingDir, INT8 bSubjectDir, // give one step better vision for people with nightops - if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS )) + // old/new traits check - SANDRO + if (gGameOptions.fNewTraitSystem) { - sDistVisible += NightBonusScale( 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS ), bLightLevel); + if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT )) + sDistVisible += NightBonusScale( gSkillTraitValues.ubNOeSightRangeBonusInDark, bLightLevel); + } + else + { + if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT )) + sDistVisible += NightBonusScale( 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT ), bLightLevel); } // Bloodcat bonus only works above ground - else if ( pSoldier->ubBodyType == BLOODCAT && gbWorldSectorZ == 0 ) + if ( pSoldier->ubBodyType == BLOODCAT && gbWorldSectorZ == 0 ) { sDistVisible += NightBonusScale( UVGOGGLES_BONUS, bLightLevel); } @@ -1335,16 +1380,30 @@ void EndMuzzleFlash( SOLDIERTYPE * pSoldier ) SOLDIERTYPE * pOtherSoldier; pSoldier->flags.fMuzzleFlash = FALSE; - +/*comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bTeam != MILITIA_TEAM ) #else if ( pSoldier->bTeam != gbPlayerNum ) #endif + { pSoldier->bVisible = 0; // indeterminate state } +*/ +//ddd{ +if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) +{ if ( pSoldier->bTeam != gbPlayerNum && pSoldier->bTeam != MILITIA_TEAM ) + pSoldier->bVisible = 0; // indeterminate state +} +else +{ + if ( pSoldier->bTeam != gbPlayerNum ) + pSoldier->bVisible = 0; // indeterminate state +} +//ddd} + for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { pOtherSoldier = MercSlots[ uiLoop ]; @@ -1362,6 +1421,7 @@ void EndMuzzleFlash( SOLDIERTYPE * pSoldier ) } // else this person is still seen, if the looker is on our side or the militia the person should stay visible +/* comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA else if ( pOtherSoldier->bTeam == gbPlayerNum || pOtherSoldier->bTeam == MILITIA_TEAM ) #else @@ -1371,6 +1431,19 @@ void EndMuzzleFlash( SOLDIERTYPE * pSoldier ) { pSoldier->bVisible = TRUE; // yes, still seen } +*/ + //ddd{ + else if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) + { + if ( pOtherSoldier->bTeam == gbPlayerNum || pOtherSoldier->bTeam == MILITIA_TEAM ) + {pSoldier->bVisible = TRUE;} // yes, still seen + } + else + { + if ( pOtherSoldier->bTeam == gbPlayerNum ) + pSoldier->bVisible = TRUE; // yes, still seen + } + //ddd} } } } @@ -1429,15 +1502,21 @@ INT8 DecideHearing( SOLDIERTYPE * pSoldier ) bHearing = 0; - if (pSoldier->stats.bExpLevel > 3) + if (EffectiveExpLevel( pSoldier ) > 3) // SANDRO - changed to calculate effective level { bHearing++; } - if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS )) + // old/new traits check - SANDRO + if (gGameOptions.fNewTraitSystem) { - // sharper hearing generally - bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS ); + if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT )) + bHearing += gSkillTraitValues.ubNOHearingRangeBonus; + } + else + { + if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT )) + bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT ); } //bSlot = FindObj( pSoldier, EXTENDEDEAR ); @@ -1465,10 +1544,17 @@ INT8 DecideHearing( SOLDIERTYPE * pSoldier ) case 14: case 15: bHearing += 3; - if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS )) + // yet another bonus for nighttime + // old/new traits check - SANDRO + if (gGameOptions.fNewTraitSystem) { - // yet another bonus for nighttime - bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS ); + if (HAS_SKILL_TRAIT( pSoldier, NIGHT_OPS_NT )) + bHearing += gSkillTraitValues.ubNOHearingRangeBonusInDark; + } + else + { + if (HAS_SKILL_TRAIT( pSoldier, NIGHTOPS_OT )) + bHearing += 1 * NUM_SKILL_TRAITS( pSoldier, NIGHTOPS_OT ); } break; default: @@ -1707,6 +1793,7 @@ void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT *pbPublOL = SEEN_THIS_TURN; // ATE: Set visiblity to 0 +/*comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) ) #else @@ -1715,6 +1802,18 @@ void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT { pOpponent->bVisible = 0; } +*/ +//ddd{ +if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) +{ if ( (pSoldier->bTeam == gbPlayerNum || pSoldier->bTeam == MILITIA_TEAM) && !(pOpponent->bTeam == gbPlayerNum || pOpponent->bTeam == MILITIA_TEAM ) ) + pOpponent->bVisible = 0; +} +else +{ if ( pSoldier->bTeam == gbPlayerNum && pOpponent->bTeam != gbPlayerNum ) + pOpponent->bVisible = 0; +} +//ddd} + } } #ifdef TESTOPPLIST @@ -2304,7 +2403,8 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, } */ - PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); + //PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); + PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME +10, 1, MIDDLEPAN ); } else { @@ -2312,7 +2412,8 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, { if ( Random( 2 ) == 0 ) { - PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); + //PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN ); + PlayJA2Sample( BLOODCAT_ROAR, RATE_11025, MIDVOLUME + 10, 1, MIDDLEPAN ); } } } @@ -2445,8 +2546,22 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, // man is seeing an opponent AGAIN whom he has seen at least once before gbSeenOpponents[pSoldier->ubID][pOpponent->ubID] = TRUE; +//ddd{ +BOOLEAN SEE_MENT = FALSE; +if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) +{ + if ( ( PTR_OURTEAM || (pSoldier->bTeam == MILITIA_TEAM) ) && (pOpponent->bVisible <= 0)) + SEE_MENT = TRUE; +} +else +{ + if (PTR_OURTEAM && (pOpponent->bVisible <= 0)) + SEE_MENT = TRUE; +} +//ddd} +/*comm by ddd // if looker is on local team, and the enemy was invisible or "maybe" // visible just prior to this #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA @@ -2454,6 +2569,8 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, #else if (PTR_OURTEAM && (pOpponent->bVisible <= 0)) #endif +*/ +if(SEE_MENT) { // if opponent was truly invisible, not just turned off temporarily (FALSE) if (pOpponent->bVisible == -1) @@ -2608,6 +2725,7 @@ void OtherTeamsLookForMan(SOLDIERTYPE *pOpponent) //NumMessage("OtherTeamsLookForMan, guy#",oppPtr->guynum); +/* comm by ddd // if the guy we're looking for is NOT on our team AND is currently visible #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if ((pOpponent->bTeam != gbPlayerNum && pOpponent->bTeam != MILITIA_TEAM) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife) @@ -2618,7 +2736,19 @@ void OtherTeamsLookForMan(SOLDIERTYPE *pOpponent) // assume he's no longer visible, until one of our mercs sees him again pOpponent->bVisible = 0; } - +*/ +//ddd{ +if(gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) +{ + if ((pOpponent->bTeam != gbPlayerNum && pOpponent->bTeam != MILITIA_TEAM) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife) + pOpponent->bVisible = 0; +} +else +{ +if ((pOpponent->bTeam != gbPlayerNum) && (pOpponent->bVisible >= 0 && pOpponent->bVisible < 2) && pOpponent->stats.bLife) +pOpponent->bVisible = 0; +} +//ddd} #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String("OTHERTEAMSLOOKFORMAN ID %d(%S) team %d side %d",pOpponent->ubID,pOpponent->name,pOpponent->bTeam,pOpponent->bSide )); @@ -3105,11 +3235,24 @@ void BetweenTurnsVisibilityAdjustments(void) { if (pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife) { + //ddd{ + BOOLEAN SEE_MENT = FALSE; + if (gGameExternalOptions.bWeSeeWhatMilitiaSeesAndViceVersa) + {if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM) + SEE_MENT = TRUE; + } + else + { if (!PTR_OURTEAM) SEE_MENT = TRUE; + } + //ddd} +/*comm by ddd #ifdef WE_SEE_WHAT_MILITIA_SEES_AND_VICE_VERSA if (!PTR_OURTEAM && pSoldier->bTeam != MILITIA_TEAM) #else if (!PTR_OURTEAM) #endif + */ + if(SEE_MENT) { // check if anyone on our team currently sees him (exclude NOBODY) if (TeamNoLongerSeesMan(gbPlayerNum,pSoldier,NOBODY,0)) @@ -3266,6 +3409,8 @@ void SaySeenQuote( SOLDIERTYPE *pSoldier, BOOLEAN fSeenCreature, BOOLEAN fVirgin TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY ); } #else + //ddd TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY ); + if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) ) TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY ); #endif } @@ -3328,7 +3473,7 @@ void OurTeamSeesSomeone( SOLDIERTYPE * pSoldier, INT8 bNumReRevealed, INT8 bNumN if ( ( gTacticalStatus.uiFlags & INCOMBAT ) ) { // If we are NOT in any music mode... - if ( gubMusicMode == MUSIC_NONE ) + if ( GetMusicMode() == MUSIC_NONE ) { SetMusicMode( MUSIC_TACTICAL_BATTLE ); } @@ -4309,7 +4454,9 @@ void DebugSoldierPage3( ) ubLine++; // OPIONION OF SELECTED MERC - if ( gusSelectedSoldier != NOBODY && ( MercPtrs[ gusSelectedSoldier ]->ubProfile < FIRST_NPC ) && pSoldier->ubProfile != NO_PROFILE ) + //if ( gusSelectedSoldier != NOBODY && ( MercPtrs[ gusSelectedSoldier ]->ubProfile < FIRST_NPC ) && pSoldier->ubProfile != NO_PROFILE ) + //new profiles by Jazz + if ( gusSelectedSoldier != NOBODY && ( gProfilesIMP[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesRPC[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesAIM[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile || gProfilesMERC[MercPtrs[ gusSelectedSoldier ]->ubProfile].ProfilId == MercPtrs[ gusSelectedSoldier ]->ubProfile ) && pSoldier->ubProfile != NO_PROFILE ) { SetFontShade(LARGEFONT1, FONT_SHADE_GREEN); gprintf( 0, LINE_HEIGHT * ubLine, L"NPC Opinion:"); @@ -4447,12 +4594,13 @@ void WriteQuantityAndAttachments( OBJECTTYPE *pObject, INT32 yp ) return; //Build attachment string fAttachments = FALSE; - if( (*pObject)[0]->attachments.empty() == false ) + if( (*pObject)[0]->AttachmentListSize() > 0 ) { fAttachments = TRUE; swprintf( szAttach, L"(" ); for (attachmentList::iterator iter = (*pObject)[0]->attachments.begin(); iter != (*pObject)[0]->attachments.end(); ++iter) { - AppendAttachmentCode( iter->usItem, szAttach ); + if(iter->exists()) + AppendAttachmentCode( iter->usItem, szAttach ); } wcscat( szAttach, L" )" ); } @@ -4519,7 +4667,7 @@ void DebugSoldierPage4( ) SetFontShade(LARGEFONT1, FONT_SHADE_GREEN); gprintf( 0, LINE_HEIGHT * ubLine, L"Exp. Level:"); SetFontShade(LARGEFONT1, FONT_SHADE_NEUTRAL); - gprintf( 150, LINE_HEIGHT * ubLine, L"%d", pSoldier->stats.bExpLevel ); + gprintf( 150, LINE_HEIGHT * ubLine, L"%d ( %d )", pSoldier->stats.bExpLevel, EffectiveExpLevel(pSoldier) ); // SANDRO - added effective level calc switch( pSoldier->ubSoldierClass ) { case SOLDIER_CLASS_ADMINISTRATOR: gprintf( 320, LINE_HEIGHT * ubLine, L"(Administrator)" ); break; @@ -4998,16 +5146,23 @@ UINT8 MovementNoise( SOLDIERTYPE *pSoldier ) return( (UINT8) (MAX_MOVEMENT_NOISE - PreRandom( 2 )) ); } - iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveDexterity( pSoldier ) * 4) / 10); // 24-100 + // CHANGED BY SANDRO - LET'S MAKE THE STEALTH BASED ON AGILITY LIKE IT SHOULD BE + //iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveDexterity( pSoldier ) * 4) / 10); // 24-100 + iStealthSkill = 20 + 4 * EffectiveExpLevel( pSoldier ) + ((EffectiveAgility( pSoldier ) * 4) / 10); // 24-100 // big bonus for those "extra stealthy" mercs if ( pSoldier->ubBodyType == BLOODCAT ) { iStealthSkill += 50; } - else if (HAS_SKILL_TRAIT( pSoldier, STEALTHY )) + // SANDRO - new/old traits + else if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT )) { - iStealthSkill += 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY ); + iStealthSkill += gSkillTraitValues.ubSTBonusToMoveQuietly; + } + else if ( !gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, STEALTHY_OT )) + { + iStealthSkill += 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT ); } if ( GetWornStealth(pSoldier) > 0 ) @@ -5618,9 +5773,18 @@ void ProcessNoise(UINT8 ubNoiseMaker, INT32 sGridNo, INT8 bLevel, UINT8 ubTerrTy case WARDEN: case GENERAL: case SERGEANT: - case CONRAD: - // ignore soldier team - continue; + case CONRAD: + // WANNE: This fixes the bug, that Conrad, when he is in OUR team, cannot interrupt enemies!!! + if (pSoldier->bTeam == OUR_TEAM) + { + // WANNE: Allow interrupt, if one of those guys is in OUR team! + break; + } + else + { + // No interrupt for those 4 guys + continue; + } default: break; } @@ -5865,6 +6029,13 @@ UINT8 CalcEffVolume(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT8 ubN // effective volume fades over distance beyond 1 tile away iEffVolume -= (iDistance - 1); + //ddd{ ;) + if(gGameExternalOptions.bLazyCivilians) + if (pSoldier->bTeam == CIV_TEAM && pSoldier->ubBodyType != CROW ) + if (pSoldier->ubCivilianGroup == 0 && pSoldier->ubProfile == NO_PROFILE) + iEffVolume =-100; + //ddd} + /* if (pSoldier->bTeam == CIV_TEAM && pSoldier->ubBodyType != CROW ) { diff --git a/Tactical/opplist.h b/Tactical/opplist.h index c1c9a09a..95559a88 100644 --- a/Tactical/opplist.h +++ b/Tactical/opplist.h @@ -79,6 +79,7 @@ extern INT32 gsWatchedLoc[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; extern INT8 gbWatchedLocLevel[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; extern UINT8 gubWatchedLocPoints[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; extern BOOLEAN gfWatchedLocReset[ TOTAL_SOLDIERS ][ NUM_WATCHED_LOCS ]; +extern INT8 STRAIGHT; #define BEST_SIGHTING_ARRAY_SIZE 6 #define BEST_SIGHTING_ARRAY_SIZE_ALL_TEAMS_LOOK_FOR_ALL 6 diff --git a/Tactical/qarray.h b/Tactical/qarray.h index 625315d1..58fdbc36 100644 --- a/Tactical/qarray.h +++ b/Tactical/qarray.h @@ -11,6 +11,21 @@ extern BOOLEAN QuoteExp_PassingDislike[NUM_PROFILES]; extern BOOLEAN QuoteExp_WitnessQueenBugDeath[NUM_PROFILES]; extern BOOLEAN QuoteExp_WitnessDeidrannaDeath[NUM_PROFILES]; +typedef struct +{ + UINT16 uiIndex; + BOOLEAN QuoteExpHeadShotOnly; + BOOLEAN QuoteExpTeamSpecific; + BOOLEAN QuoteExpGenderCode; + BOOLEAN QuoteExpGotGunOrUsedGun; + BOOLEAN QuoteExpPassingDislike; + BOOLEAN QuoteExpWitnessQueenBugDeath; + BOOLEAN QuoteExpWitnessDeidrannaDeath; + +} QARRAY_VALUES; + +extern QARRAY_VALUES QuoteExp[NUM_PROFILES]; + #endif \ No newline at end of file diff --git a/Tactical/soldier profile type.h b/Tactical/soldier profile type.h index 89571ca6..480bf111 100644 --- a/Tactical/soldier profile type.h +++ b/Tactical/soldier profile type.h @@ -4,7 +4,9 @@ #include "overhead types.h" #include "Soldier Control.h" -#define NUM_PROFILES 170 +#define NUM_PROFILES 255 //170 new profiles by Jazz +//tais: maximum amount of starting gear kits +#define NUM_MERCSTARTINGGEAR_KITS 5 #define FIRST_RPC 57 #define FIRST_NPC 75 @@ -92,34 +94,100 @@ inline bool OKToCheckOpinion(int profileNumber) { return (profileNumber < DontUseMeDirectly::MaxIDToCheckForMorale); } - +// SANDRO - replaced this list to represent the old traits only typedef enum { - NO_SKILLTRAIT = 0, - LOCKPICKING, - HANDTOHAND, - ELECTRONICS, - NIGHTOPS, - THROWING, - TEACHING, - HEAVY_WEAPS, - AUTO_WEAPS, - STEALTHY, - AMBIDEXT, - THIEF, - MARTIALARTS, - KNIFING, - PROF_SNIPER, - CAMOUFLAGED, - CAMOUFLAGED_URBAN, - CAMOUFLAGED_DESERT, - CAMOUFLAGED_SNOW, - NUM_SKILLTRAITS + NO_SKILLTRAIT_OT = 0, + LOCKPICKING_OT, + HANDTOHAND_OT, + ELECTRONICS_OT, + NIGHTOPS_OT, + THROWING_OT, + TEACHING_OT, + HEAVY_WEAPS_OT, + AUTO_WEAPS_OT, + STEALTHY_OT, + AMBIDEXT_OT, + THIEF_OT, + MARTIALARTS_OT, + KNIFING_OT, + PROF_SNIPER_OT, + CAMOUFLAGED_OT, + // SANDRO - I dared to remove these for it is really useless, + // with the camo removing/repainting feature you only need the basic camouflage trait anyway + //CAMOUFLAGED_URBAN, + //CAMOUFLAGED_DESERT, + //CAMOUFLAGED_SNOW, + EXPERT, + NUM_SKILLTRAITS_OT } SkillTrait; +////////////////////////////////////////////////////////////////////// +// SANDRO - the list for new traits typedef enum { - NO_PERSONALITYTRAIT = 0, + NO_SKILLTRAIT_NT = 0, + // MAJOR TRAITS + AUTO_WEAPONS_NT, // 1 + HEAVY_WEAPONS_NT, // 2 + SNIPER_NT, // 3 + RANGER_NT, // 4 + GUNSLINGER_NT, // 5 + MARTIAL_ARTS_NT, // 6 + SQUADLEADER_NT, // 7 + TECHNICIAN_NT, // 8 + DOCTOR_NT, // 9 + // MINOR TRAITS + AMBIDEXTROUS_NT, // 10 + MELEE_NT, // 11 + THROWING_NT, // 12 + NIGHT_OPS_NT, // 13 + STEALTHY_NT, // 14 + ATHLETICS_NT, // 15 + BODYBUILDING_NT, // 16 + DEMOLITIONS_NT, // 17 + TEACHING_NT, // 18 + SCOUTING_NT, // 19 + NUM_SKILLTRAITS_NT +} SkillTraitNew; + +#define NUM_MAJOR_TRAITS 9 +#define NUM_MINOR_TRAITS 10 + +// SANDRO - new set of character traits +typedef enum +{ + CHAR_TRAIT_NORMAL = 0, + CHAR_TRAIT_SOCIABLE, + CHAR_TRAIT_LONER, + CHAR_TRAIT_OPTIMIST, + CHAR_TRAIT_ASSERTIVE, + CHAR_TRAIT_INTELLECTUAL, + CHAR_TRAIT_PRIMITIVE, + CHAR_TRAIT_AGGRESSIVE, + CHAR_TRAIT_PHLEGMATIC, + CHAR_TRAIT_DAUNTLESS, + CHAR_TRAIT_PACIFIST, + CHAR_TRAIT_MALICIOUS, + CHAR_TRAIT_SHOWOFF, + NUM_CHAR_TRAITS +} CharacterTraits; + +// SANDRO - appearances +typedef enum +{ + APPEARANCE_AVARAGE = 0, + APPEARANCE_UGLY, + APPEARANCE_HOMELY, + APPEARANCE_ATTRACTIVE, + APPEARANCE_BABE, + NUM_APPEARANCES +} Appearances; +////////////////////////////////////////////////////////////////////// + +typedef enum +{ + NO_DISABILITY = 0, HEAT_INTOLERANT, NERVOUS, CLAUSTROPHOBIC, @@ -127,7 +195,7 @@ typedef enum FEAR_OF_INSECTS, FORGETFUL, PSYCHO, - NUM_PERSONALITYTRAIT + NUM_DISABILITIES } PersonalityTrait; #define NERVOUS_RADIUS 10 @@ -176,6 +244,73 @@ typedef enum{ #define BUDDY_OPINION +25 #define HATED_OPINION -25 +/////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - Let's add a nice new struct for records, as there are just too many of them +class STRUCT_Records +{ +public: + + UINT16 usKillsElites; + UINT16 usKillsRegulars; + UINT16 usKillsAdmins; + UINT16 usKillsHostiles; + UINT16 usKillsCreatures; + UINT16 usKillsTanks; + UINT16 usKillsOthers; + + UINT16 usAssistsMercs; + UINT16 usAssistsMilitia; + UINT16 usAssistsOthers; + + UINT16 usShotsFired; + UINT16 usMissilesLaunched; + UINT16 usGrenadesThrown; + UINT16 usKnivesThrown; + UINT16 usBladeAttacks; + UINT16 usHtHAttacks; + UINT16 usShotsHit; + + UINT16 usBattlesTactical; + UINT16 usBattlesAutoresolve; + UINT16 usBattlesRetreated; + UINT16 usAmbushesExperienced; + UINT16 usLargestBattleFought; + + UINT16 usTimesWoundedShot; + UINT16 usTimesWoundedStabbed; + UINT16 usTimesWoundedPunched; + UINT16 usTimesWoundedBlasted; + UINT16 usTimesStatDamaged; + UINT16 usTimesSurgeryUndergoed; + UINT16 usFacilityAccidents; + + UINT16 usLocksPicked; + UINT16 usLocksBreached; + UINT16 usTrapsRemoved; + UINT16 usExpDetonated; + UINT16 usItemsRepaired; + UINT16 usItemsCombined; + UINT16 usItemsStolen; + UINT16 usMercsBandaged; + UINT16 usSurgeriesMade; + UINT16 usMilitiaTrained; + UINT16 usNPCsDiscovered; + UINT16 usSectorsDiscovered; + UINT8 ubQuestsHandled; + + UINT16 zFiller1; + UINT16 zFiller2; + UINT16 zFiller3; + UINT16 zFiller4; + UINT16 zFiller5; + UINT16 zFiller6; + UINT16 zFiller7; + UINT16 zFiller8; + UINT8 zFiller9; + +}; // RECORDS +////////////////////////////////////////////////////////////////////////////// + // CHRISL: Class to handle profile equipment from XML_MercStartingGear class MERCPROFILEGEAR { public: @@ -193,6 +328,7 @@ public: void clearInventory(); public: UINT16 mIndex; + INT16 PriceModifier; CHAR8 mName[80]; char endOfPOD; // marker for end of POD (plain old data) std::vector inv; @@ -300,7 +436,7 @@ public: INT16 sSalary; INT8 bLife; INT8 bDexterity; // dexterity (hand coord) value - INT8 bPersonalityTrait; + INT8 bDisability; INT8 bSkillTrait; INT8 bReputationTolerance; @@ -524,12 +660,16 @@ public: INT8 bExplosivesDelta; INT8 bStrengthDelta; INT8 bLeadershipDelta; - UINT16 usKills; - UINT16 usAssists; - UINT16 usShotsFired; - UINT16 usShotsHit; - UINT16 usBattlesFought; - UINT16 usTimesWounded; + ///////////////////////////////////////////////////////////// + // SANDRO - converted to it's own structure + //UINT16 usKills; + //UINT16 usAssists; + //UINT16 usShotsFired; + //UINT16 usShotsHit; + //UINT16 usBattlesFought; + //UINT16 usTimesWounded; + ///////////////////////////////////////////////////////////// + UINT16 usTotalDaysServed; INT16 sLeadershipGain; @@ -543,12 +683,13 @@ public: INT16 sSalary; INT8 bLife; INT8 bDexterity; // dexterity (hand coord) value - INT8 bPersonalityTrait; - INT8 bSkillTrait; + INT8 bDisability; + INT8 bSkillTraits[30]; INT8 bReputationTolerance; INT8 bExplosive; - INT8 bSkillTrait2; + //INT8 bSkillTrait2; + //INT8 bSkillTrait3; // added by SANDRO INT8 bLeadership; INT8 bBuddy[5]; @@ -598,6 +739,7 @@ public: UINT32 uiBiWeeklySalary; INT8 bMedicalDeposit; INT8 bAttitude; + INT8 bCharacterTrait; // added by SANDRO INT8 bBaseMorale; UINT16 sMedicalDepositAmount; @@ -660,6 +802,10 @@ public: std::vector inv; std::vector bInvStatus; std::vector bInvNumber; + + // SANDRO - merc records + STRUCT_Records records; + }; // MERCPROFILESTRUCT; // WANNE - BMP: DONE! @@ -753,7 +899,7 @@ public: INT16 sSalary; INT8 bLife; INT8 bDexterity; // dexterity (hand coord) value - INT8 bPersonalityTrait; + INT8 bDisability; INT8 bSkillTrait; INT8 bReputationTolerance; diff --git a/TacticalAI/AIInternals.h b/TacticalAI/AIInternals.h index 711d295a..7964c0f1 100644 --- a/TacticalAI/AIInternals.h +++ b/TacticalAI/AIInternals.h @@ -236,3 +236,14 @@ INT8 FindDirectionForClimbing( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel INT16 AssessTacticalSituation( INT8 bSide ); BOOLEAN TeamSeesOpponent( INT8 bSide, SOLDIERTYPE * pOpponent ); INT32 CalcStraightThreatValue( SOLDIERTYPE *pEnemy ); + +// SANDRO - added following functions +BOOLEAN DoctorIsPresent( SOLDIERTYPE * pPatient, BOOLEAN fOnDoctorAssignmentCheck ); +BOOLEAN AIDetermineStealingWeaponAttempt( SOLDIERTYPE * pSoldier, SOLDIERTYPE * ubOpponent ); + +// HEADROCK HAM 4: Calculate average recoil offset for a shot. +FLOAT AICalcRecoilForShot( SOLDIERTYPE *pSoldier, OBJECTTYPE *pWeapon, UINT8 ubShotNum); + + +// HEADROCK HAM 4: Calculate average recoil offset for a shot. +FLOAT AICalcRecoilForShot( SOLDIERTYPE *pSoldier, OBJECTTYPE *pWeapon, UINT8 ubShotNum); diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index 2122cd3c..43385103 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -55,6 +55,7 @@ #include "Queen Command.h" #include "cheats.h" #include "points.h" +#include "Soldier Functions.h" // added by SANDRO #endif #include "connect.h" @@ -2043,6 +2044,23 @@ void AIDecideRadioAnimation( SOLDIERTYPE *pSoldier ) } } +UINT32 GetTankCannonIndex() +{ + UINT32 tankCannonIndex = 0; + + for (UINT32 i = 0; i < MAXITEMS; i++) + { + if (Item[i].cannon) + { + tankCannonIndex = Item[i].uiIndex; + break; + } + } + + return tankCannonIndex; +} + + INT8 ExecuteAction(SOLDIERTYPE *pSoldier) { @@ -2056,8 +2074,29 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) // reset this field, too pSoldier->aiData.bLastAttackHit = FALSE; + // WANNE.TANK: Choose cannon or rocket UINT16 usHandItem = pSoldier->inv[HANDPOS].usItem; + if (TANK(pSoldier)) + { + // No cannon selected to fire + if (!Item[pSoldier->inv[HANDPOS].usItem].cannon) + { + // 50 % chance, that the tank fires with the explosive cannon + UINT32 fireWithCannon = GetRndNum(2); + if (fireWithCannon) + { + UINT32 tankCannonIndex = GetTankCannonIndex(); + if (tankCannonIndex > 0) + { + usHandItem = tankCannonIndex; + } + } + } + } + + UINT16 usSoldierIndex; // added by SANDRO + #ifdef TESTAICONTROL if (gfTurnBasedAI || gTacticalStatus.fAutoBandageMode) { @@ -2065,7 +2104,7 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) } #endif - DebugAI( String( "%d does %s (a.d. %d) at time %ld", pSoldier->ubID, gzActionStr[pSoldier->aiData.bAction], pSoldier->aiData.usActionData, GetJA2Clock() ) ); + DebugAI( String( "%d does %s (a.d. %d) at time %lu", pSoldier->ubID, gzActionStr[pSoldier->aiData.bAction], pSoldier->aiData.usActionData, GetJA2Clock() ) ); // 0verhaul: The decideaction stage does so many path plots and overrides that // relying on a stored path from there is a bad idea. @@ -2183,7 +2222,17 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) case AI_ACTION_LEAVE_WATER_GAS: // seek nearest spot of ungassed land case AI_ACTION_SEEK_NOISE: // seek most important noise heard case AI_ACTION_RUN_AWAY: // run away from nearby opponent(s) - + // SANDRO - ENEMY TAUNTS + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) && pSoldier->bVisible != -1 ) + { + if ( Random( 5 ) == 0 ) + { + if (pSoldier->aiData.bAction == AI_ACTION_SEEK_NOISE ) + StartEnemyTaunt( pSoldier, TAUNT_SEEK_NOISE ); + else if (pSoldier->aiData.bAction == AI_ACTION_RUN_AWAY ) + StartEnemyTaunt( pSoldier, TAUNT_RUN_AWAY ); + } + } case AI_ACTION_APPROACH_MERC: // walk up to someone to talk case AI_ACTION_TRACK: // track by ground scent case AI_ACTION_EAT: // monster approaching corpse @@ -2400,8 +2449,28 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) // ATE: Make sure it's a person :) if ( IS_MERC_BODY_TYPE( pSoldier ) && pSoldier->ubProfile == NO_PROFILE ) { + // SANDRO - SOLDIER TAUNTS + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) ) + { + if ( Random( 8 ) == 0 ) + { + if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN ) + StartEnemyTaunt( pSoldier, TAUNT_FIRE_GUN ); + else if (Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher || Item[pSoldier->inv[HANDPOS].usItem].mortar || Item[pSoldier->inv[HANDPOS].usItem].rocketlauncher ) + StartEnemyTaunt( pSoldier, TAUNT_FIRE_LAUNCHER ); + else if (pSoldier->aiData.bAction == AI_ACTION_TOSS_PROJECTILE && Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_THROWN && !Item[pSoldier->inv[HANDPOS].usItem].flare ) + StartEnemyTaunt( pSoldier, TAUNT_THROW ); + else if (pSoldier->aiData.bAction == AI_ACTION_KNIFE_MOVE ) + { + if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE ) + StartEnemyTaunt( pSoldier, TAUNT_CHARGE_KNIFE ); + //else if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH ) + // StartEnemyTaunt( pSoldier, TAUNT_CHARGE_HTH ); + } + } + } // CC, ATE here - I put in some TEMP randomness... - if ( Random( 50 ) == 0 ) + else if ( Random( 50 ) == 0 ) { StartCivQuote( pSoldier ); } @@ -2489,6 +2558,15 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) { HandleInitialRedAlert(pSoldier->bTeam, TRUE); } + + // SANDRO - ENEMY TAUNTS + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) && pSoldier->bVisible != -1 ) + { + if ( Random( 4 ) == 0 ) + { + StartEnemyTaunt( pSoldier, TAUNT_ALERT ); + } + } //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Debug: AI radios your position!" ); // DROP THROUGH HERE! case AI_ACTION_YELLOW_ALERT: // tell friends opponent(s) heard @@ -2679,6 +2757,18 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) // start the offer of surrender! StartCivQuote( pSoldier ); break; + ///////////////////////////////////////////////////////////// + // SANDRO - added a possibility for enemies to try to steal your gun + case AI_ACTION_STEAL_MOVE: // preparing to steal opponents weapon + + pSoldier->aiData.ubPendingAction = NO_PENDING_ACTION; + pSoldier->usUIMovementMode = DetermineMovementMode( pSoldier, AI_ACTION_KNIFE_MOVE ); + usSoldierIndex = WhoIsThere2( pSoldier->aiData.usActionData, pSoldier->bTargetLevel); + if ( usSoldierIndex != NOBODY ) + MercStealFromMerc( pSoldier, MercPtrs[usSoldierIndex] ); + + break; + ///////////////////////////////////////////////////////////// default: #ifdef BETAVERSION diff --git a/TacticalAI/AIUtils.cpp b/TacticalAI/AIUtils.cpp index 9edd44f0..c67dd728 100644 --- a/TacticalAI/AIUtils.cpp +++ b/TacticalAI/AIUtils.cpp @@ -23,8 +23,14 @@ #include "environment.h" #include "lighting.h" #include "Soldier Create.h" + #include "SkillCheck.h" // added by SANDRO #endif +////////////////////////////////////////////////////////////////////////////// +// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne() +// On the bottom here, there are these functions made +////////////////////////////////////////////////////////////////////// + // // CJC's DG->JA2 conversion notes // @@ -151,9 +157,9 @@ UINT8 StanceChange( SOLDIERTYPE * pSoldier, INT16 ubAttackAPCost ) if (PTR_STANDING) { - if (pSoldier->bActionPoints - ubAttackAPCost >= APBPConstants[AP_CROUCH]) + if (pSoldier->bActionPoints - ubAttackAPCost >= GetAPsCrouch(pSoldier, TRUE)) { - if ( (pSoldier->bActionPoints - ubAttackAPCost >= APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) && IsValidStance( pSoldier, ANIM_PRONE ) && ConsiderProne( pSoldier ) ) + if ( (pSoldier->bActionPoints - ubAttackAPCost >= GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE)) && IsValidStance( pSoldier, ANIM_PRONE ) && ConsiderProne( pSoldier ) ) { return( ANIM_PRONE ); } @@ -165,7 +171,7 @@ UINT8 StanceChange( SOLDIERTYPE * pSoldier, INT16 ubAttackAPCost ) } else if (PTR_CROUCHED) { - if ( (pSoldier->bActionPoints - ubAttackAPCost >= APBPConstants[AP_PRONE]) && IsValidStance( pSoldier, ANIM_PRONE ) && ConsiderProne( pSoldier ) ) + if ( (pSoldier->bActionPoints - ubAttackAPCost >= GetAPsProne(pSoldier, TRUE)) && IsValidStance( pSoldier, ANIM_PRONE ) && ConsiderProne( pSoldier ) ) { return( ANIM_PRONE ); } @@ -192,7 +198,7 @@ UINT8 ShootingStanceChange( SOLDIERTYPE * pSoldier, ATTACKTYPE * pAttack, INT8 b uiCurrChanceOfDamage = 0; bAPsAfterAttack = pSoldier->bActionPoints - MinAPsToAttack( pSoldier, pAttack->sTarget, ADDTURNCOST, 1); - if (bAPsAfterAttack < APBPConstants[AP_CROUCH]) + if (bAPsAfterAttack < GetAPsCrouch(pSoldier, TRUE)) { return( 0 ); } @@ -220,7 +226,7 @@ UINT8 ShootingStanceChange( SOLDIERTYPE * pSoldier, ATTACKTYPE * pAttack, INT8 b for (bLoop = 0; bLoop < 3; bLoop++) { bStanceDiff = abs( bLoop - bStanceNum ); - if (bStanceDiff == 2 && bAPsAfterAttack < APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) + if (bStanceDiff == 2 && bAPsAfterAttack < GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE)) { // can't consider this! continue; @@ -487,7 +493,7 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier) break; case AI_ACTION_PICKUP_ITEM: // grab things lying on the ground - bMinPointsNeeded = __max( MinPtsToMove( pSoldier ), APBPConstants[AP_PICKUP_ITEM] ); + bMinPointsNeeded = __max( MinPtsToMove( pSoldier ), GetBasicAPsToPickupItem( pSoldier ) ); // SANDRO break; case AI_ACTION_OPEN_OR_CLOSE_DOOR: @@ -497,7 +503,7 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier) break; case AI_ACTION_DROP_ITEM: - bMinPointsNeeded = APBPConstants[AP_PICKUP_ITEM]; + bMinPointsNeeded = GetBasicAPsToPickupItem( pSoldier ); // SANDRO break; case AI_ACTION_FIRE_GUN: // shoot at nearby opponent @@ -534,7 +540,7 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier) break; case AI_ACTION_CHANGE_STANCE: // crouch - bMinPointsNeeded = APBPConstants[AP_CROUCH]; + bMinPointsNeeded = GetAPsCrouch(pSoldier, TRUE); break; case AI_ACTION_GIVE_AID: // help injured/dying friend @@ -542,16 +548,17 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier) break; case AI_ACTION_CLIMB_ROOF: + // SANDRO - improved this a bit if (pSoldier->pathing.bLevel == 0) { - if( PTR_CROUCHED ) bAPForStandUp = 2; - if( PTR_PRONE ) bAPForStandUp = 4; - bMinPointsNeeded = APBPConstants[AP_CLIMBROOF] + bAPForStandUp + bAPToLookAtWall; + if( PTR_CROUCHED ) bAPForStandUp = (INT8)(GetAPsCrouch(pSoldier, TRUE)); + if( PTR_PRONE ) bAPForStandUp = GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE); + bMinPointsNeeded = GetAPsToClimbRoof( pSoldier, FALSE ) + bAPForStandUp + bAPToLookAtWall; } else { - if( !PTR_CROUCHED ) bAPForStandUp = 2; - bMinPointsNeeded = APBPConstants[AP_CLIMBOFFROOF] + bAPForStandUp + bAPToLookAtWall; + if( !PTR_CROUCHED ) bAPForStandUp = (INT8)(GetAPsCrouch(pSoldier, TRUE)); + bMinPointsNeeded = GetAPsToClimbRoof( pSoldier, TRUE ) + bAPForStandUp + bAPToLookAtWall; } break; @@ -564,6 +571,10 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier) bMinPointsNeeded = 0; break; + case AI_ACTION_STEAL_MOVE: // added by SANDRO + //bMinPointsNeeded = GetAPsToStealItem( pSoldier, NULL, pSoldier->aiData.usActionData );; + break; + default: #ifdef BETAVERSION //NumMessage("AffordableAction - Illegal action type = ",pSoldier->aiData.bAction); @@ -2084,6 +2095,9 @@ INT8 CalcMorale(SOLDIERTYPE *pSoldier) (pSoldier->aiData.bAttitude == BRAVESOLO || pSoldier->aiData.bAttitude == BRAVEAID)) bMoraleCategory = MORALE_WORRIED; + // SANDRO - on Insane difficulty enemy morale cannot go below worried + if (bMoraleCategory == MORALE_HOPELESS && gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) + bMoraleCategory = MORALE_WORRIED; #ifdef DEBUGDECISIONS STR tempstr; @@ -2128,7 +2142,7 @@ INT32 CalcManThreatValue( SOLDIERTYPE *pEnemy, INT32 sMyGrid, UINT8 ubReduceForC else { // ADD twice the man's level (2-20) - iThreatValue += pEnemy->stats.bExpLevel; + iThreatValue += EffectiveExpLevel(pEnemy); // SANDRO - find precise effective exp level // ADD man's total action points (10-35) iThreatValue += pEnemy->CalcActionPoints(); @@ -2725,7 +2739,7 @@ INT32 CalcStraightThreatValue( SOLDIERTYPE *pEnemy ) else { // ADD twice the man's level (2-20) - iThreatValue += pEnemy->stats.bExpLevel; + iThreatValue += EffectiveExpLevel(pEnemy); // SANDRO - find precise effective exp level // ADD man's total action points (10-35) iThreatValue += pEnemy->CalcActionPoints(); diff --git a/TacticalAI/Attacks.cpp b/TacticalAI/Attacks.cpp index a60b864d..75c257a4 100644 --- a/TacticalAI/Attacks.cpp +++ b/TacticalAI/Attacks.cpp @@ -21,6 +21,7 @@ #include "environment.h" #include "lighting.h" #include "Sound Control.h" +#include "message.h" #endif extern INT16 DirIncrementer[8]; @@ -115,6 +116,36 @@ void LoadWeaponIfNeeded(SOLDIERTYPE *pSoldier) } } +// FROM SB JA2005 +void ResetWeaponMode( SOLDIERTYPE * pSoldier ) +{ + // ATE: Don't do this if in a fire amimation..... + if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) + { + return; + } + + pSoldier->bWeaponMode = WM_NORMAL; + +// + pSoldier->aiData.bShownAimTime = REFINE_AIM_1; + + //!pSoldier->aiData.ubBurstAP = 0; //SB reset long burst length + //^^^^ , . +// gfDisplayFullCountRing = FALSE; +// gfDisplayFullCountRingBurst = FALSE; +// +// pSoldier->bDoBurst = Weapon[Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex].mode[WM_NORMAL].usROF > 0; + +// DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); +// gfUIForceReExamineCursorData = TRUE; + +// gfShowBurstLength = Weapon[Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex].mode[pSoldier->bWeaponMode].usROF > 0; +// gfShowBurstLength = Weapon[Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex].mode[pSoldier->bWeaponMode].ubBullets > 1; + +} +// + void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUnseen) { UINT32 uiLoop; @@ -254,9 +285,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns if ( TANK( pSoldier ) ) { - // HEADROCK HAM 3.6: Calculation must take into account APBP constants and other aiming modifications! - INT8 bAPsLeft = pSoldier->bActionPoints - ubMinAPcost; - ubMaxPossibleAimTime = CalcAimingLevelsAvailableWithAP( pSoldier, pOpponent->sGridNo, bAPsLeft ); + ubMaxPossibleAimTime = pSoldier->bActionPoints - ubMinAPcost; // always burst if ( ubMaxPossibleAimTime < ubBurstAPs ) @@ -291,11 +320,7 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns //sprintf(tempstr,"Vs. %s, at AimTime %d, ubChanceToHit = %d",ExtMen[pOpponent->ubID].name,ubAimTime,ubChanceToHit); //PopMessage(tempstr); - // HEADROCK HAM 3.6: Actual aiming time is no longer 1AP per level... Failure to take this into account - // may yield skewed results in favour of high-aim targets. - INT16 sActualAimTime = CalcAPCostForAiming( pSoldier, pOpponent->sGridNo, (INT8)ubAimTime ); - - iHitRate = (pSoldier->bActionPoints * ubChanceToHit) / (ubRawAPCost + sActualAimTime); + iHitRate = (pSoldier->bActionPoints * ubChanceToHit) / (ubRawAPCost + ubAimTime); //NumMessage("hitRate = ",iHitRate); // if aiming for this amount of time produces a better hit rate @@ -501,7 +526,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) if ( EXPLOSIVE_GUN( usInHand ) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"explosive gun"); - iTossRange = Weapon[ usInHand ].usRange / CELL_X_SIZE; + iTossRange = GetModifiedGunRange(usInHand) / CELL_X_SIZE; } else { @@ -1068,7 +1093,8 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) } // calculate the maximum possible aiming time - ubMaxPossibleAimTime = min(AllowedAimingLevels(pSoldier),pSoldier->bActionPoints - ubMinAPcost); + // HEADROCK HAM 4: Required for new Aiming Level Limits function + ubMaxPossibleAimTime = min( AllowedAimingLevels(pSoldier, sGridNo), pSoldier->bActionPoints - ubMinAPcost); DebugMsg(TOPIC_JA2 , DBG_LEVEL_3 , String("Max Possible Aim Time = %d",ubMaxPossibleAimTime )); // calc next attack's minimum AP cost (excludes readying & turning) @@ -1282,7 +1308,8 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt iBestHitRate = 0; // reset best hit rate to minimum // calculate the maximum possible aiming time - ubMaxPossibleAimTime = min(AllowedAimingLevels(pSoldier),pSoldier->bActionPoints - ubMinAPCost); + // HEADROCK HAM 4: Required for new Aiming Level Limits function + ubMaxPossibleAimTime = min(AllowedAimingLevels(pSoldier, pOpponent->sGridNo),pSoldier->bActionPoints - ubMinAPCost); //NumMessage("Max Possible Aim Time = ",ubMaxPossibleAimTime); // consider the various aiming times @@ -1433,8 +1460,9 @@ void CalcTentacleAttack(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab ) if (pSoldier->pathing.bLevel != pOpponent->pathing.bLevel) continue; // next merc + UINT16 usRange = GetModifiedGunRange(CREATURE_QUEEN_TENTACLES); // if this opponent is outside the range of our tentacles - if ( GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, pOpponent->sGridNo ) > Weapon[ CREATURE_QUEEN_TENTACLES].usRange ) + if ( GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, pOpponent->sGridNo ) > usRange ) { continue; // next merc } @@ -1609,10 +1637,16 @@ INT32 EstimateShotDamage(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT16 ub // calculate distance to target, obtain his gun's maximum range rating iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, pOpponent->sGridNo ); - iMaxRange = Weapon[usItem].usRange; + // SANDRO - added specific range calculation + if ( Item[ usItem ].usItemClass & IC_GUN ) + iMaxRange = GunRange( pObj, pSoldier ); + else + iMaxRange = GetModifiedGunRange(usItem); // bullet loses speed and penetrating power, 50% loss per maximum range - iPowerLost = ((50 * iRange) / iMaxRange); + // SANDRO - you know, 50% is a lot, it often leads to negative damage values in the end + // while there is no true effect of this in game !!! Made it 25%! + iPowerLost = ((25 * iRange) / iMaxRange); // up to 50% extra impact for making particularly accurate successful shots ubBonus = ubChanceToHit / 4; // /4 is really /2 and /2 again @@ -1641,7 +1675,7 @@ INT32 EstimateShotDamage(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT16 ub // check for ceramic plates; these do affect monster spit for (attachmentList::iterator iter = pOpponent->inv[VESTPOS][0]->attachments.begin(); iter != pOpponent->inv[VESTPOS][0]->attachments.end(); ++iter) { - if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 ) + if (Item[iter->usItem].usItemClass == IC_ARMOUR && (*iter)[0]->data.objectStatus > 0 && iter->exists() ) { iTorsoProt += (INT32) Armour[Item[iter->usItem].ubClassIndex].ubProtection * (INT32) (*iter)[0]->data.objectStatus / 100; @@ -1745,7 +1779,7 @@ INT32 EstimateThrowDamage( SOLDIERTYPE *pSoldier, UINT8 ubItemPos, SOLDIERTYPE * else if ( Item[pSoldier->inv[ ubItemPos ].usItem].rocketlauncher || Item[pSoldier->inv[ ubItemPos ].usItem].grenadelauncher || Item[pSoldier->inv[ ubItemPos ].usItem].mortar ) { OBJECTTYPE* pAttachment = FindLaunchableAttachment(&pSoldier->inv[ ubItemPos ],pSoldier->inv[ ubItemPos ].usItem ) ; - if ( pAttachment ) + if ( pAttachment->exists() ) ubExplosiveIndex = Item[pAttachment->usItem].ubClassIndex; else return 0; @@ -1843,21 +1877,44 @@ INT32 EstimateStabDamage( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, } else { - // NB martial artists don't get a bonus for using brass knuckles! - if (pSoldier->usAttackingWeapon && !( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS ) ) ) + // this all was a little changed for enhanced close combat system - SANDRO + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) { - iImpact = GetDamage(&pSoldier->inv[HANDPOS]); + iImpact = EffectiveStrength( pSoldier ) / 5; // 0 to 20 for strength, adjusted by damage taken + + if ( pSoldier->usAttackingWeapon ) + { + iImpact += GetDamage(&pSoldier->inv[HANDPOS]); + } + else + { + // base HTH damage + iImpact += 4; // Slightly reduced for we can now attack to head for bigger damage - SANDRO + // Add melee damage multiplier to bare HtH attacks as well - SANDRO + // actually I make the influence a little lesser, because to the blades and so, + // only the item impact is multiplied, not the level and strength bonus, but here it does + iImpact += iImpact * gGameExternalOptions.iMeleeDamageModifier / 120; + } } else { - // base HTH damage - iImpact = 5; + + // NB martial artists don't get a bonus for using brass knuckles! + if (pSoldier->usAttackingWeapon && !( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) ) ) + { + iImpact = GetDamage(&pSoldier->inv[HANDPOS]); + } + else + { + // base HTH damage + iImpact = 5; + } + iImpact += EffectiveStrength( pSoldier ) / 5; // 0 to 20 for strength, adjusted by damage taken } - iImpact += EffectiveStrength( pSoldier ) / 5; // 0 to 20 for strength, adjusted by damage taken } - iImpact += (pSoldier->stats.bExpLevel / 2); // 0 to 4 for level + iImpact += (EffectiveExpLevel( pSoldier ) / 2); // 0 to 4 for level // SANDRO - added effective level calc iFluke = 0; iBonus = ubChanceToHit / 4; // up to 50% extra impact for accurate attacks @@ -1867,17 +1924,81 @@ INT32 EstimateStabDamage( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, if (!fBladeAttack) { // add bonuses for hand-to-hand and martial arts - if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS ) ) + // Check for new traits - SANDRO + if ( gGameOptions.fNewTraitSystem ) { - iImpact = iImpact * (100 + gbSkillTraitBonus[MARTIALARTS] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS ) ) / 100; + if (!pSoldier->usAttackingWeapon || Item[pSoldier->inv[HANDPOS].usItem].brassknuckles) + { + // add bonuses for martial arts + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + { + // also add breath damage bonus into consideration + iImpact = (INT32)((iImpact * ( 100 + (gSkillTraitValues.ubMABonusDamageHandToHand + gSkillTraitValues.ubMABonusBreathDamageHandToHand) * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); + + + // The Spinning kicks or aimed punch bonus - SANDRO + //if (pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime > 0)) + //{ + // iImpact += (iImpact * gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100; // +75% damage per trait + //} + } + } + else + { + // +30% damage of blunt weapons for melee character + if (HAS_SKILL_TRAIT( pSoldier, MELEE_NT )) + { + iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.ubMEDamageBonusBlunt)/100) + 0.5); + + //if (pSoldier->aiData.bAimTime > 0) + //{ + // iImpact += (iImpact * (100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus) / 100); // 50% incresed damage if focused melee attack + //} + } + } } - if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND ) ) + else { - iImpact = iImpact * (100 + gbSkillTraitBonus[HANDTOHAND] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND ) ) / 100; + if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) ) + { + iImpact = (INT32)((iImpact * (100 + gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ) ) / 100) + 0.5); + } + if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) ) + { + iImpact = (INT32)((iImpact * (100 + gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND_OT ) ) / 100) + 0.5); + } + } + // SANDRO - Enhanced Close Combat System - aiming at body parts makes difference + if (gGameExternalOptions.fEnhancedCloseCombatSystem && (gAnimControl[ pOpponent->usAnimState ].ubEndHeight == ANIM_PRONE)) + { + iImpact = (INT32)(iImpact * 150 / 100); // 50% incresed damage to lying characters } // Here, if we're doing a bare-fisted attack, // we want to pay attention just to wounds inflicted - iImpact = iImpact / PUNCH_REAL_DAMAGE_PORTION; + // SANDRO - No, we may consider the breath damage as asort of "real" damage too, so only reduce it by half + iImpact = iImpact / 2; + //iImpact = iImpact / PUNCH_REAL_DAMAGE_PORTION; + } + // SANDRO - damage bonus to melee trait + else + { + if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && (gGameOptions.fNewTraitSystem) ) + { + iImpact += (iImpact * (100 + gSkillTraitValues.ubMEDamageBonusBlades ) / 100); // +30% damage + + //if (pSoldier->aiData.bAimTime > 0) + //{ + // iImpact += (iImpact * ( 100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus ) / 100); // 50% incresed damage if focused melee attack + //} + } + // SANDRO - Enhanced Close Combat System + if (gGameExternalOptions.fEnhancedCloseCombatSystem) + { + if (gAnimControl[ pOpponent->usAnimState ].ubEndHeight == ANIM_PRONE) + { + iImpact = (INT32)(iImpact * 140 / 100); // 40% incresed damage to lying characters + } + } } if (iImpact < 1) @@ -1914,7 +2035,24 @@ INT8 TryToReload( SOLDIERTYPE * pSoldier ) { (*pObj)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; - DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0); + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - SANDRO + if ( gGameOptions.fNewTraitSystem ) + { + // Sniper trait makes chambering a round faster + if (( Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_SN_RIFLE || Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_RIFLE ) && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT )) + DeductPoints(pSoldier, (INT16)(((Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubSNChamberRoundAPsReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )))/100) + 0.5), 0); + // Ranger trait makes pumping shotguns faster + else if (( Weapon[Item[(pObj)->usItem].ubClassIndex].ubWeaponType == GUN_SHOTGUN ) && HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + DeductPoints(pSoldier, (INT16)(((Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubRAPumpShotgunsAPsReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT )))/100) + 0.5), 0); + else + DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0); + } + else + { + DeductPoints(pSoldier, Weapon[Item[(pObj)->usItem].ubClassIndex].APsToReloadManually, 0); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// PlayJA2Sample( Weapon[ Item[pObj->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); @@ -1942,7 +2080,24 @@ INT8 TryToReload( SOLDIERTYPE * pSoldier ) { (*pObj2)[0]->data.gun.ubGunState |= GS_CARTRIDGE_IN_CHAMBER; - DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0); + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // STOMP traits - SANDRO (well, I don't know any one-handed sniper rifle, but what the hell...) + if ( gGameOptions.fNewTraitSystem ) + { + // Sniper trait makes chambering a round faster + if (( Weapon[Item[(pObj2)->usItem].ubClassIndex].ubWeaponType == GUN_SN_RIFLE || Weapon[Item[(pObj2)->usItem].ubClassIndex].ubWeaponType == GUN_RIFLE ) && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT )) + DeductPoints(pSoldier, (INT16)(((Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubSNChamberRoundAPsReduction * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )))/100) + 0.5), 0); + // Ranger trait makes pumping shotguns faster + else if (( Weapon[Item[(pObj2)->usItem].ubClassIndex].ubWeaponType == GUN_SHOTGUN ) && HAS_SKILL_TRAIT( pSoldier, RANGER_NT )) + DeductPoints(pSoldier, (INT16)(((Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually * (100 - gSkillTraitValues.ubRAPumpShotgunsAPsReduction * NUM_SKILL_TRAITS( pSoldier, RANGER_NT )))/100) + 0.5), 0); + else + DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0); + } + else + { + DeductPoints(pSoldier, Weapon[Item[(pObj2)->usItem].ubClassIndex].APsToReloadManually, 0); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// PlayJA2Sample( Weapon[ Item[pObj2->usItem].ubClassIndex ].ManualReloadSound, RATE_11025, SoundVolume( HIGHVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); @@ -2492,10 +2647,10 @@ void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN s // (suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn] ) && GetMagSize(pObj) > 30 && (*pObj)[0]->data.gun.ubGunShotsLeft > 20 )) BOOLEAN fEnableAISuppression = FALSE; - if ( gGameExternalOptions.fIncreaseAISuppressionFire && ((!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) || + if ( gGameExternalOptions.fIncreaseAISuppressionFire && ((!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj, pSoldier) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) || // SANDRO - added argument to GunRange() (suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn]))) ) fEnableAISuppression = TRUE; - else if ( !gGameExternalOptions.fIncreaseAISuppressionFire && ( (!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) || + else if ( !gGameExternalOptions.fIncreaseAISuppressionFire && ( (!suppressionFire && ( (IsScoped(pObj) && GunRange(pObj, pSoldier) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) ) || // SANDRO - added argument (suppressionFire && IsGunAutofireCapable(&pSoldier->inv[pBestShot->bWeaponIn] ) && GetMagSize(pObj) > 30 && (*pObj)[0]->data.gun.ubGunShotsLeft > 20 ))) fEnableAISuppression = TRUE; @@ -2523,3 +2678,142 @@ void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN s } } } + +// SANDRO - function to determine if we should try to steal the enemy gun +BOOLEAN AIDetermineStealingWeaponAttempt( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent ) +{ + INT16 sChance = 0; + UINT32 uiSuccessChance = 0; + + if( pOpponent == NULL ) + { + return( FALSE ); + } + + if( pOpponent->bTeam != gbPlayerNum ) + { + return( FALSE ); + } + + if( pOpponent->bCollapsed || pOpponent->bBreathCollapsed ) + { + return( FALSE ); + } + pSoldier->usUIMovementMode = RUNNING; + if( pSoldier->bActionPoints < GetAPsToStealItem( pSoldier, NULL, pOpponent->sGridNo ) ) + { + return( FALSE ); + } + + if( (pOpponent->inv[HANDPOS].exists() != true) ) + { + return( FALSE ); + } + if ( !(Item[pOpponent->inv[HANDPOS].usItem].usItemClass & IC_WEAPON) ) + { + UINT16 dfgvdfv = Item[pOpponent->inv[HANDPOS].usItem].usItemClass; + return( FALSE ); + } + + uiSuccessChance = CalcChanceToSteal(pSoldier, pOpponent, 0); + if ( uiSuccessChance >= 100 ) + { + sChance = 90; + } + else if ( uiSuccessChance >= 85 ) + { + sChance = 75; + } + else if ( uiSuccessChance >= 70 ) + { + sChance = 60; + } + else if ( uiSuccessChance >= 50 ) + { + sChance = 40; + } + else if ( uiSuccessChance >= 25 ) + { + sChance = 15; + } + else + { + return( FALSE ); + } + + if( gGameOptions.fNewTraitSystem ) + { + if( !HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + { + return( FALSE ); + } + else if( NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) > 1 ) + { + sChance += 50; + } + } + else + { + if( !HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) ) + { + return( FALSE ); + } + else if(( NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ) > 1 ) || ( NUM_SKILL_TRAITS( pSoldier, HANDTOHAND_OT ) > 1 )) + { + sChance += 25; + } + } + + if( pSoldier->stats.bLife < pSoldier->stats.bLifeMax ) + { + sChance -= (pSoldier->stats.bLifeMax - pSoldier->stats.bLife); + } + if( pSoldier->bBreath < pSoldier->bBreathMax ) + { + sChance -= ((pSoldier->bBreathMax - pSoldier->bBreath) / 2); + } + + if( pOpponent->stats.bLife < pOpponent->stats.bLifeMax ) + { + sChance += (pOpponent->stats.bLifeMax - pOpponent->stats.bLife); + } + if( pOpponent->bBreath < pOpponent->bBreathMax ) + { + sChance += ((pOpponent->bBreathMax - pOpponent->bBreath) / 2); + } + + if( pSoldier->bActionPoints > (GetAPsToStealItem( pSoldier, NULL, pOpponent->sGridNo ) + (2 * ApsToPunch( pSoldier ))) ) + { + sChance += 35; + } + else if ( pSoldier->bActionPoints > (GetAPsToStealItem( pSoldier, NULL, pOpponent->sGridNo ) + ApsToPunch( pSoldier )) ) + { + sChance += 20; + } + else + { + sChance -= 10; + } + + if( Chance( sChance ) ) + { + return( TRUE ); + } + else + { + return( FALSE ); + } +} + +// HEADROCK HAM 4: This is required for the AI to be able to assess the length of autofire volleys using the new +// recoil system. +FLOAT AICalcRecoilForShot( SOLDIERTYPE *pSoldier, OBJECTTYPE *pWeapon, UINT8 ubShotNum) +{ + INT8 bRecoilX = 0; + INT8 bRecoilY = 0; + GetRecoil( pWeapon, &bRecoilX, &bRecoilY, ubShotNum ); + // Return average shooter's ability to control this gun. + // HEADROCK HAM 4: TODO: Incorporate items that alter max counter-force. + FLOAT AverageRecoil = __max(0, ((FLOAT)sqrt( (FLOAT)(bRecoilX * bRecoilX) + (FLOAT)(bRecoilY * bRecoilY) ) - (gGameCTHConstants.RECOIL_MAX_COUNTER_FORCE * 0.7f) ) ); + return AverageRecoil; +} \ No newline at end of file diff --git a/TacticalAI/DecideAction.cpp b/TacticalAI/DecideAction.cpp index d4c0add4..3ec91e00 100644 --- a/TacticalAI/DecideAction.cpp +++ b/TacticalAI/DecideAction.cpp @@ -36,6 +36,11 @@ #include "connect.h" #include "Text.h" +////////////////////////////////////////////////////////////////////////////// +// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne() +// On the bottom here, there are these functions made +////////////////////////////////////////////////////////////////////// + extern BOOLEAN gfHiddenInterrupt; extern BOOLEAN gfUseAlternateQueenPosition; @@ -845,9 +850,36 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) } +//ddd{ + if(gGameExternalOptions.bNewTacticalAIBehavior + && !( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) ) + && pSoldier->bTeam == ENEMY_TEAM) + { + INT32 cnt; + ROTTING_CORPSE * pCorpse; - + for ( cnt = 0; cnt < giNumRottingCorpse; cnt++ ) + { + pCorpse = &(gRottingCorpse[ cnt ] ); + + if ( pCorpse->fActivated && pCorpse->def.ubAIWarningValue > 0 ) + if ( PythSpacesAway( pSoldier->sGridNo, pCorpse->def.sGridNo ) <= 5 )// (smaxvid ?) + { + //, .? + //CHRISL: Shouldn't we be using the corpse's bLevel? Otherwise a soldier inside a building can see a corpse on the roof of that building + //if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pSoldier->pathing.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) ) + if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pCorpse->def.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) ) + { + ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, L"Warning: enemy corpse found!!!" ); + //pCorpse->def.ubAIWarningValue=0; + gRottingCorpse[ cnt ].def.ubAIWarningValue=0; + return( AI_ACTION_RED_ALERT ); + } + } + } + } +//ddd} //////////////////////////////////////////////////////////////////////////// // POINT PATROL: move towards next point unless getting a bit winded @@ -2204,7 +2236,10 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if (BestThrow.ubPossible) { // if firing mortar make sure we have room - if ( Item[pSoldier->inv[ BestThrow.bWeaponIn ].usItem].mortar ) + //if ( Item[pSoldier->inv[ BestThrow.bWeaponIn ].usItem].mortar ) //comm by ddd + if (Item[pSoldier->inv[ BestThrow.bWeaponIn ].usItem].mortar + || Item[pSoldier->inv[ BestThrow.bWeaponIn ].usItem].grenadelauncher + || Item[pSoldier->inv[ BestThrow.bWeaponIn ].usItem].flare ) { ubOpponentDir = GetDirectionFromGridNo( BestThrow.sTarget, pSoldier ); @@ -2311,7 +2346,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) OBJECTTYPE * gun = &pSoldier->inv[BestShot.bWeaponIn]; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("decideactionred: men in sector %d, ubspotters called by %d, nobody %d",gTacticalStatus.Team[pSoldier->bTeam].bMenInSector,gTacticalStatus.ubSpottersCalledForBy,NOBODY )); //if ( ( ( IsScoped(gun) && GunRange(gun) > pSoldier->GetMaxDistanceVisible(BestShot.sTarget, BestShot.bTargetLevel) ) || pSoldier->aiData.bOrders == SNIPER ) && - if ( ( ( IsScoped(gun) && GunRange(gun) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) && + if ( ( ( IsScoped(gun) && GunRange(gun, pSoldier) > MaxNormalDistanceVisible() ) || pSoldier->aiData.bOrders == SNIPER ) && // SANDRO - added argument (gTacticalStatus.Team[pSoldier->bTeam].bMenInSector > 1) && (gTacticalStatus.ubSpottersCalledForBy == NOBODY)) @@ -2360,17 +2395,30 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) pSoldier->aiData.usActionData = BestShot.sTarget; //pSoldier->aiData.bAimTime = BestShot.ubAimTime; INT16 ubBurstAPs = 0; + FLOAT dTotalRecoil = 0; pSoldier->bDoAutofire = 0; - do - { - pSoldier->bDoAutofire++; - ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire ); + if(UsingNewCTHSystem() == true){ + do + { + INT8 bRecoilX = 0; + INT8 bRecoilY = 0; + pSoldier->bDoAutofire++; + dTotalRecoil += AICalcRecoilForShot( pSoldier, &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire ); + ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire ); + } + while( pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire + && dTotalRecoil <= 10.0f ); + } else { + do + { + pSoldier->bDoAutofire++; + ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire ); + } + while( pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs && + pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && + GetAutoPenalty(&pSoldier->inv[ pSoldier->ubAttackingHand ], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)*pSoldier->bDoAutofire <= 80 ); } - while( pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs && - pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && - GetAutoPenalty(&pSoldier->inv[ pSoldier->ubAttackingHand ], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)*pSoldier->bDoAutofire <= 80 ); - pSoldier->bDoAutofire--; @@ -2385,7 +2433,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) pSoldier->bDoBurst = 1; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[ MSG113_SUPPRESSIONFIRE ] ); - Menptr[BestShot.ubOpponent].ubSuppressionPoints += pSoldier->bDoAutofire; + // HEADROCK HAM 4: This is the stupidest thing ever. + // Menptr[BestShot.ubOpponent].ubSuppressionPoints += pSoldier->bDoAutofire; Menptr[BestShot.ubOpponent].ubSuppressorID = pSoldier->ubID; return( AI_ACTION_FIRE_GUN ); } @@ -2463,6 +2512,11 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) //////////////////////////////////////////////////////////////////////////// if ( ubCanMove && InLightAtNight( pSoldier->sGridNo, pSoldier->pathing.bLevel ) && pSoldier->aiData.bOrders != STATIONARY ) { + //ddd , + if(gGameExternalOptions.bNewTacticalAIBehavior) + pSoldier->aiData.bAction = AI_ACTION_LEAVE_WATER_GAS; + //ddd + pSoldier->aiData.usActionData = FindNearbyDarkerSpot( pSoldier ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -2687,12 +2741,12 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: stop flanking"); if (PythSpacesAway ( pSoldier->sGridNo, tempGridNo ) > MIN_FLANK_DIST_RED * 2 ) { - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,tempGridNo,APBPConstants[AP_PRONE],AI_ACTION_SEEK_OPPONENT,0); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,tempGridNo,GetAPsProne( pSoldier, TRUE),AI_ACTION_SEEK_OPPONENT,0); if ( LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, tempGridNo, pSoldier->pathing.bLevel, TRUE) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, tempGridNo, (INT8) (MinAPsToAttack( pSoldier, tempGridNo, ADDTURNCOST) + APBPConstants[AP_CROUCH]), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, tempGridNo, (INT8) (MinAPsToAttack( pSoldier, tempGridNo, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -2815,7 +2869,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) ////////////////////////////////////////////////////////////////////// // try to move towards him - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestDisturbance,APBPConstants[AP_CROUCH],AI_ACTION_SEEK_OPPONENT,0); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestDisturbance,GetAPsCrouch( pSoldier, TRUE),AI_ACTION_SEEK_OPPONENT,0); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -2917,12 +2971,12 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if (TileIsOutOfBounds(pSoldier->aiData.usActionData) || pSoldier->numFlanks >= MAX_FLANKS_RED ) { - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestDisturbance,APBPConstants[AP_CROUCH], AI_ACTION_SEEK_OPPONENT,0); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestDisturbance,GetAPsCrouch( pSoldier, TRUE), AI_ACTION_SEEK_OPPONENT,0); //pSoldier->numFlanks = 0; if ( PythSpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, sClosestDisturbance, pSoldier->pathing.bLevel, TRUE ) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + APBPConstants[AP_CROUCH]), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -2960,7 +3014,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if ( PythSpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, sClosestDisturbance, pSoldier->pathing.bLevel, TRUE ) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + APBPConstants[AP_CROUCH]), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -3058,7 +3112,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) ////////////////////////////////////////////////////////////////////// // GO DIRECTLY TOWARDS CLOSEST FRIEND UNDER FIRE OR WHO LAST RADIOED ////////////////////////////////////////////////////////////////////// - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestFriend,APBPConstants[AP_CROUCH], AI_ACTION_SEEK_OPPONENT,0); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestFriend,GetAPsCrouch( pSoldier, TRUE), AI_ACTION_SEEK_OPPONENT,0); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -3148,7 +3202,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) { // either moving significantly closer or into very close range // ensure will we have enough APs for a possible crouch plus a shot - if ( InternalGoAsFarAsPossibleTowards( pSoldier, pSoldier->aiData.usActionData, (INT8) (MinAPsToAttack( pSoldier, sClosestOpponent, ADDTURNCOST) + APBPConstants[AP_CROUCH]), AI_ACTION_TAKE_COVER, 0 ) == pSoldier->aiData.usActionData ) + if ( InternalGoAsFarAsPossibleTowards( pSoldier, pSoldier->aiData.usActionData, (INT8) (MinAPsToAttack( pSoldier, sClosestOpponent, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_TAKE_COVER, 0 ) == pSoldier->aiData.usActionData ) { return(AI_ACTION_TAKE_COVER); } @@ -3425,7 +3479,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD ) { // reduce bleeding by 1 point per AP (in RT, APs will get recalculated so it's okay) - pSoldier->bBleeding = __max( 0, pSoldier->bBleeding - pSoldier->bActionPoints ); + pSoldier->bBleeding = __max( 0, pSoldier->bBleeding - (pSoldier->bActionPoints/2) ); return( AI_ACTION_NONE ); // will end-turn/wait depending on whether we're in TB or realtime } #ifdef RECORDNET @@ -3936,7 +3990,9 @@ INT16 ubMinAPCost; { // look around for a worthy target (which sets BestShot.ubPossible) BOOLEAN shootUnseen = FALSE; - if (gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM ) + ///ddd + //if (gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM ) //comm by ddd + if (gGameOptions.ubDifficultyLevel > DIF_LEVEL_MEDIUM || gGameExternalOptions.bNewTacticalAIBehavior) shootUnseen = TRUE; CalcBestShot(pSoldier,&BestShot,shootUnseen); @@ -4125,6 +4181,107 @@ INT16 ubMinAPCost; RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY); } } + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - even if we don't have any blade, calculate how much damage we could do unarmed + else if ( !TANK( pSoldier) ) + { + bWeaponIn = FindAIUsableObjClass( pSoldier, IC_PUNCH ); + if (bWeaponIn == NO_SLOT) // if no punch-type weapon found, just calculate it with empty hands + { + bWeaponIn = FindEmptySlotWithin( pSoldier, HANDPOS, NUM_INV_SLOTS ); + } + if (bWeaponIn != NO_SLOT) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"try to punch"); + BestStab.bWeaponIn = bWeaponIn; + // if it's in his holster, swap it into his hand temporarily + if (bWeaponIn != HANDPOS) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionblack: about to rearrange pocket before punch check"); + RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY); + } + + // get the minimum cost to attack with punch + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + // if we can afford the minimum AP cost to punch + if (pSoldier->bActionPoints >= ubMinAPCost) + { + // then look around for a worthy target (which sets BestStab.ubPossible) + CalcBestStab(pSoldier,&BestStab, FALSE); + + if (BestStab.ubPossible) + { + // if we have not enough APs to deal at least two or three punches, + // reduce the attack value as one punch ain't much + if( gGameOptions.fNewTraitSystem ) + { + // if we are not specialized, reduce the attack attractiveness generaly + if ( !HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + { + BestStab.iAttackValue /= 4; + // if too far and not having APs for at least 3 hits no way to attack + if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + (2 * (ApsToPunch( pSoldier )))) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1) ) + { + BestStab.ubPossible = 0; + BestStab.iAttackValue = 0; + } + } + else + { + if (PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1) + { + BestStab.iAttackValue = (BestStab.iAttackValue * 2); + } + // if too far and not having APs for at least 2 hits + else if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + ApsToPunch( pSoldier )) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1)) + { + BestStab.iAttackValue /= 3; + } + } + } + else + { + if ( !HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) ) + { + // if we are not specialized, reduce the attack attractiveness generaly + BestStab.iAttackValue /= 4; + // if too far and not having APs for at least 3 hits + if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + (2 * (ApsToPunch( pSoldier )))) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget <= 1)) ) + { + BestStab.ubPossible = 0; + BestStab.iAttackValue = 0; + } + } + else + { + BestStab.iAttackValue = ((BestStab.iAttackValue * 3)/2); + + if (PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget) <= 1) + { + BestStab.iAttackValue = ((BestStab.iAttackValue * 3)/2); + } + // if too far and not having APs for at least 2 hits + else if (((CalcTotalAPsToAttack( pSoldier,BestStab.sTarget,ADDTURNCOST, 0 ) + ApsToPunch( pSoldier )) > pSoldier->bActionPoints) && !(PythSpacesAway(pSoldier->sGridNo, BestStab.sTarget <= 1)) ) + { + BestStab.iAttackValue /= 3; + } + } + } + // now we KNOW FOR SURE that we will do something (stab, at least) + NPCDoesAct(pSoldier); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"NPC decided to punch"); + } + + } + // if it was in his holster, swap it back into his holster for now + if (bWeaponIn != HANDPOS) + { + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"about to rearrange pocket after punch check"); + RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY); + } + } + } + ///////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // CHOOSE THE BEST TYPE OF ATTACK OUT OF THOSE FOUND TO BE POSSIBLE @@ -4148,11 +4305,27 @@ INT16 ubMinAPCost; ubBestAttackAction = AI_ACTION_THROW_KNIFE; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = throw knife"); } - else + else if ( Item[ pSoldier->inv[BestStab.bWeaponIn].usItem ].usItemClass & IC_BLADE ) // SANDRO - check specifically for blade attack { ubBestAttackAction = AI_ACTION_KNIFE_MOVE; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = move to stab"); } + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - added a chance to try to steal merc's gun from hands + else + { + if (AIDetermineStealingWeaponAttempt( pSoldier, MercPtrs[BestStab.ubOpponent] ) == TRUE) + { + ubBestAttackAction = AI_ACTION_STEAL_MOVE; + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = move to steal weapon"); + } + else + { + ubBestAttackAction = AI_ACTION_KNIFE_MOVE; + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"best action = move to punch"); + } + } + //////////////////////////////////////////////////////////////////////////////////// } if (BestThrow.ubPossible && ((BestThrow.iAttackValue > BestAttack.iAttackValue) || (ubBestAttackAction == AI_ACTION_NONE))) { @@ -4223,6 +4396,10 @@ INT16 ubMinAPCost; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = stab with a knife"); memcpy(&BestAttack,&BestStab,sizeof(BestAttack)); break; + case AI_ACTION_STEAL_MOVE: // added by SANDRO + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: best attack = try to steal weapon"); + memcpy(&BestAttack,&BestStab,sizeof(BestAttack)); + break; default: // set to empty @@ -4233,12 +4410,14 @@ INT16 ubMinAPCost; } // NB a desire of 4 or more is only achievable by brave/aggressive guys with high morale + UINT16 usRange = GetModifiedGunRange(pSoldier->inv[ BestAttack.bWeaponIn ].usItem); + if ( (pSoldier->bActionPoints == pSoldier->bInitialActionPoints) && (ubBestAttackAction == AI_ACTION_FIRE_GUN) && (pSoldier->aiData.bShock == 0) && (pSoldier->stats.bLife >= pSoldier->stats.bLifeMax / 2) && (BestAttack.ubChanceToReallyHit < 30) && - (PythSpacesAway( pSoldier->sGridNo, BestAttack.sTarget ) > Weapon[ pSoldier->inv[ BestAttack.bWeaponIn ].usItem ].usRange / CELL_X_SIZE ) && + (PythSpacesAway( pSoldier->sGridNo, BestAttack.sTarget ) > usRange / CELL_X_SIZE ) && (RangeChangeDesire( pSoldier ) >= 4) ) { // okay, really got to wonder about this... could taking cover be an option? @@ -4383,7 +4562,7 @@ INT16 ubMinAPCost; if (ubBestAttackAction == AI_ACTION_FIRE_GUN) { // Do we need to change stance? NB We'll have to ready our gun again - if ( !TANK( pSoldier ) && ( pSoldier->bActionPoints >= BestAttack.ubAPCost + APBPConstants[AP_CROUCH] + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 1 ) ) ) + if ( !TANK( pSoldier ) && ( pSoldier->bActionPoints >= BestAttack.ubAPCost + GetAPsCrouch( pSoldier, TRUE) + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 1 ) ) ) { // since the AI considers shooting chance from standing primarily, if we are not // standing we should always consider a stance change @@ -4484,13 +4663,13 @@ INT16 ubMinAPCost; iChance = (25 / max((BestAttack.ubAimTime + 1),1)); switch (pSoldier->aiData.bAttitude) { - case DEFENSIVE: iChance += -5; break; - case BRAVESOLO: iChance += 5; break; - case BRAVEAID: iChance += 5; break; - case CUNNINGSOLO: iChance += 0; break; - case CUNNINGAID: iChance += 0; break; - case AGGRESSIVE: iChance += 10; break; - case ATTACKSLAYONLY:iChance += 30; break; + case DEFENSIVE: iChance += -5; break; + case BRAVESOLO: iChance += 5; break; + case BRAVEAID: iChance += 5; break; + case CUNNINGSOLO: iChance += 0; break; + case CUNNINGAID: iChance += 0; break; + case AGGRESSIVE: iChance += 10; break; + case ATTACKSLAYONLY:iChance += 30; break; } // HEADROCK HAM B2.6: Allows control over increased enemy burstfire. @@ -4510,10 +4689,10 @@ INT16 ubMinAPCost; iChance += 5 * ( 15 - PythSpacesAway( pSoldier->sGridNo, BestAttack.sTarget ) ); } } + // HEADROCK HAM 3.6: due to the "else", this part of the formula is NEVER hit. Removing. //else if (PythSpacesAway( pSoldier->sGridNo, BestAttack.sTarget ) < 10 && gGameOptions.ubDifficultyLevel > DIF_LEVEL_EASY ) if (PythSpacesAway( pSoldier->sGridNo, BestAttack.sTarget ) < 10 && gGameOptions.ubDifficultyLevel > DIF_LEVEL_EASY ) - { iChance += 100; } @@ -4535,20 +4714,33 @@ INT16 ubMinAPCost; if (IsGunAutofireCapable( &pSoldier->inv[BestAttack.bWeaponIn] ) && !(Menptr[BestShot.ubOpponent].stats.bLife < OKLIFE) && // don't burst at downed targets (( pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft > 1 && - BestAttack.ubAimTime != BURSTING ) || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) ) + !pSoldier->bDoBurst ) || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack: ENOUGH APs TO AUTOFIRE, RANDOM CHANCE OF DOING SO"); + + FLOAT dTotalRecoil = 0.0f; pSoldier->bDoAutofire = 0; - do - { - pSoldier->bDoAutofire++; - ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier->bDoAutofire ); + if(UsingNewCTHSystem() == true){ + do + { + INT8 bRecoilX = 0; + INT8 bRecoilY = 0; + pSoldier->bDoAutofire++; + dTotalRecoil += AICalcRecoilForShot( pSoldier, &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire ); + ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestShot.bWeaponIn]), pSoldier->bDoAutofire ); + } + while( pSoldier->bActionPoints >= BestShot.ubAPCost + ubBurstAPs + sActualAimTime && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire + && dTotalRecoil <= 10.0f ); + } else { + do + { + pSoldier->bDoAutofire++; + ubBurstAPs = CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier->bDoAutofire ); + } + while( pSoldier->bActionPoints >= BestAttack.ubAPCost + ubBurstAPs && + pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && + GetAutoPenalty(&pSoldier->inv[ BestAttack.bWeaponIn ], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)*pSoldier->bDoAutofire <= 80); } - while( pSoldier->bActionPoints >= BestAttack.ubAPCost + ubBurstAPs && - pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && - GetAutoPenalty(&pSoldier->inv[ BestAttack.bWeaponIn ], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE)*pSoldier->bDoAutofire <= 80); - - pSoldier->bDoAutofire--; if (pSoldier->bDoAutofire > 0) @@ -4606,20 +4798,24 @@ INT16 ubMinAPCost; if ((INT32) PreRandom( 100 ) < iChance || Weapon[pSoldier->inv[BestAttack.bWeaponIn].usItem].NoSemiAuto) { - BestAttack.ubAimTime = AUTOFIRING + pSoldier->bDoAutofire; - BestAttack.ubAPCost = BestAttack.ubAPCost + CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier->bDoAutofire ); + pSoldier->aiData.bAimTime = BestAttack.ubAimTime ; + pSoldier->bDoBurst = 1; + BestAttack.ubAPCost = BestAttack.ubAPCost + CalcAPsToAutofire( pSoldier->CalcActionPoints(), &(pSoldier->inv[BestAttack.bWeaponIn]), pSoldier->bDoAutofire ) + sActualAimTime; + } + else + { + pSoldier->bDoAutofire = 0; + pSoldier->bDoBurst = 0; } } } - else - { - // HEADROCK HAM 3.6: No no no! This line removes all aiming from a potentially deadly single-shot! Commenting out. - //pSoldier->aiData.bAimTime = 0; - pSoldier->aiData.bAimTime = BestAttack.ubAimTime; - pSoldier->bDoBurst = 0; - pSoldier->bDoAutofire = 0; - // not enough aps - do somthing else - } + } + + if (!pSoldier->bDoBurst) + { + pSoldier->aiData.bAimTime = BestAttack.ubAimTime; + pSoldier->bDoBurst = 0; + pSoldier->bDoAutofire = 0; } ////////////////////////////////////////////////////////////////////////// @@ -4629,6 +4825,10 @@ INT16 ubMinAPCost; + // HEADROCK HAM 4: No longer necessary to do here. The conditions above already handle this, specifically + // WITHOUT messing with the BestAttack.ubAimTime variable, since that can apply now even when bursting + // or autofiring!! + /* if (BestAttack.ubAimTime == BURSTING) { pSoldier->aiData.bAimTime = 0; @@ -4642,7 +4842,7 @@ INT16 ubMinAPCost; pSoldier->bDoAutofire = BestAttack.ubAimTime-AUTOFIRING; BestAttack.ubAimTime = AUTOFIRING; - } + }*/ /* else // defaults already set @@ -4669,6 +4869,32 @@ INT16 ubMinAPCost; } } + // SANDRO - chance to make aimed punch/stab for martial arts/melee + else if (ubBestAttackAction == AI_ACTION_KNIFE_MOVE && gGameOptions.fNewTraitSystem) + { + pSoldier->aiData.bAimTime = 0; + + if (Item[pSoldier->inv[BestAttack.bWeaponIn].usItem].usItemClass == IC_PUNCH) + { + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT)) + { + if( PreRandom( (gGameExternalOptions.fEnhancedCloseCombatSystem ? 2 : 0) + 2 * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT) ) > 2 ) + { + pSoldier->aiData.bAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6); + } + } + } + else + { + if (HAS_SKILL_TRAIT( pSoldier, MELEE_NT)) + { + if( PreRandom( gGameExternalOptions.fEnhancedCloseCombatSystem ? 3 : 1 ) > 0 ) + { + pSoldier->aiData.bAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6); + } + } + } + } ////////////////////////////////////////////////////////////////////////// // OTHERWISE, JUST GO AHEAD & ATTACK! @@ -4889,59 +5115,63 @@ INT16 ubMinAPCost; // if not in water and not already crouched, try to crouch down first if (!gfTurnBasedAI || GetAPsToChangeStance( pSoldier, ANIM_CROUCH ) <= pSoldier->bActionPoints) { - if ( !fCivilian && !gfHiddenInterrupt && IsValidStance( pSoldier, ANIM_CROUCH ) ) + if ( !fCivilian && !gfHiddenInterrupt && IsValidStance( pSoldier, ANIM_CROUCH ) && ubBestAttackAction != AI_ACTION_KNIFE_MOVE && ubBestAttackAction != AI_ACTION_KNIFE_STAB && ubBestAttackAction != AI_ACTION_STEAL_MOVE) // SANDRO - if knife attack don't crouch { - pSoldier->aiData.usActionData = StanceChange( pSoldier, BestAttack.ubAPCost ); - if (pSoldier->aiData.usActionData != 0) + // determine the location of the known closest opponent + // (don't care if he's conscious, don't care if he's reachable at all) + + sClosestOpponent = ClosestSeenOpponent(pSoldier, NULL, NULL); + // SANDRO - don't crouch if in close combat distance (we got penalties that way) + if (PythSpacesAway(pSoldier->sGridNo, sClosestOpponent) > 1 ) { - if (pSoldier->aiData.usActionData == ANIM_PRONE) + pSoldier->aiData.usActionData = StanceChange( pSoldier, BestAttack.ubAPCost ); + if (pSoldier->aiData.usActionData != 0) { - // we might want to turn before lying down! - if ( (!gfTurnBasedAI || GetAPsToLook( pSoldier ) <= pSoldier->bActionPoints - GetAPsToChangeStance( pSoldier, (INT8) pSoldier->aiData.usActionData )) && - (((pSoldier->aiData.bAIMorale > MORALE_HOPELESS) || ubCanMove) && !AimingGun(pSoldier)) ) + if (pSoldier->aiData.usActionData == ANIM_PRONE) { - // determine the location of the known closest opponent - // (don't care if he's conscious, don't care if he's reachable at all) - - sClosestOpponent = ClosestSeenOpponent(pSoldier, NULL, NULL); - // if we have a closest seen opponent - if (!TileIsOutOfBounds(sClosestOpponent)) + // we might want to turn before lying down! + if ( (!gfTurnBasedAI || GetAPsToLook( pSoldier ) <= pSoldier->bActionPoints - GetAPsToChangeStance( pSoldier, (INT8) pSoldier->aiData.usActionData )) && + (((pSoldier->aiData.bAIMorale > MORALE_HOPELESS) || ubCanMove) && !AimingGun(pSoldier)) ) { - bDirection = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sClosestOpponent),CenterY(sClosestOpponent)); - - // if we're not facing towards him - if (pSoldier->ubDirection != bDirection) + // if we have a closest seen opponent + if (!TileIsOutOfBounds(sClosestOpponent)) { - if ( pSoldier->InternalIsValidStance( bDirection, (INT8) pSoldier->aiData.usActionData) ) + bDirection = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sClosestOpponent),CenterY(sClosestOpponent)); + + // if we're not facing towards him + if (pSoldier->ubDirection != bDirection) { - // change direction, THEN change stance! - pSoldier->aiData.bNextAction = AI_ACTION_CHANGE_STANCE; - pSoldier->aiData.usNextActionData = pSoldier->aiData.usActionData; - pSoldier->aiData.usActionData = bDirection; + if ( pSoldier->InternalIsValidStance( bDirection, (INT8) pSoldier->aiData.usActionData) ) + { + // change direction, THEN change stance! + pSoldier->aiData.bNextAction = AI_ACTION_CHANGE_STANCE; + pSoldier->aiData.usNextActionData = pSoldier->aiData.usActionData; + pSoldier->aiData.usActionData = bDirection; #ifdef DEBUGDECISIONS - sprintf(tempstr,"%s - TURNS to face CLOSEST OPPONENT in direction %d",pSoldier->name,pSoldier->aiData.usActionData); - AIPopMessage(tempstr); + sprintf(tempstr,"%s - TURNS to face CLOSEST OPPONENT in direction %d",pSoldier->name,pSoldier->aiData.usActionData); + AIPopMessage(tempstr); #endif - return(AI_ACTION_CHANGE_FACING); - } - else if ( (pSoldier->aiData.usActionData == ANIM_PRONE) && (pSoldier->InternalIsValidStance( bDirection, ANIM_CROUCH) ) ) - { - // we shouldn't go prone, since we can't turn to shoot - pSoldier->aiData.usActionData = ANIM_CROUCH; - pSoldier->aiData.bNextAction = AI_ACTION_END_TURN; - return( AI_ACTION_CHANGE_STANCE ); + return(AI_ACTION_CHANGE_FACING); + } + else if ( (pSoldier->aiData.usActionData == ANIM_PRONE) && (pSoldier->InternalIsValidStance( bDirection, ANIM_CROUCH) ) ) + { + // we shouldn't go prone, since we can't turn to shoot + pSoldier->aiData.usActionData = ANIM_CROUCH; + pSoldier->aiData.bNextAction = AI_ACTION_END_TURN; + return( AI_ACTION_CHANGE_STANCE ); + } } + // else we are facing in the right direction + } - // else we are facing in the right direction - + // else we don't know any enemies } - // else we don't know any enemies - } - // we don't want to turn + // we don't want to turn + } + pSoldier->aiData.bNextAction = AI_ACTION_END_TURN; + return( AI_ACTION_CHANGE_STANCE ); } - pSoldier->aiData.bNextAction = AI_ACTION_END_TURN; - return( AI_ACTION_CHANGE_STANCE ); } } } diff --git a/TacticalAI/FindLocations.cpp b/TacticalAI/FindLocations.cpp index 02a4d30f..aac2f01e 100644 --- a/TacticalAI/FindLocations.cpp +++ b/TacticalAI/FindLocations.cpp @@ -33,6 +33,12 @@ #include "PathAIDebug.h" +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - all "APBPConstants[AP_CROUCH]" and "APBPConstants[AP_PRONE]" here +// were changed to GetAPsCrouch() and GetAPsProne() +// - also all "APBPConstants[AP_PICKUP_ITEM]" were replaced by GetBasicAPsToPickupItem() +//////////////////////////////////////////////////////////////////////////////////////////////////////// + INT16 * gsCoverValue = NULL; #ifdef _DEBUG @@ -128,13 +134,13 @@ INT8 CalcWorstCTGTForPosition( SOLDIERTYPE * pSoldier, UINT8 ubOppID, INT32 sOpp switch (bCubeLevel) { case 1: - if (iMyAPsLeft < APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) + if (iMyAPsLeft < GetAPsCrouch(pSoldier,TRUE) + GetAPsProne(pSoldier,TRUE)) { continue; } break; case 2: - if (iMyAPsLeft < APBPConstants[AP_CROUCH]) + if (iMyAPsLeft < GetAPsCrouch(pSoldier,TRUE)) { continue; } @@ -168,13 +174,13 @@ INT8 CalcAverageCTGTForPosition( SOLDIERTYPE * pSoldier, UINT8 ubOppID, INT32 sO switch (bCubeLevel) { case 1: - if (iMyAPsLeft < APBPConstants[AP_CROUCH] + APBPConstants[AP_PRONE]) + if (iMyAPsLeft < GetAPsCrouch(pSoldier,TRUE) + GetAPsProne(pSoldier,TRUE)) { continue; } break; case 2: - if (iMyAPsLeft < APBPConstants[AP_CROUCH]) + if (iMyAPsLeft < GetAPsCrouch(pSoldier,TRUE)) { continue; } @@ -430,7 +436,7 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i { // if I CAN'T crouch when I get there, that makes it significantly less // appealing a spot (how much depends on range), so that's a penalty to me - if (iMyAPsLeft < APBPConstants[AP_CROUCH]) + if (iMyAPsLeft < GetAPsCrouch(pMe,TRUE)) // subtract another 1 % penalty for NOT being able to crouch per tile // the farther away we are, the bigger a difference crouching will make! iMyPosValue -= ((iMyPosValue * (AIM_PENALTY_TARGET_CROUCHED + (iRange / CELL_X_SIZE))) / 100); @@ -1662,7 +1668,7 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem ) return AI_ACTION_NONE; } - if (pSoldier->bActionPoints < APBPConstants[AP_PICKUP_ITEM]) + if (pSoldier->bActionPoints < GetBasicAPsToPickupItem( pSoldier )) { return( AI_ACTION_NONE ); } @@ -1719,7 +1725,7 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem ) // set an AP limit too, to our APs less the cost of picking up an item // and less the cost of dropping an item since we might need to do that - gubNPCAPBudget = pSoldier->bActionPoints - APBPConstants[AP_PICKUP_ITEM]; + gubNPCAPBudget = pSoldier->bActionPoints - GetBasicAPsToPickupItem( pSoldier ); // reset the "reachable" flags in the region we're looking at for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++) @@ -1922,7 +1928,12 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem ) // WANNE: Fix a vanilla bug: When an enemy soldier is looking for items and finds a non-helmet/vest/leggings piece of armour it was incorrectly considered for pickup. // Fixed by Tron (Stracciatella): Revision: 5719 // break; - continue; + // continue; <- silversurfer: bad idea, this causes the game to hang + // to make sure that the item isn't considered set iTempValue to zero and get out + { + iTempValue = 0; + break; + } } } else @@ -1959,7 +1970,7 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem ) //if (pSoldier->inv[HANDPOS].exists() == true && PlaceInAnyPocket(pSoldier, &pSoldier->inv[HANDPOS], false) == false) if (FindBetterSpotForItem( pSoldier, HANDPOS ) == FALSE) { - if (pSoldier->bActionPoints < APBPConstants[AP_PICKUP_ITEM] + APBPConstants[AP_PICKUP_ITEM]) + if (pSoldier->bActionPoints < GetBasicAPsToPickupItem( pSoldier ) + GetBasicAPsToPickupItem( pSoldier )) { return( AI_ACTION_NONE ); } @@ -1968,7 +1979,7 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem ) // destroy this item! DebugAI( String( "%d decides he must drop %S first so destroys it", pSoldier->ubID, ItemNames[ pSoldier->inv[HANDPOS].usItem ] ) ); DeleteObj( &(pSoldier->inv[HANDPOS]) ); - DeductPoints( pSoldier, APBPConstants[AP_PICKUP_ITEM], 0 ); + DeductPoints( pSoldier, GetBasicAPsToPickupItem( pSoldier ), 0 ); } else { diff --git a/TacticalAI/Medical.cpp b/TacticalAI/Medical.cpp index 6ad26b7c..2e4eeb3e 100644 --- a/TacticalAI/Medical.cpp +++ b/TacticalAI/Medical.cpp @@ -15,6 +15,9 @@ #include "Buildings.h" #include "worldman.h" #include "Assignments.h" + // added by SANDRO + #include "Soldier Profile.h" + #include "GameSettings.h" #endif //forward declarations of common classes to eliminate includes @@ -465,3 +468,47 @@ INT8 DecideAutoBandage( SOLDIERTYPE * pSoldier ) // do nothing return( AI_ACTION_NONE ); } + +// SANDRO - added a function +BOOLEAN DoctorIsPresent( SOLDIERTYPE * pPatient, BOOLEAN fOnDoctorAssignmentCheck ) +{ + SOLDIERTYPE * pMedic = NULL; + UINT8 cnt; + INT8 bSlot; + BOOLEAN fDoctorHasBeenFound = FALSE; + + cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; + for ( pMedic = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; cnt++,pMedic++) + { + if ( !(pMedic->bActive) || !(pMedic->bInSector) || ( pMedic->flags.uiStatusFlags & SOLDIER_VEHICLE ) || (pMedic->bAssignment == VEHICLE ) ) + { + // is nowhere around! + continue; // NEXT!!! + } + + if ( pPatient->ubID == pMedic->ubID ) + { + // cannot make surgery on self! + continue; // NEXT!!! + } + if ( fOnDoctorAssignmentCheck && pMedic->bAssignment != DOCTOR ) + { + // not on the right assignment! + continue; // NEXT!!! + } + + bSlot = FindMedKit( pMedic ); + if (bSlot == NO_SLOT) + { + // no medical kit! + continue; // NEXT!!! + } + + if (pMedic->stats.bLife > OKLIFE && !(pMedic->bCollapsed) && pMedic->stats.bMedical > 0 && (NUM_SKILL_TRAITS( pMedic, DOCTOR_NT ) >= gSkillTraitValues.ubDONumberTraitsNeededForSurgery)) + { + fDoctorHasBeenFound = TRUE; + } + } + + return( fDoctorHasBeenFound ); +} diff --git a/TacticalAI/Movement.cpp b/TacticalAI/Movement.cpp index 7e60dbf4..6483c671 100644 --- a/TacticalAI/Movement.cpp +++ b/TacticalAI/Movement.cpp @@ -7,7 +7,7 @@ #include "overhead.h" #include "worldman.h" #include "pathai.h" - #include "points.h" + //#include "points.h" #include "message.h" #include "Smell.h" #include "mapscreen.h" @@ -720,7 +720,7 @@ INT32 InternalGoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, IN if (pSoldier->usUIMovementMode == RUNNING) { - sAPCost += APBPConstants[AP_START_RUN_COST]; + sAPCost += GetAPsStartRun( pSoldier ); // changed by SANDRO } } diff --git a/TacticalAI/NPC.cpp b/TacticalAI/NPC.cpp index 16b3337d..3fb618e1 100644 --- a/TacticalAI/NPC.cpp +++ b/TacticalAI/NPC.cpp @@ -47,15 +47,21 @@ #include "Scheduling.h" #include "Tactical Save.h" #include "Campaign Types.h" + #include "GameSettings.h" // added by SANDRO + #include "Soldier Profile.h" #endif - + #include "Soldier Profile.h" //forward declarations of common classes to eliminate includes class OBJECTTYPE; class SOLDIERTYPE; // WANNE - BMP: DONE! //SB: new .npc format -#define NPCEX_SIGNATURE 0x00070000 +#define _MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((UINT32)(UINT8)(ch0) | ((UINT32)(UINT8)(ch1) << 8) | \ + ((UINT32)(UINT8)(ch2) << 16) | ((UINT32)(UINT8)(ch3) << 24 )) + +#define NPCEX_SIGNATURE _MAKEFOURCC('B','1','1','3') #define NUM_CIVQUOTE_SECTORS 20 #define MINERS_CIV_QUOTE_INDEX 16 @@ -143,7 +149,9 @@ NPCQuoteInfo * LoadQuoteFile( UINT8 ubNPC ) // use a copy of Herve's data file instead! sprintf( zFileName, "NPCData\\%03d.npc", HERVE ); } - else if ( ubNPC < FIRST_RPC || ubNPC >= GASTON || (ubNPC < FIRST_NPC && gMercProfiles[ ubNPC ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) ) + //else if ( ubNPC < FIRST_RPC || ubNPC >= GASTON || (ubNPC < FIRST_NPC && gMercProfiles[ ubNPC ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) ) + //new profiles by Jazz + else if ( gProfilesIMP[ubNPC].ProfilId == ubNPC || gProfilesAIM[ubNPC].ProfilId == ubNPC || gProfilesMERC[ubNPC].ProfilId == ubNPC || ( gProfilesRPC[ubNPC].ProfilId == ubNPC && gMercProfiles[ ubNPC ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED ) ) { sprintf( zFileName, "NPCData\\000.npc", ubNPC ); } @@ -257,7 +265,7 @@ NPCQuoteInfo& NPCQuoteInfo::operator=(const _old_NPCQuoteInfo& src) ubLastDay = src.ubLastDay; ubApproachRequired = src.ubApproachRequired; ubOpinionRequired = src.ubOpinionRequired; - ubUnused = 0; + usUnused = 0; ubQuoteNum = src.ubQuoteNum; ubNumQuotes = src.ubNumQuotes; ubStartQuest = src.ubStartQuest; @@ -305,7 +313,9 @@ BOOLEAN EnsureQuoteFileLoaded( UINT8 ubNPC ) fLoadFile = TRUE; } - if ( ubNPC >= FIRST_RPC && ubNPC < FIRST_NPC ) +// if ( ubNPC >= FIRST_RPC && ubNPC < FIRST_NPC ) + //new profiles by Jazz + if ( ( gProfilesRPC[ubNPC].ProfilId == ubNPC ) ) { if (gMercProfiles[ ubNPC ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED) { @@ -415,20 +425,31 @@ BOOLEAN RefreshNPCScriptRecord( UINT8 ubNPC, UINT8 ubRecord ) { // we have some work to do... // loop through all PCs, and refresh their copy of this record - for ( ubLoop = 0; ubLoop < FIRST_RPC; ubLoop++ ) // need more finesse here + //for ( ubLoop = 0; ubLoop < FIRST_RPC; ubLoop++ ) // need more finesse here + //new profiles by Jazz + for ( ubLoop = 0; ubLoop < NUM_PROFILES; ubLoop++ ) // need more finesse here { + //new profiles by Jazz + if ( gProfilesIMP[ubLoop].ProfilId == ubLoop || gProfilesAIM[ubLoop].ProfilId == ubLoop || gProfilesMERC[ubLoop].ProfilId == ubLoop ) RefreshNPCScriptRecord( ubLoop, ubRecord ); } - for ( ubLoop = GASTON; ubLoop < NUM_PROFILES; ubLoop++ ) // need more finesse here - { - RefreshNPCScriptRecord( ubLoop, ubRecord ); - } - for ( ubLoop = FIRST_RPC; ubLoop < FIRST_NPC; ubLoop++ ) + + //for ( ubLoop = GASTON; ubLoop < NUM_PROFILES; ubLoop++ ) // need more finesse here + //{ + // RefreshNPCScriptRecord( ubLoop, ubRecord ); + //} + + //new profiles by Jazz + //for ( ubLoop = FIRST_RPC; ubLoop < FIRST_NPC; ubLoop++ ) + for ( ubLoop = 0; ubLoop < NUM_PROFILES; ubLoop++ ) { + if ( gProfilesRPC[ubLoop].ProfilId == ubLoop ) + { if ( gMercProfiles[ ubNPC ].ubMiscFlags & PROFILE_MISC_FLAG_RECRUITED && gpBackupNPCQuoteInfoArray[ ubNPC ] != NULL ) { RefreshNPCScriptRecord( ubLoop, ubRecord ); } + } } return( TRUE ); } @@ -462,21 +483,87 @@ NPCQuoteInfo * LoadCivQuoteFile( UINT8 ubIndex ) NPCQuoteInfo * pFileData; UINT32 uiBytesRead; UINT32 uiFileSize; + DWORD uiSignature = 0; // SB // WANNE - BMP: DONE! - if ( ubIndex == MINERS_CIV_QUOTE_INDEX ) - { - sprintf( zFileName, "NPCData\\miners.npc" ); - } - else - { - sprintf( zFileName, "NPCData\\%c%d.npc", 'A' + ( gsCivQuoteSector[ ubIndex ][ 1 ] - 1 ), gsCivQuoteSector[ ubIndex ][ 0 ] ); - } + if ( ubIndex == MINERS_CIV_QUOTE_INDEX ) + { + sprintf( zFileName, "NPCData\\miners.npc" ); + } + else + { + sprintf( zFileName, "NPCData\\%c%d.npc", 'A' + ( gsCivQuoteSector[ ubIndex ][ 1 ] - 1 ), gsCivQuoteSector[ ubIndex ][ 0 ] ); + } CHECKN( FileExists( zFileName ) ); hFile = FileOpen( zFileName, FILE_ACCESS_READ, FALSE ); CHECKN( hFile ); + // ----------------------------------------------------------- + // WANNE: This fixes the bug, that NPCs do not give hints + // Problem was, the missing conversion from old to new NPC structure! + if (!FileRead( hFile, &uiSignature, sizeof(uiSignature), &uiBytesRead ) || uiBytesRead != sizeof(uiSignature) ) + return NULL; + + if(uiSignature == NPCEX_SIGNATURE)//new fmt + { + uiFileSize = sizeof( NPCQuoteInfo ) * NUM_NPC_QUOTE_RECORDS; + pFileData = (NPCQuoteInfo *)MemAlloc( uiFileSize ); + if (pFileData) + { + if (!FileRead( hFile, pFileData, uiFileSize, &uiBytesRead ) || uiBytesRead != uiFileSize ) + { + MemFree( pFileData ); + pFileData = NULL; + } + } + + FileClose( hFile ); + } + else //old fmt - make conversion + { + int iRecord; + _old_NPCQuoteInfo * pFileData_old_; + uiFileSize = sizeof( _old_NPCQuoteInfo ) * NUM_NPC_QUOTE_RECORDS; + pFileData_old_ = ( _old_NPCQuoteInfo * )MemAlloc( uiFileSize ); + FileSeek(hFile, 0, FILE_SEEK_FROM_START); + if (pFileData_old_) + { + if (!FileRead( hFile, pFileData_old_, uiFileSize, &uiBytesRead ) || uiBytesRead != uiFileSize ) + { + MemFree( pFileData_old_ ); + pFileData_old_ = NULL; + } + } + + FileClose( hFile ); + //check for Russian script & make a runtime conversion of it to International + if( *(DWORD*)pFileData_old_ == 0x00350039 ) + { + //just offset records 4 bytes backward + _old_NPCQuoteInfo * pEnglishScript = ( _old_NPCQuoteInfo * )MemAlloc( uiFileSize ); + memcpy( pEnglishScript, ((char*)pFileData_old_)+4, uiFileSize-4 ); + MemFree( pFileData_old_ ); + pFileData_old_ = pEnglishScript; + } + + // Now it's time for conversion + uiFileSize = sizeof(NPCQuoteInfo) * NUM_NPC_QUOTE_RECORDS; + pFileData = (NPCQuoteInfo*)MemAlloc(uiFileSize); + for(iRecord=0; iRecord new script format + return( pFileData ); + + // ----------------------------------------------------------- + // WANNE: This is old vanilla JA2 code without conversion of NPC data to new format used for Big Maps project + /* uiFileSize = sizeof( NPCQuoteInfo ) * NUM_NPC_QUOTE_RECORDS; pFileData = (NPCQuoteInfo *)MemAlloc( uiFileSize ); if (pFileData) @@ -491,6 +578,8 @@ NPCQuoteInfo * LoadCivQuoteFile( UINT8 ubIndex ) FileClose( hFile ); return( pFileData ); + // ----------------------------------------------------------- + */ } @@ -578,8 +667,12 @@ BOOLEAN ReloadAllQuoteFiles( void ) { UINT8 ubProfile, ubLoop; - for ( ubProfile = FIRST_RPC; ubProfile < GASTON; ubProfile++ ) + //for ( ubProfile = FIRST_RPC; ubProfile < GASTON; ubProfile++ ) + //new profiles by Jazz + for ( ubProfile = 0; ubProfile < NUM_PROFILES; ubProfile++ ) { + if ( gProfilesRPC[ubProfile].ProfilId == ubProfile || gProfilesNPC[ubProfile].ProfilId == ubProfile ) + { // zap backup if any if ( gpBackupNPCQuoteInfoArray[ ubProfile ] != NULL ) { @@ -587,6 +680,7 @@ BOOLEAN ReloadAllQuoteFiles( void ) gpBackupNPCQuoteInfoArray[ ubProfile ] = NULL; } ReloadQuoteFileIfLoaded( ubProfile ); + } } // reload all civ quote files for ( ubLoop = 0; ubLoop < NUM_CIVQUOTE_SECTORS; ubLoop++ ) @@ -642,6 +736,12 @@ INT32 CalcThreateningEffectiveness( UINT8 ubMerc ) iDeadliness = -30; } + // SANDRO - bonus for threatening for assertive people + if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_ASSERTIVE ) + { + iDeadliness += 50; + } + return( (EffectiveLeadership( pSoldier ) + iStrength + iDeadliness) / 3 ); //Trail minor bug fix. } @@ -661,6 +761,15 @@ UINT8 CalcDesireToTalk( UINT8 ubNPC, UINT8 ubMerc, INT8 bApproach ) iPersonalVal += pNPCProfile->bMercOpinion[ubMerc]; } + // SANDRO - bonus for communication with people for assertive people + if ( gGameOptions.fNewTraitSystem && bApproach != APPROACH_THREATEN) + { + if ( pMercProfile->bCharacterTrait == CHAR_TRAIT_ASSERTIVE ) + iPersonalVal += 50; + else if ( pMercProfile->bCharacterTrait == CHAR_TRAIT_MALICIOUS ) + iPersonalVal -= 50; + } + // ARM: NOTE - for towns which don't use loyalty (San Mona, Estoni, Tixa, Orta ) // loyalty will always remain 0 (this was OKed by Ian) iTownVal = gTownLoyalty[ pNPCProfile->bTown ].ubRating; @@ -1215,7 +1324,9 @@ UINT8 NPCConsiderReceivingItemFromMerc( UINT8 ubNPC, UINT8 ubMerc, OBJECTTYPE * } break; default: - if ( usItemToConsider == MONEY && (ubNPC == SKYRIDER || (ubNPC >= FIRST_RPC && ubNPC < FIRST_NPC) ) ) + //if ( usItemToConsider == MONEY && (ubNPC == SKYRIDER || (ubNPC >= FIRST_RPC && ubNPC < FIRST_NPC) ) ) + //new profiles by Jazz + if ( usItemToConsider == MONEY && (ubNPC == SKYRIDER || ( gProfilesRPC[ubNPC].ProfilId == ubNPC ) ) ) { if ( gMercProfiles[ ubNPC ].iBalance < 0 && pNPCQuoteInfo->sActionData != NPC_ACTION_DONT_ACCEPT_ITEM ) { @@ -1603,14 +1714,23 @@ void ResetOncePerConvoRecordsForNPC( UINT8 ubNPC ) void ResetOncePerConvoRecordsForAllNPCsInLoadedSector( void ) { UINT8 ubLoop; - + UINT8 IDnpc; + if ( gWorldSectorX == 0 || gWorldSectorY == 0 ) { return; } - for ( ubLoop = FIRST_RPC; ubLoop < GASTON; ubLoop++ ) + //for ( ubLoop = FIRST_RPC; ubLoop < GASTON; ubLoop++ ) + //new profiles by Jazz + for ( IDnpc = 0; IDnpc < NUM_PROFILES; IDnpc++ ) { + + if ( gProfilesRPC[IDnpc].ProfilId == IDnpc || gProfilesNPC[IDnpc].ProfilId == IDnpc) + { + ubLoop = IDnpc; + + if ( gMercProfiles[ ubLoop ].sSectorX == gWorldSectorX && gMercProfiles[ ubLoop ].sSectorY == gWorldSectorY && gMercProfiles[ ubLoop ].bSectorZ == gbWorldSectorZ && @@ -1618,6 +1738,9 @@ void ResetOncePerConvoRecordsForAllNPCsInLoadedSector( void ) { ResetOncePerConvoRecordsForNPC( ubLoop ); } + + } + } } @@ -1695,7 +1818,15 @@ void Converse( UINT8 ubNPC, UINT8 ubMerc, INT8 bApproach, UINT32 uiApproachData } return; } + pNPCQuoteInfoArray = gpNPCQuoteInfoArray[ubNPC]; + + //Legion jazz + if (zHiddenNames[ubNPC].Hidden == TRUE) + { + zHiddenNames[ubNPC].Hidden = FALSE; + } + pProfile = &(gMercProfiles[ubNPC]); switch( bApproach ) @@ -1849,7 +1980,7 @@ void Converse( UINT8 ubNPC, UINT8 ubMerc, INT8 bApproach, UINT32 uiApproachData break; case TRIGGER_NPC: // if triggering, pass in the approach data as the record to consider - DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Handling trigger %S/%d at %ld", gMercProfiles[ ubNPC ].zNickname, (UINT8)uiApproachData, GetJA2Clock() ) ); + DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Handling trigger %S/%d at %lu", gMercProfiles[ ubNPC ].zNickname, (UINT8)uiApproachData, GetJA2Clock() ) ); NPCConsiderTalking( ubNPC, ubMerc, bApproach, (UINT8)uiApproachData, pNPCQuoteInfoArray, &pQuotePtr, &ubRecordNum ); break; default: @@ -2242,6 +2373,11 @@ void Converse( UINT8 ubNPC, UINT8 ubMerc, INT8 bApproach, UINT32 uiApproachData case APPROACH_DECLARATION_OF_HOSTILITY: case APPROACH_INITIAL_QUOTE: case APPROACH_GIVINGITEM: + // SANDRO - new records - NPCs discovered + if ( pProfile->ubLastDateSpokenTo == 0 && FindSoldierByProfileID( ubMerc, TRUE ) != NULL ) + { + gMercProfiles[ubMerc].records.usNPCsDiscovered++; + } pProfile->ubLastDateSpokenTo = (UINT8) GetWorldDay(); break; default: diff --git a/TacticalAI/NPC.h b/TacticalAI/NPC.h index 9735c6bd..1bc365fc 100644 --- a/TacticalAI/NPC.h +++ b/TacticalAI/NPC.h @@ -90,8 +90,6 @@ public: // conditions INT16 sRequiredItem; // item NPC must have to say quote - INT32 sRequiredGridNo; // location for NPC req'd to say quote - UINT16 usFactMustBeTrue; // ...before saying quote UINT16 usFactMustBeFalse; // ...before saying quote UINT8 ubQuest; // quest must be current to say quote @@ -99,7 +97,6 @@ public: UINT8 ubLastDay; // last day quote can be said UINT8 ubApproachRequired; // must use this approach to generate quote UINT8 ubOpinionRequired; // opinion needed for this quote - UINT8 ubUnused; // quote to say (if any) UINT8 ubQuoteNum; // this is the quote to say @@ -110,10 +107,17 @@ public: UINT8 ubEndQuest; UINT8 ubTriggerNPC; UINT8 ubTriggerNPCRec; + UINT8 ubFiller; UINT16 usSetFactTrue; UINT16 usGiftItem; // item NPC gives to merc after saying quote + UINT16 usUnused; INT16 sActionData; // special action value + + INT32 sRequiredGridNo; // location for NPC req'd to say quote INT32 usGoToGridNo; + UINT16 usSourceDialogueLevel; // reserved for future use + UINT16 usDestDialogueLevel; // reserved for future use + public: NPCQuoteInfo& operator=(const _old_NPCQuoteInfo& src); }; diff --git a/TacticalAI/TacticalAI_VS2005.vcproj b/TacticalAI/TacticalAI_VS2005.vcproj new file mode 100644 index 00000000..c76ab393 --- /dev/null +++ b/TacticalAI/TacticalAI_VS2005.vcproj @@ -0,0 +1,431 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TacticalAI/TacticalAI_VS2008.vcproj b/TacticalAI/TacticalAI_VS2008.vcproj index 3be2d51d..916cf2ec 100644 --- a/TacticalAI/TacticalAI_VS2008.vcproj +++ b/TacticalAI/TacticalAI_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > diff --git a/TacticalAI/TacticalAI_VS2010.vcxproj b/TacticalAI/TacticalAI_VS2010.vcxproj new file mode 100644 index 00000000..157d03bd --- /dev/null +++ b/TacticalAI/TacticalAI_VS2010.vcxproj @@ -0,0 +1,233 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + {B369A125-E62E-46AE-9285-58003D688301} + Win32Proj + TacticalAI + TacticalAI + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + + + + + MultiThreaded + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/TacticalAI/TacticalAI_VS2010.vcxproj.filters b/TacticalAI/TacticalAI_VS2010.vcxproj.filters new file mode 100644 index 00000000..d2be0d58 --- /dev/null +++ b/TacticalAI/TacticalAI_VS2010.vcxproj.filters @@ -0,0 +1,75 @@ + + + + + {2552d0a1-b3ed-43af-a06c-d0737ce6a63f} + + + {0f98d0d9-dbab-4dc2-8aa6-ee517a6ceab6} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/TacticalAI/ai.h b/TacticalAI/ai.h index 773e77e9..f82d04b4 100644 --- a/TacticalAI/ai.h +++ b/TacticalAI/ai.h @@ -97,6 +97,7 @@ typedef enum AI_ACTION_TRAVERSE_DOWN, // move down a level AI_ACTION_OFFER_SURRENDER, // offer surrender to the player AI_ACTION_RAISE_GUN, + AI_ACTION_STEAL_MOVE, // added by SANDRO } ActionType; diff --git a/TileEngine/Explosion Control.cpp b/TileEngine/Explosion Control.cpp index e825fb04..82066367 100644 --- a/TileEngine/Explosion Control.cpp +++ b/TileEngine/Explosion Control.cpp @@ -67,6 +67,8 @@ #include "fov.h" #include "Map Information.h" #include "Soldier Functions.h"//dnl ch40 200909 +#include "Text.h" // added by SANDRO +#include "campaign.h" // yet another one added #endif #include "Soldier Macros.h" @@ -1477,6 +1479,294 @@ BOOLEAN DamageSoldierFromBlast( UINT8 ubPerson, UINT8 ubOwner, INT32 sBombGridNo { sNewWoundAmt = 0; } + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - STOMP traits + else + { + if ( (MercPtrs[ ubOwner ] != NULL) && gGameOptions.fNewTraitSystem) + { + // Demolitions damage bonus with bombs and mines + if ( HAS_SKILL_TRAIT( MercPtrs[ ubOwner ], DEMOLITIONS_NT ) && + Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_NORMAL && Item[usItem].usItemClass == IC_BOMB && + (!Item[usItem].attachment || Item[usItem].mine )) + { + sNewWoundAmt = (INT16)(((sNewWoundAmt * (100 + gSkillTraitValues.ubDEDamageOfBombsAndMines)) / 100) + 0.5); + } + // Heavy Weapons trait bonus damage to tanks + if ( HAS_SKILL_TRAIT( MercPtrs[ ubOwner ], HEAVY_WEAPONS_NT ) && TANK( pSoldier ) && + Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_NORMAL ) + { + sNewWoundAmt = (INT16)(((sNewWoundAmt * (100 + gSkillTraitValues.ubHWDamageTanksBonusPercent * NUM_SKILL_TRAITS( MercPtrs[ ubOwner ], HEAVY_WEAPONS_NT ))) / 100) + 0.5); // +30% + } + // Heavy Weapons trait bonus damage with rocket, grenade launchers and mortar + else if ( HAS_SKILL_TRAIT( MercPtrs[ ubOwner ], HEAVY_WEAPONS_NT ) && + Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_NORMAL && + ((Item[usItem].usItemClass == IC_BOMB && Item[usItem].attachment && !Item[usItem].mine ) || // mortar shells + (Item[usItem].usItemClass == IC_GRENADE && (Item[usItem].glgrenade || Item[usItem].electronic) ) || // rockets for rocketlaunchers (I haven't found any other way) + (Item[usItem].usItemClass == IC_LAUNCHER ) || Item[usItem].rocketlauncher || Item[usItem].singleshotrocketlauncher ) ) + { + sNewWoundAmt = (INT16)(((sNewWoundAmt * (100 + gSkillTraitValues.ubHWDamageBonusPercentForHW * NUM_SKILL_TRAITS( MercPtrs[ ubOwner ], HEAVY_WEAPONS_NT ))) / 100) + 0.5); // +15% + } + } + // adjust damage resistance of TANKS + if ( TANK( pSoldier ) && gGameOptions.fNewTraitSystem ) + { + sNewWoundAmt = (INT16)(sNewWoundAmt * (100 - gSkillTraitValues.bTanksDamageResistanceModifier) / 100); + // another half of this for ordinary grenades + if ( (( Item[usItem].usItemClass == IC_GRENADE ) || Item[usItem].glgrenade ) && !Item[usItem].electronic ) + sNewWoundAmt = (INT16)(sNewWoundAmt * (100 - (gSkillTraitValues.bTanksDamageResistanceModifier / 2)) / 100); + } + + // Bodybuilding damage resistance + if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, BODYBUILDING_NT ) ) + sNewWoundAmt = max( 1, (INT16)(sNewWoundAmt * (100 - gSkillTraitValues.ubBBDamageResistance) / 100)); + + // Damage resistance for Militia + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.bGreenMilitiaDamageResistance != 0) + sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.bGreenMilitiaDamageResistance) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.bRegularMilitiaDamageResistance != 0) + sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.bRegularMilitiaDamageResistance) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.bVeteranMilitiaDamageResistance != 0) + sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.bVeteranMilitiaDamageResistance) /100); + // bonus for enemy too + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminDamageResistance != 0) + sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.sEnemyAdminDamageResistance) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularDamageResistance != 0) + sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.sEnemyRegularDamageResistance) /100); + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0) + sNewWoundAmt -= ((sNewWoundAmt * gGameExternalOptions.sEnemyEliteDamageResistance) /100); + + // we can loose stats due to being hit by the blast + else if ( gGameOptions.fNewTraitSystem && Explosive[Item[usItem].ubClassIndex].ubType == EXPLOSV_NORMAL && + !AM_A_ROBOT( pSoldier ) && !(pSoldier->flags.uiStatusFlags & SOLDIER_MONSTER) && + sNewWoundAmt > 2 && sNewWoundAmt < pSoldier->stats.bLife ) + { + if ( PreRandom( sNewWoundAmt ) > gSkillTraitValues.ubDamageNeededToLoseStats ) + { + UINT8 ubStatLoss = PreRandom( sNewWoundAmt ) + 1; + UINT8 ubPickStat = PreRandom( 20 ); + if (ubPickStat < 3 ) // 15% chance to lose Wisdom + { + if (ubStatLoss >= pSoldier->stats.bWisdom) + { + ubStatLoss = pSoldier->stats.bWisdom - 1; + } + if ( ubStatLoss > 0 ) + { + pSoldier->stats.bWisdom -= ubStatLoss; + pSoldier->ubCriticalStatDamage[DAMAGED_STAT_WISDOM] += ubStatLoss; + + if (pSoldier->ubProfile != NO_PROFILE) + { + gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom; + } + + if (pSoldier->name[0] && pSoldier->bVisible == TRUE) + { + // make stat RED for a while... + pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( WIS_INCREASE ); + + if (ubStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_WISDOM], pSoldier->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_WISDOM], pSoldier->name, ubStatLoss ); + } + } + } + } + else if (ubPickStat < 7 ) // 20% chance to lose Dexterity + { + if (ubStatLoss >= pSoldier->stats.bDexterity) + { + ubStatLoss = pSoldier->stats.bDexterity - 1; + } + if ( ubStatLoss > 0 ) + { + pSoldier->stats.bDexterity -= ubStatLoss; + pSoldier->ubCriticalStatDamage[DAMAGED_STAT_DEXTERITY] += ubStatLoss; + + if (pSoldier->ubProfile != NO_PROFILE) + { + gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity; + } + + if (pSoldier->name[0] && pSoldier->bVisible == TRUE) + { + // make stat RED for a while... + pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( DEX_INCREASE ); + + if (ubStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_DEX], pSoldier->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_DEX], pSoldier->name, ubStatLoss ); + } + } + } + } + else if (ubPickStat < 11 ) // 20% chance to lose Strength + { + if (ubStatLoss >= pSoldier->stats.bStrength) + { + ubStatLoss = pSoldier->stats.bStrength - 1; + } + if ( ubStatLoss > 0 ) + { + pSoldier->stats.bStrength -= ubStatLoss; + // added this for healing lost stats feature + pSoldier->ubCriticalStatDamage[DAMAGED_STAT_STRENGTH] += ubStatLoss; + + if (pSoldier->ubProfile != NO_PROFILE) + { + gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength; + } + + if (pSoldier->name[0] && pSoldier->bVisible == TRUE) + { + // make stat RED for a while... + pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE ); + + if (ubStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_STRENGTH], pSoldier->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_STRENGTH], pSoldier->name, ubStatLoss ); + } + } + } + } + else if (ubPickStat < 15 ) // 20% chance to lose Agility + { + if (ubStatLoss >= pSoldier->stats.bAgility) + { + ubStatLoss = pSoldier->stats.bAgility - 1; + } + if ( ubStatLoss > 0 ) + { + pSoldier->stats.bAgility -= ubStatLoss; + // added this for healing lost stats feature + pSoldier->ubCriticalStatDamage[DAMAGED_STAT_AGILITY] += ubStatLoss; + + if (pSoldier->ubProfile != NO_PROFILE) + { + gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility; + } + + if (pSoldier->name[0] && pSoldier->bVisible == TRUE) + { + // make stat RED for a while... + pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( AGIL_INCREASE ); + + if (ubStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_1_AGIL], pSoldier->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[STR_LOSES_AGIL], pSoldier->name, ubStatLoss ); + } + } + } + } + else if (ubPickStat < 18 ) // 15% chance to lose Health + { + if (ubStatLoss >= (pSoldier->stats.bLifeMax - OKLIFE)) + { + ubStatLoss = pSoldier->stats.bLifeMax - OKLIFE - 1; + } + if ( ubStatLoss > sNewWoundAmt) + { + ubStatLoss = (UINT8)sNewWoundAmt; + } + if ( ubStatLoss > 0 ) + { + pSoldier->stats.bLifeMax -= ubStatLoss; + pSoldier->ubCriticalStatDamage[DAMAGED_STAT_HEALTH] += ubStatLoss; + + if (pSoldier->ubProfile != NO_PROFILE) + { + gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax; + } + + if (pSoldier->name[0] && pSoldier->bVisible == TRUE) + { + // make stat RED for a while... + pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock(); + pSoldier->usValueGoneUp &= ~( HEALTH_INCREASE ); + + if (ubStatLoss == 1) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_LOSES_ONE_POINT_MAX_HEALTH], pSoldier->name ); + } + else + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_LOSES_X_POINTS_MAX_HEALTH], pSoldier->name, ubStatLoss ); + } + } + } + } + else // 10% chance to be blinded + { + if (pSoldier->bBlindedCounter < ubStatLoss ) + { + pSoldier->bBlindedCounter = ubStatLoss ; + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s was blinded by the blast!", pSoldier->name ); + } + } + // SANDRO - new merc records - times stat damaged + if ( ubStatLoss > 0 && pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++; + } + } + + sNewWoundAmt = max(1, sNewWoundAmt); + } + ////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////// + // SANDRO - option to make special NPCs stronger - damage resistance + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( pSoldier->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + sNewWoundAmt -= (sNewWoundAmt * gGameExternalOptions.usSpecialNPCStronger / 200); + sNewWoundAmt = max( 1, sNewWoundAmt); + break; + } + } + + // SANDRO - new merc records - times wounded (blasted by explosion) + if ( ( sNewWoundAmt > 1 || sBreathAmt > 1000 ) && pSoldier->ubProfile != NO_PROFILE ) + gMercProfiles[ pSoldier->ubProfile ].records.usTimesWoundedBlasted++; + //////////////////////////////////////////////////////////////////////////////////// + // Lesh: flashbang does affect on soldier or not - check it if ( (Item[usItem].usItemClass & IC_EXPLOSV) && fFlashbang ) @@ -3359,12 +3649,18 @@ void DecayBombTimers( void ) if ( (*pObj)[0]->data.misc.ubBombOwner > 1 ) { gubPersonToSetOffExplosions = (UINT8) ((*pObj)[0]->data.misc.ubBombOwner - 2); + // SANDRO - merc records - detonating explosives + if ( MercPtrs[ gubPersonToSetOffExplosions ]->ubProfile != NO_PROFILE && MercPtrs[ gubPersonToSetOffExplosions ]->bTeam == gbPlayerNum ) + { + gMercProfiles[ MercPtrs[ gubPersonToSetOffExplosions ]->ubProfile ].records.usExpDetonated++; + } } else { gubPersonToSetOffExplosions = NOBODY; } + // put this bomb on the queue AddBombToQueue( uiWorldBombIndex, uiTimeStamp ); @@ -3397,6 +3693,17 @@ void SetOffBombsByFrequency( UINT8 ubID, INT8 bFrequency ) // Found a remote bomb, so check to see if it has the same frequency if ((*pObj)[0]->data.misc.bFrequency == bFrequency) { + // SANDRO - added merc records and some exp + if ( ((*pObj)[0]->data.misc.ubBombOwner) > 1 ) + { + if ( MercPtrs[((*pObj)[0]->data.misc.ubBombOwner - 2)]->ubProfile != NO_PROFILE && + MercPtrs[((*pObj)[0]->data.misc.ubBombOwner - 2)]->bTeam == gbPlayerNum ) + { + gMercProfiles[MercPtrs[((*pObj)[0]->data.misc.ubBombOwner - 2)]->ubProfile].records.usExpDetonated++; + + StatChange( MercPtrs[((*pObj)[0]->data.misc.ubBombOwner - 2)], EXPLODEAMT, ( 5 ), FALSE ); + } + } gubPersonToSetOffExplosions = ubID; @@ -3497,6 +3804,14 @@ BOOLEAN SetOffBombsInGridNo( UINT8 ubID, INT32 sGridNo, BOOLEAN fAllBombs, INT8 { gubPersonToSetOffExplosions = ubID; + // SANDRO - merc records + // only if we blew up somebody not in our team(no achievement for blowing our guys :)), only if owner exists and have profile + if ( (MercPtrs[ubID]->bTeam != gbPlayerNum) && ((*pObj)[0]->data.misc.ubBombOwner > 1) ) + { + if ( MercPtrs[ ((*pObj)[0]->data.misc.ubBombOwner - 2) ]->ubProfile != NO_PROFILE && MercPtrs[ ((*pObj)[0]->data.misc.ubBombOwner - 2) ]->bTeam == gbPlayerNum ) + gMercProfiles[ MercPtrs[ ((*pObj)[0]->data.misc.ubBombOwner - 2) ]->ubProfile ].records.usExpDetonated++; + } + // put this bomb on the queue AddBombToQueue( uiWorldBombIndex, uiTimeStamp ); if (pObj->usItem != ACTION_ITEM || (*pObj)[0]->data.misc.bActionValue == ACTION_ITEM_BLOW_UP) diff --git a/TileEngine/Explosion Control.h b/TileEngine/Explosion Control.h index 5af67d2d..79b205b1 100644 --- a/TileEngine/Explosion Control.h +++ b/TileEngine/Explosion Control.h @@ -133,4 +133,12 @@ BOOLEAN DishOutGasDamage( SOLDIERTYPE * pSoldier, EXPLOSIVETYPE * pExplosive, IN void SpreadEffect( INT32 sGridNo, UINT8 ubRadius, UINT16 usItem, UINT8 ubOwner, BOOLEAN fSubsequent, INT8 bLevel, INT32 iSmokeEffectNum , BOOL fFromRemoteClient = FALSE , BOOL fNewSmokeEffect = FALSE ); void AddBombToQueue( UINT32 uiWorldBombIndex, UINT32 uiTimeStamp, BOOL fFromRemoteClient = FALSE ); +extern void ToggleActionItemsByFrequency( INT8 bFrequency ); +extern void PerformItemAction( INT32 sGridNo, OBJECTTYPE * pObj ); +extern BOOLEAN gfExplosionQueueMayHaveChangedSight; +extern void TogglePressureActionItemsInGridNo( INT32 sGridNo ); + +extern BOOLEAN DoesSAMExistHere( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, INT32 sGridNo ); + +extern BOOLEAN HookerInRoom( UINT8 ubRoom ); #endif \ No newline at end of file diff --git a/TileEngine/Interactive Tiles.cpp b/TileEngine/Interactive Tiles.cpp index f11c2708..20f0c9fb 100644 --- a/TileEngine/Interactive Tiles.cpp +++ b/TileEngine/Interactive Tiles.cpp @@ -144,7 +144,7 @@ BOOLEAN StartInteractiveObject( INT32 sGridNo, UINT16 usStructureID, SOLDIERTYPE } -BOOLEAN CalcInteractiveObjectAPs( INT32 sGridNo, STRUCTURE * pStructure, INT16 *psAPCost, INT16 *psBPCost ) +BOOLEAN CalcInteractiveObjectAPs( SOLDIERTYPE * pSoldier, INT32 sGridNo, STRUCTURE * pStructure, INT16 *psAPCost, INT16 *psBPCost ) // SANDRO - added argument { if (pStructure == NULL) { @@ -156,7 +156,8 @@ BOOLEAN CalcInteractiveObjectAPs( INT32 sGridNo, STRUCTURE * pStructure, INT16 * // If closed, we do not know what to do yet... //if ( pStructure->fFlags & STRUCTURE_OPEN ) //{ - *psAPCost = APBPConstants[AP_OPEN_DOOR]; + // SANDRO - changed this + *psAPCost = GetAPsToOpenDoor( pSoldier ); *psBPCost = APBPConstants[AP_OPEN_DOOR]; //} //else @@ -167,7 +168,8 @@ BOOLEAN CalcInteractiveObjectAPs( INT32 sGridNo, STRUCTURE * pStructure, INT16 * } else { - *psAPCost = APBPConstants[AP_OPEN_DOOR]; + // SANDRO - changed this + *psAPCost = GetAPsToOpenDoor( pSoldier ); *psBPCost = APBPConstants[AP_OPEN_DOOR]; } diff --git a/TileEngine/Interactive Tiles.h b/TileEngine/Interactive Tiles.h index ebbad98d..51426ff2 100644 --- a/TileEngine/Interactive Tiles.h +++ b/TileEngine/Interactive Tiles.h @@ -25,7 +25,7 @@ UINT32 GetInteractiveTileCursor( UINT32 uiOldCursor, BOOLEAN fConfirm ); BOOLEAN InteractWithInteractiveObject( SOLDIERTYPE *pSoldier, STRUCTURE *pStructure, UINT8 ubDirection ); BOOLEAN SoldierHandleInteractiveObject( SOLDIERTYPE *pSoldier ); -BOOLEAN CalcInteractiveObjectAPs( INT32 sGridNo, STRUCTURE * pStructure, INT16 *psAPCost, INT16 *psBPCost ); +BOOLEAN CalcInteractiveObjectAPs( SOLDIERTYPE * pSoldier, INT32 sGridNo, STRUCTURE * pStructure, INT16 *psAPCost, INT16 *psBPCost ); // SANDRO - added argument void HandleStructChangeFromGridNo( SOLDIERTYPE *pSoldier, INT32 sGridNo ); diff --git a/TileEngine/Isometric Utils.cpp b/TileEngine/Isometric Utils.cpp index 1a5bb5c7..be4ec71c 100644 --- a/TileEngine/Isometric Utils.cpp +++ b/TileEngine/Isometric Utils.cpp @@ -185,6 +185,344 @@ UINT8 gPurpendicularDirection[ NUM_WORLD_DIRECTIONS ][ NUM_WORLD_DIRECTIONS ] = }; +//----------------------legion by Jazz----------------- + +BOOLEAN FindWindowJumpDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection ) +{ + INT32 cnt; + INT32 sNewGridNo, sOtherSideOfFence; + BOOLEAN fFound = FALSE; + UINT8 bMinNumTurns = 100; + INT8 bNumTurns; + INT8 bMinDirection = 0; + INT8 direction2 = -1; + + if ( pSoldier->ubDirection == NORTH ) + direction2 = NORTH; + else if ( pSoldier->ubDirection == EAST ) + direction2 = EAST; + else if ( pSoldier->ubDirection == SOUTH ) + direction2 = SOUTH; + else if ( pSoldier->ubDirection == WEST ) + direction2 = WEST; + + // WANNE: No need to check on SOUTH and EAST tile, because it is the tile that has the fence we are standing on! + if (direction2 == NORTH || direction2 == WEST) + { + // IF there is a fence in this gridno, return false! + if ( IsJumpableWindowPresentAtGridNo( sGridNo, direction2 ) ) + { + return( FALSE ); + } + } + + // LOOP THROUGH ALL 8 DIRECTIONS + for ( cnt = 0; cnt < 8; cnt+= 2 ) + { + if (cnt != direction2) + continue; + + // get the fence tile + if (cnt == NORTH || cnt == WEST) + { + sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + sOtherSideOfFence = sNewGridNo; + } + // current tile we are standing is the fence tile + else + { + sNewGridNo = sGridNo; + sOtherSideOfFence = NewGridNo( sNewGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + } + + //if ( NewOKDestination( pSoldier, sOtherSideOfFence, TRUE, 0 ) && validDestTile) + if ( NewOKDestination( pSoldier, sOtherSideOfFence, TRUE, 0 ) /*&& validDestTile*/) + { + // ATE: Check if there is somebody waiting here..... + + // Check if we have a fence here + if ( IsJumpableWindowPresentAtGridNo( sNewGridNo , direction2) ) + { + fFound = TRUE; + + // FInd how many turns we should go to get here + bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir ); + + if ( bNumTurns < bMinNumTurns ) + { + bMinNumTurns = bNumTurns; + bMinDirection = (INT8)cnt; + } + + break; + } + } + } + + if ( fFound ) + { + *pbDirection = bMinDirection; + return( TRUE ); + } + + return( FALSE ); +} + +BOOLEAN FindFenceDirection( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection ) +{ + INT32 cnt; + INT32 sNewGridNo, sOtherSideOfFence; + BOOLEAN fFound = FALSE; + UINT8 bMinNumTurns = 100; + INT8 bNumTurns; + INT8 bMinDirection = 0; + + // IF there is a fence in this gridno, return false! + if ( IsLegionFencePresentAtGridno( sGridNo ) ) + { + return( FALSE ); + } + + // LOOP THROUGH ALL 8 DIRECTIONS + for ( cnt = 0; cnt < 8; cnt+= 2 ) + { + // go out *2* tiles + sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + sOtherSideOfFence = NewGridNo( sNewGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + + if ( NewOKDestination( pSoldier, sOtherSideOfFence, TRUE, 0 ) ) + { + // ATE: Check if there is somebody waiting here..... + + + // Check if we have a fence here + if ( IsLegionFencePresentAtGridno( sNewGridNo ) ) + { + fFound = TRUE; + + // FInd how many turns we should go to get here + bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir ); + + if ( bNumTurns < bMinNumTurns ) + { + bMinNumTurns = bNumTurns; + bMinDirection = (INT8)cnt; + } + } + } + + } + + if ( fFound ) + { + *pbDirection = bMinDirection; + return( TRUE ); + } + + return( FALSE ); +} + +BOOLEAN FindHeigherLevelOkno( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection ) +{ + + INT32 cnt; + INT32 sNewGridNo; + BOOLEAN fFound = FALSE; + UINT8 bMinNumTurns = 100; + INT8 bNumTurns; + INT8 bMinDirection = 0; + + // LOOP THROUGH ALL 8 DIRECTIONS + for ( cnt = 0; cnt < 8; cnt+= 2 ) + { + sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + + // Make sure there is NOT a roof here... + // Check OK destination + if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) ) + { + if ( FindStructure( sNewGridNo, STRUCTURE_WALLNWINDOW ) == NULL ) + { + { + fFound = TRUE; + + // FInd how many turns we should go to get here + bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir ); + + if ( bNumTurns < bMinNumTurns ) + { + bMinNumTurns = bNumTurns; + bMinDirection = (INT8)cnt; + } + + } + } + } + } + + if ( fFound ) + { + *pbDirection = bMinDirection; + return( TRUE ); + } + + return( FALSE ); + +/* INT32 cnt; + INT32 sNewGridNo; + BOOLEAN fFound = FALSE; + UINT8 bMinNumTurns = 100; + INT8 bNumTurns; + INT8 bMinDirection = 0; + + //STRUCTURE * pStructure; + + // IF there is a roof over our heads, this is an ivalid.... + // return ( FALSE );l + if ( FindStructure( sGridNo, STRUCTURE_WALLNWINDOW ) != NULL ) + { + + return( FALSE ); + } + + for ( cnt = 0; cnt < 8; cnt+= 2 ) + { + sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + + if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) ) + { + // Check if this tile has a higher level + if ( IsOknoLevel( sNewGridNo ) ) + { + fFound = TRUE; + + // FInd how many turns we should go to get here + bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir ); + + if ( bNumTurns < bMinNumTurns ) + { + bMinNumTurns = bNumTurns; + bMinDirection = (INT8)cnt; + } + } + } + + } + + + + if ( fFound ) + { + *pbDirection = bMinDirection; + return( TRUE ); + } + + return( FALSE ); +*/ +} + +BOOLEAN FindHeigherLevelFence( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection ) +{ + INT32 cnt; + INT32 sNewGridNo; + BOOLEAN fFound = FALSE; + UINT8 bMinNumTurns = 100; + INT8 bNumTurns; + INT8 bMinDirection = 0; + + //STRUCTURE * pStructure; + + // IF there is a roof over our heads, this is an ivalid.... + // return ( FALSE );l + if ( FindStructure( sGridNo, STRUCTURE_FENCE ) != NULL ) + { + + return( FALSE ); + } + + for ( cnt = 0; cnt < 8; cnt+= 2 ) + { + sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + + if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) ) + { + // Check if this tile has a higher level + if ( IsLegionLevel( sNewGridNo ) ) + { + fFound = TRUE; + + // FInd how many turns we should go to get here + bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir ); + + if ( bNumTurns < bMinNumTurns ) + { + bMinNumTurns = bNumTurns; + bMinDirection = (INT8)cnt; + } + } + } + + } + + + + if ( fFound ) + { + *pbDirection = bMinDirection; + return( TRUE ); + } + + return( FALSE ); +} + +BOOLEAN FindLowerLevelFence( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bStartingDir, INT8 *pbDirection ) +{ + INT32 cnt; + INT32 sNewGridNo; + BOOLEAN fFound = FALSE; + UINT8 bMinNumTurns = 100; + INT8 bNumTurns; + INT8 bMinDirection = 0; + + // LOOP THROUGH ALL 8 DIRECTIONS + for ( cnt = 0; cnt < 8; cnt+= 2 ) + { + sNewGridNo = NewGridNo( sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) ); + + // Make sure there is NOT a roof here... + // Check OK destination + if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) ) + { + if ( FindStructure( sNewGridNo, STRUCTURE_FENCE ) == NULL ) + { + { + fFound = TRUE; + + // FInd how many turns we should go to get here + bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir ); + + if ( bNumTurns < bMinNumTurns ) + { + bMinNumTurns = bNumTurns; + bMinDirection = (INT8)cnt; + } + + } + } + } + } + + if ( fFound ) + { + *pbDirection = bMinDirection; + return( TRUE ); + } + + return( FALSE ); +} +//--------------------------------------------------------------------------------- + + GridNode::MapXY_t GridNode::MapXY; static GridNode::MapXY_t *pMapXY = GridNode::initGridNodes(); // A hack to initialize the MapXY grid @@ -632,7 +970,7 @@ INT32 GetRangeFromGridNoDiff( INT32 sGridNo1, INT32 sGridNo2 ) // Convert our grid-not into an XY ConvertGridNoToXY( sGridNo2, &sXPos2, &sYPos2 ); - uiDist = sqrt((double) ( sXPos2 - sXPos )*( sXPos2 - sXPos ) + ( sYPos2 - sYPos ) * ( sYPos2 - sYPos ) ); + uiDist = (INT32)(sqrt((double) ( sXPos2 - sXPos )*( sXPos2 - sXPos ) + ( sYPos2 - sYPos ) * ( sYPos2 - sYPos ) )); return( uiDist ); } diff --git a/TileEngine/Isometric Utils.h b/TileEngine/Isometric Utils.h index db1f4791..22187869 100644 --- a/TileEngine/Isometric Utils.h +++ b/TileEngine/Isometric Utils.h @@ -140,4 +140,12 @@ public: static MapXY_t *initGridNodes() { for (INT32 i=0; i //SB: make size of gpRevealedMap dependable from variable tactical map dimensions #define NUM_REVEALED_BYTES (WORLD_MAX/8) diff --git a/TileEngine/Shade Table Util.cpp b/TileEngine/Shade Table Util.cpp index 79081eaa..2956a5ef 100644 --- a/TileEngine/Shade Table Util.cpp +++ b/TileEngine/Shade Table Util.cpp @@ -12,7 +12,7 @@ #include "Fileman.h" #endif -#include "VFS/vfs.h" +#include #define SHADE_TABLE_DIR "ShadeTables" diff --git a/TileEngine/Tactical Placement GUI.cpp b/TileEngine/Tactical Placement GUI.cpp index 3dfa5aa4..59e73eb0 100644 --- a/TileEngine/Tactical Placement GUI.cpp +++ b/TileEngine/Tactical Placement GUI.cpp @@ -386,13 +386,10 @@ void InitTacticalPlacementGUI() gMercPlacement[ giPlacements ].pSoldier = MercPtrs[ i ]; gMercPlacement[ giPlacements ].ubStrategicInsertionCode = MercPtrs[ i ]->ubStrategicInsertionCode; gMercPlacement[ giPlacements ].fPlaced = FALSE; - #ifdef JA2BETAVERSION - CheckForValidMapEdge( &MercPtrs[ i ]->ubStrategicInsertionCode ); - #else - // WANNE: We need to have valid map edges in multiplayer! - if (is_networked) - CheckForValidMapEdge( &MercPtrs[ i ]->ubStrategicInsertionCode ); - #endif + + // WANNE: We always want to have edgepoints + CheckForValidMapEdge( &MercPtrs[ i ]->ubStrategicInsertionCode ); + switch( MercPtrs[ i ]->ubStrategicInsertionCode ) { case INSERTION_CODE_NORTH: @@ -743,7 +740,6 @@ void RenderTacticalPlacementGUI() } else { - // TODO.RW: Check for insertion if (is_networked) { gMercPlacement[ gbCursorMercID ].ubStrategicInsertionCode = GetValidInsertionDirectionForMP(gMercPlacement[ gbCursorMercID ].ubStrategicInsertionCode); @@ -991,8 +987,8 @@ void TacticalPlacementHandle() case ENTER: if( ButtonList[ iTPButtons[ DONE_BUTTON ] ]->uiFlags & BUTTON_ENABLED ) { - /*if(!is_client)KillTacticalPlacementGUI();*/ - //if(is_client)send_donegui(0); only by mouse //hayden + if(!is_client)KillTacticalPlacementGUI(); + if(is_client)send_donegui(0); } break; case 'c': @@ -1010,25 +1006,6 @@ void TacticalPlacementHandle() HandleShortCutExitState(); } break; - case 'l'://hayden - if( InputEvent.usKeyState & ALT_DOWN ) - { - /* - if (is_networked) - { - KillTacticalPlacementGUI(); - DoQuickLoad(); - } - */ - } - break; - case '7': - if (is_networked) - { - if(is_server) - manual_overide(); - } - break; } } } diff --git a/TileEngine/TileEngine_VS2005.vcproj b/TileEngine/TileEngine_VS2005.vcproj new file mode 100644 index 00000000..14329658 --- /dev/null +++ b/TileEngine/TileEngine_VS2005.vcproj @@ -0,0 +1,667 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TileEngine/TileEngine_VS2008.vcproj b/TileEngine/TileEngine_VS2008.vcproj index 1aeb6162..2056ef22 100644 --- a/TileEngine/TileEngine_VS2008.vcproj +++ b/TileEngine/TileEngine_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -499,6 +499,14 @@ RelativePath="worldman.h" > + + + + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA} + Win32Proj + TileEngine + TileEngine + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/TileEngine/TileEngine_VS2010.vcxproj.filters b/TileEngine/TileEngine_VS2010.vcxproj.filters new file mode 100644 index 00000000..838f0b83 --- /dev/null +++ b/TileEngine/TileEngine_VS2010.vcxproj.filters @@ -0,0 +1,252 @@ + + + + + {74f02e9a-2a7e-4654-8228-90ca0ba88a66} + + + {878cd328-bcac-4171-a25a-60953e8550e3} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/TileEngine/WorldDat.cpp b/TileEngine/WorldDat.cpp index a352e116..307ab1f6 100644 --- a/TileEngine/WorldDat.cpp +++ b/TileEngine/WorldDat.cpp @@ -12,10 +12,16 @@ #include "sys globals.h" #include "tile surface.h" #include "fileMan.h" + #include "Debug.h" #endif -#include "VFS/vfs.h" +#include +#include +#include "XML_TileSet.hpp" #include "XMLWriter.h" + +void ExportTilesets(vfs::Path const& filename); + // THIS FILE CONTAINS DEFINITIONS FOR TILESET FILES void SetTilesetThreeTerrainValues(); @@ -28,76 +34,156 @@ UINT8 gubNumSets = MAX_TILESETS; TILESET gTilesets[ MAX_TILESETS ]; - +extern bool g_bUseXML_Tilesets; void InitEngineTilesets( ) { - UINT32 cnt, cnt2, uiNumFiles; -// FILE *hfile; - HWFILE hfile; - CHAR8 zName[32]; - UINT32 uiNumBytesRead; - XMLWriter xmlw; - - //OPEN FILE -// hfile = fopen( "BINARYDATA\\JA2SET.DAT", "rb" ); - hfile = FileOpen( "BINARYDATA\\JA2SET.DAT", FILE_ACCESS_READ, FALSE ); - if ( !hfile ) + if(g_bUseXML_Tilesets) { - SET_ERROR( "Cannot open tileset data file" ); - return; + const vfs::Path tileset_filename(L"Ja2Set.dat.xml"); + if(!getVFS()->fileExists(tileset_filename)) + { + SGP_TRYCATCH_RETHROW( ExportTilesets(tileset_filename), L"Could not export tileset XML file"); + } + vfs::tReadableFile* file = getVFS()->getReadFile(tileset_filename); + SGP_THROW_IFFALSE(file, + _BS(L"File '") << tileset_filename << L"' does not exist and could not be created" << _BS::wget); + + CTilesetReader tileset_reader(gTilesets); + xml_auto::TGenericXMLParser pars(&tileset_reader,NULL); + + SGP_TRYCATCH_RETHROW( pars.parseFile(file), + _BS(L"Parser Error in file : ") << file->getPath() << _BS::wget ); + } + else + { + UINT32 cnt, cnt2, uiNumFiles; + //FILE *hfile; + HWFILE hfile; + CHAR8 zName[32]; + UINT32 uiNumBytesRead; + + //OPEN FILE + hfile = FileOpen( "BINARYDATA\\JA2SET.DAT", FILE_ACCESS_READ, FALSE ); + if ( !hfile ) + { + SET_ERROR( "Cannot open tileset data file" ); + return; + } + + // READ # TILESETS and compare + FileRead( hfile, &gubNumSets, sizeof( gubNumSets ), &uiNumBytesRead ); + // CHECK + if ( gubNumSets > MAX_TILESETS ) + { + // Report error + SET_ERROR( "Too many tilesets in the data file" ); + return; + } + + // READ #files + FileRead( hfile, &uiNumFiles, sizeof( uiNumFiles ), &uiNumBytesRead ); + + // COMPARE + if ( uiNumFiles != NUMBEROFTILETYPES ) + { + // Report error + SET_ERROR( "Number of tilesets slots in code does not match data file" ); + return; + } + + // Loop through each tileset, load name then files + for ( cnt = 0; cnt < gubNumSets; cnt++ ) + { + //Read name + FileRead( hfile, &zName, sizeof( zName ), &uiNumBytesRead ); + + // Read ambience value + FileRead( hfile, &(gTilesets[ cnt ].ubAmbientID), sizeof( UINT8 ), &uiNumBytesRead ); + + // Set into tileset + swprintf( gTilesets[ cnt ].zName, L"%S", zName ); + + // Loop for files + for ( cnt2 = 0; cnt2 < uiNumFiles; cnt2++ ) + { + // Read file name + FileRead( hfile, &zName, sizeof( zName ), &uiNumBytesRead ); + + // Set into database + strcpy( gTilesets[ cnt ].TileSurfaceFilenames[ cnt2 ], zName ); + } + } + + FileClose( hfile ); } + // SET CALLBACK FUNTIONS!!!!!!!!!!!!! + gTilesets[ TLS_CAVES_1 ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetTwoTerrainValues; + gTilesets[ TLS_AIRSTRIP ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_DEAD_AIRSTRIP ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_PALACE ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_BALIME ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_BALIME_MUSEUM ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_QUEENS_TROPICAL ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_MEDUNA_INNER_TOWN ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_QUEENS_SAM ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + gTilesets[ TLS_QUEENS_AIRPORT ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; + + gTilesets[ TLS_TROPICAL_1 ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetFourTerrainValues; + gTilesets[ TLS_DESERT_SAM ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetFourTerrainValues; +} + +#ifdef USE_VFS +void ExportTilesets(vfs::Path const& filename) +{ + UINT32 uiNumBytesRead = 0; + CHAR8 zName[32]; + + //OPEN FILE + HWFILE hfile = FileOpen( "BINARYDATA\\JA2SET.DAT", FILE_ACCESS_READ, FALSE ); + SGP_THROW_IFFALSE(hfile, L"Cannot open tileset data file" ); + + XMLWriter xmlw; xmlw.openNode("JA2SET"); // READ # TILESETS and compare -// fread( &gubNumSets, sizeof( gubNumSets ), 1, hfile ); - FileRead( hfile, &gubNumSets, sizeof( gubNumSets ), &uiNumBytesRead ); + UINT8 numSets = 0; + FileRead( hfile, &numSets, sizeof( numSets ), &uiNumBytesRead ); + // CHECK - if ( gubNumSets > MAX_TILESETS ) - { - // Report error - SET_ERROR( "Too many tilesets in the data file" ); - return; - } - xmlw.addAttributeToNextValue("numTilesets",(int)gubNumSets); + SGP_THROW_IFFALSE( numSets <= MAX_TILESETS, L"Too many tilesets in the data file" ); + xmlw.addAttributeToNextValue("numTilesets",(int)numSets); // READ #files -// fread( &uiNumFiles, sizeof( uiNumFiles ), 1, hfile ); - FileRead( hfile, &uiNumFiles, sizeof( uiNumFiles ), &uiNumBytesRead ); + UINT32 numFiles; + FileRead( hfile, &numFiles, sizeof( numFiles ), &uiNumBytesRead ); // COMPARE - if ( uiNumFiles != NUMBEROFTILETYPES ) - { - // Report error - SET_ERROR( "Number of tilesets slots in code does not match data file" ); - return; - } - xmlw.addAttributeToNextValue("numFiles",(int)uiNumFiles); + SGP_THROW_IFFALSE( numFiles == NUMBEROFTILETYPES, + L"Number of tilesets slots in code does not match data file" ); + + xmlw.addAttributeToNextValue("numFiles",(int)numFiles); xmlw.openNode("tilesets"); // Loop through each tileset, load name then files - for ( cnt = 0; cnt < gubNumSets; cnt++ ) + for ( UINT8 cnt = 0; cnt < numSets; cnt++ ) { xmlw.addAttributeToNextValue("index",(int)cnt); xmlw.openNode("Tileset"); + //Read name -// fread( &zName, sizeof( zName ), 1, hfile ); FileRead( hfile, &zName, sizeof( zName ), &uiNumBytesRead ); xmlw.addValue("Name",std::string(zName)); // Read ambience value -// fread( &(gTilesets[ cnt ].ubAmbientID), sizeof( UINT8), 1, hfile ); - FileRead( hfile, &(gTilesets[ cnt ].ubAmbientID), sizeof( UINT8 ), &uiNumBytesRead ); - xmlw.addValue("AmbientID",(int)gTilesets[ cnt ].ubAmbientID); - - // Set into tileset - swprintf( gTilesets[ cnt ].zName, L"%S", zName ); + UINT8 ambientID = 0; + FileRead( hfile, &ambientID, sizeof( UINT8 ), &uiNumBytesRead ); + xmlw.addValue("AmbientID",(int)ambientID); xmlw.openNode("Files"); // Loop for files - for ( cnt2 = 0; cnt2 < uiNumFiles; cnt2++ ) + for ( UINT32 cnt2 = 0; cnt2 < numFiles; cnt2++ ) { // Read file name -// fread( &zName, sizeof( zName ), 1, hfile ); FileRead( hfile, &zName, sizeof( zName ), &uiNumBytesRead ); if(!std::string(zName).empty()) { @@ -107,38 +193,26 @@ void InitEngineTilesets( ) // Set into database strcpy( gTilesets[ cnt ].TileSurfaceFilenames[ cnt2 ], zName ); - +//ddd{ 250 . +// if((cnt==0)&&(cnt2+1 == uiNumFiles)) +// { strcpy( gTilesets[ cnt ].TileSurfaceFilenames[ 151 ], "okop.sti" ); +// xmlw.AddAttributeToNextValue("index",(int)151); //for exp in xml +// xmlw.AddValue("file",std::string("okop.sti")); +// } +//ddd} + } xmlw.closeNode(); // Files xmlw.closeNode(); // tileset } xmlw.closeNode(); -// fclose( hfile ); FileClose( hfile ); xmlw.closeNode(); -#ifdef USE_VFS - xmlw.writeToFile("Ja2Set.dat.xml"); -#endif - // SET CALLBACK FUNTIONS!!!!!!!!!!!!! - gTilesets[ TLS_CAVES_1 ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetTwoTerrainValues; - gTilesets[ TLS_AIRSTRIP ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_DEAD_AIRSTRIP ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_PALACE ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_BALIME ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_BALIME_MUSEUM ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_QUEENS_TROPICAL ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_MEDUNA_INNER_TOWN ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_QUEENS_SAM ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - gTilesets[ TLS_QUEENS_AIRPORT ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetThreeTerrainValues; - - gTilesets[ TLS_TROPICAL_1 ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetFourTerrainValues; - gTilesets[ TLS_DESERT_SAM ].MovementCostFnc = (TILESET_CALLBACK)SetTilesetFourTerrainValues; + xmlw.writeToFile(filename); } - - - +#endif void SetTilesetOneTerrainValues( ) { diff --git a/TileEngine/XML_StructureData.hpp b/TileEngine/XML_StructureData.hpp new file mode 100644 index 00000000..fcca146e --- /dev/null +++ b/TileEngine/XML_StructureData.hpp @@ -0,0 +1,640 @@ +#ifndef _XML_STRUCTUREDATA_HPP_ +#define _XML_STRUCTUREDATA_HPP_ + +#include "XML_auto_parse.h" + +#include +#include + +class CStructureDataStates +{ +public: + enum States + { + STATE_NONE, + STATE_STRUCTURE_FILE, + // *********** + STATE_HEADER, + STATE_HEADER_id, + STATE_HEADER_num_structures, + STATE_HEADER_num_images, + STATE_HEADER_struct_stored, + STATE_HEADER_tile_locs_stores, + STATE_HEADER_data_size, + STATE_HEADER_flags, + STATE_HEADER_flags_any, + // *********** + STATE_AUXIMAGE_DATA, + STATE_AUX_image, + STATE_AUX_image_tile_index, + STATE_AUX_image_wall_orient, + STATE_AUX_image_num_tiles, + STATE_AUX_image_num_frames, + STATE_AUX_image_cur_frame, + STATE_AUX_image_FLAGS, + STATE_AUX_image_FLAGS_any, + // *********** + STATE_TILE_OFFSETS, + STATE_TOFF_offset, + // *********** + STATE_STRUCTURE_DATA, + // -- + STATE_SD_structure, + STATE_SD_structure_number, + STATE_SD_structure_armour, + STATE_SD_structure_hitpoits, + STATE_SD_structure_density, + STATE_SD_structure_wallrientation, + STATE_SD_structure_destr_partner, + STATE_SD_structure_desct_delta, + STATE_SD_structure_ZoffsetX, + STATE_SD_structure_ZoffsetY, + STATE_SD_structure_flags, + STATE_SD_structure_flags_any, + STATE_SD_structure_numtiles, + // -- + STATE_SD_TILES, + STATE_SD_TILES_tile, + STATE_SD_TILES_tile_OffsetX, + STATE_SD_TILES_tile_OffsetY, + STATE_SD_TILES_tile_OffsetBase, + STATE_SD_TILES_tile_vehitLoc, + STATE_SD_TILES_tile_flags, + STATE_SD_TILES_tile_flags_any, + STATE_SD_TILES_tile_profile, + STATE_SD_TILES_tile_profile_any, + }; +}; + +PARSER_CLASS_MACRO(CStructureDataReader, CStructureDataStates) +{ + typedef CStructureDataReader _myt; + + struct StructureData + { + DB_STRUCTURE structure; + std::vector tiles; + }; + std::vector _structures; +public: + PURE_TRANSITION(NOOP, _myt); + + /**********************************************************************/ + /* HEADER */ + /**********************************************************************/ + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Header,_myt,false); + TRANSITION_ENTER{ + memset(&(P_DATA->oHeader), 0, sizeof(STRUCTURE_FILE_HEADER)); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Header_NumStructures,_myt,true); + TRANSITION_LEAVE{ + P_DATA->oHeader.usNumberOfStructures = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Header_NumImages,_myt,true); + TRANSITION_LEAVE{ + P_DATA->oHeader.usNumberOfImages = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Header_StructStored,_myt,true); + TRANSITION_LEAVE{ + P_DATA->oHeader.usNumberOfStructuresStored = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Header_TileLocsStored,_myt,true); + TRANSITION_LEAVE{ + P_DATA->oHeader.usNumberOfImageTileLocsStored = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Header_DataSize,_myt,true); + TRANSITION_LEAVE{ + P_DATA->oHeader.usStructureDataSize = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + DEFINE_TRANSITION(TR_Header_Flags,_myt,true); + TRANSITION_LEAVE{ + if(std::string(tag_name) == "STRUCTURE_FILE_CONTAINS_STRUCTUREDATA") P_DATA->oHeader.fFlags |= STRUCTURE_FILE_CONTAINS_STRUCTUREDATA; + if(std::string(tag_name) == "STRUCTURE_FILE_CONTAINS_AUXIMAGEDATA") P_DATA->oHeader.fFlags |= STRUCTURE_FILE_CONTAINS_AUXIMAGEDATA; + } + FINISH_TRANSITION; + + /**********************************************************************/ + /* AUXIMAGE_DATA */ + /**********************************************************************/ + int count_aux_tiles; + DEFINE_TRANSITION(TR_AUXIMAGE_DATA, _myt, false); + TRANSITION_ENTER{ + long num = 0; + SGP_THROW_IFFALSE(atts.getLong("number_of",num), L"no attribute 'number_of'"); + if(num > 0) + { + SGP_THROW_IFFALSE(num == P_DATA->oHeader.usNumberOfImages , L"inconsistent data"); + P_DATA->pStructureFileRef->usNumberOfStructures = (UINT16)num; + int size = sizeof(AuxObjectData) * num; + P_DATA->pStructureFileRef->pAuxData = (AuxObjectData*)MemAlloc(size); + memset(P_DATA->pStructureFileRef->pAuxData, 0, size); + P_DATA->count_aux_tiles = 0; + } + } + FINISH_TRANSITION; + + /**********************************************************************/ + AuxObjectData* current_aux; + DEFINE_TRANSITION(TR_AUX_image, _myt, false); + TRANSITION_ENTER{ + long index = -1; + SGP_THROW_IFFALSE(atts.getLong("index", index), L"no attribute 'index'"); + SGP_THROW_IFFALSE(index >= 0 && index < P_DATA->oHeader.usNumberOfImages, L"index out of range"); + P_DATA->current_aux = &P_DATA->pStructureFileRef->pAuxData[index]; + } + TRANSITION_LEAVE{ + P_DATA->current_aux = NULL; + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_image_tile_index, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_aux, L"aux is null"); + P_DATA->current_aux->usTileLocIndex = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_image_wall_orient, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_aux, L"aux is null"); + P_DATA->current_aux->ubWallOrientation = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_image_num_tiles, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_aux, L"aux is null"); + int num_tiles = atoi(char_data.c_str()); + P_DATA->current_aux->ubNumberOfTiles = num_tiles; + P_DATA->count_aux_tiles += num_tiles; + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_image_num_frames, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_aux, L"aux is null"); + P_DATA->current_aux->ubNumberOfFrames = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_image_cur_frame, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_aux, L"aux is null"); + P_DATA->current_aux->ubCurrentFrame = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_image_FLAGS, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_aux, L"aux is null"); + if(std::string(tag_name) == "AUX_FULL_TILE") P_DATA->current_aux->fFlags |= AUX_FULL_TILE; + if(std::string(tag_name) == "AUX_ANIMATED_TILE") P_DATA->current_aux->fFlags |= AUX_ANIMATED_TILE; + if(std::string(tag_name) == "AUX_DYNAMIC_TILE") P_DATA->current_aux->fFlags |= AUX_DYNAMIC_TILE; + if(std::string(tag_name) == "AUX_INTERACTIVE_TILE") P_DATA->current_aux->fFlags |= AUX_INTERACTIVE_TILE; + if(std::string(tag_name) == "AUX_IGNORES_HEIGHT") P_DATA->current_aux->fFlags |= AUX_IGNORES_HEIGHT; + if(std::string(tag_name) == "AUX_USES_LAND_Z") P_DATA->current_aux->fFlags |= AUX_USES_LAND_Z; + } + FINISH_TRANSITION; + + /**********************************************************************/ + /* AUXTILE_DATA */ + /**********************************************************************/ + DEFINE_TRANSITION(TR_AUX_TILES, _myt, false); + TRANSITION_ENTER{ + long num = 0; + SGP_THROW_IFFALSE(atts.getLong("number_of",num), L"no attribute 'number_of'"); + if(num > 0) + { + SGP_THROW_IFFALSE(num == P_DATA->count_aux_tiles && num == P_DATA->oHeader.usNumberOfImageTileLocsStored, + L"counted number and given number of tiles aux images are not equal"); + + int size = num * sizeof(RelTileLoc); + P_DATA->pStructureFileRef->pTileLocData = (RelTileLoc*)MemAlloc(size); + memset(P_DATA->pStructureFileRef->pTileLocData, 0, size); + } + } + FINISH_TRANSITION; + + DEFINE_TRANSITION(TR_AUX_Tile_offset, _myt, false); + TRANSITION_ENTER{ + long index = 0, x = 0 , y = 0; + SGP_THROW_IFFALSE(atts.getLong("index", index), L"nu attribute 'index'"); + SGP_THROW_IFFALSE(index >= 0 && index < P_DATA->oHeader.usNumberOfImageTileLocsStored, L"index out of range"); + SGP_THROW_IFFALSE(atts.getLong("x", x), L"no attribute 'x'"); + SGP_THROW_IFFALSE(atts.getLong("y", y), L"no attribute 'y'"); + P_DATA->pStructureFileRef->pTileLocData[index].bTileOffsetX = (INT8)x; + P_DATA->pStructureFileRef->pTileLocData[index].bTileOffsetY = (INT8)y; + } + FINISH_TRANSITION; + + /**********************************************************************/ + /* STRUCTURE_DATA */ + /**********************************************************************/ + StructureData* current_structure; + int structure_index, structure_count; + DEFINE_TRANSITION(TR_Structure_data,_myt, false); + TRANSITION_ENTER{ + long num = 0, stored = 0; + SGP_THROW_IFFALSE(atts.getLong("number_of",num), L"structure data : no attribute 'number_of'"); + if(!atts.getLong("stored",stored)) + { + stored = num; + } + if(num > 0) + { + // header consistency check (to be removed later ?) + SGP_THROW_IFFALSE(num == P_DATA->oHeader.usNumberOfStructures, L"inconsistent data : number of structures"); + SGP_THROW_IFFALSE(stored == P_DATA->oHeader.usNumberOfStructuresStored, L"inconsistent data : number of stored structures"); + P_DATA->_structures.resize(stored); + for(int i=0; i < stored; ++i) + { + memset(&P_DATA->_structures[i].structure, 0, sizeof(DB_STRUCTURE)); + } + // save data + P_DATA->pStructureFileRef->usNumberOfStructures = (UINT16)num; + P_DATA->pStructureFileRef->usNumberOfStructuresStored = (UINT16)stored; + } + P_DATA->structure_count = 0; + P_DATA->structure_index = -1; + } + TRANSITION_LEAVE{ + // copy gathered data into game object + if(!P_DATA->_structures.empty()) + { + SGP_THROW_IFFALSE(P_DATA->pStructureFileRef->usNumberOfStructuresStored == P_DATA->structure_count, L"wrong number of structures"); + + int size = 0; + for(::size_t i = 0; i < P_DATA->_structures.size(); ++i) + { + size += sizeof(DB_STRUCTURE); + for(::size_t j = 0; j < P_DATA->_structures[i].tiles.size(); ++j) + { + size += sizeof(DB_STRUCTURE_TILE); + } + } + + SGP_THROW_IFFALSE(size == P_DATA->oHeader.usStructureDataSize, + _BS(L"data size is supposed to be '") << P_DATA->oHeader.usStructureDataSize << L"' but is '" << size << L"'" << _BS::wget); + + P_DATA->structure_data_size = size; + + P_DATA->pStructureFileRef->pubStructureData = (UINT8*)MemAlloc(size); + UINT8 *tmp = P_DATA->pStructureFileRef->pubStructureData; + for(::size_t i = 0; i < P_DATA->_structures.size(); ++i) + { + memcpy(tmp, &P_DATA->_structures[i].structure, sizeof(DB_STRUCTURE)); + tmp += sizeof(DB_STRUCTURE); + for(::size_t j = 0; j < P_DATA->_structures[i].tiles.size(); ++j) + { + memcpy(tmp, &P_DATA->_structures[i].tiles[j], sizeof(DB_STRUCTURE_TILE)); + tmp += sizeof(DB_STRUCTURE_TILE); + } + } + } + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure, _myt, false); + TRANSITION_ENTER{ + long index; + SGP_THROW_IFFALSE( atts.getLong("index", index), L"no attribute 'index'" ); + SGP_THROW_IFFALSE( (index >= 0) && (index < P_DATA->pStructureFileRef->usNumberOfStructures), L"structure index out of range"); + SGP_THROW_IFFALSE( (P_DATA->structure_count >= 0) && (P_DATA->structure_count < P_DATA->pStructureFileRef->usNumberOfStructuresStored), L"structure count larger than announced"); + P_DATA->current_structure = &P_DATA->_structures[P_DATA->structure_count]; + P_DATA->current_structure->structure.usStructureNumber = (UINT16)index; + P_DATA->structure_index = index; + } + TRANSITION_LEAVE{ + // finished this structure, increase index for next run + P_DATA->structure_index = -1; + P_DATA->structure_count += 1; + P_DATA->current_structure = NULL; + } + FINISH_TRANSITION; + + /**********************************************************************/ + //DEFINE_TRANSITION(TR_Structure_number, _myt, true); + //TRANSITION_LEAVE{ + // SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + // P_DATA->current_structure->structure.usStructureNumber = atoi(char_data.c_str()); + // SGP_THROW_IFFALSE( P_DATA->current_structure->structure.usStructureNumber == P_DATA->structure_index, L"inconsistent data"); + //} + //FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_armour, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.ubArmour = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_hitpoints, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.ubHitPoints = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_density, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.ubDensity = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_wall_orient, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.ubWallOrientation = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_destr_partner, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.bDestructionPartner = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_partner_delta, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.bPartnerDelta = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_offX, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.bZTileOffsetX = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_offY, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + P_DATA->current_structure->structure.bZTileOffsetY = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_num_tiles, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + int num_tiles = atoi(char_data.c_str()); + SGP_THROW_IFFALSE(num_tiles >= 0, L"invalid number"); + P_DATA->current_structure->structure.ubNumberOfTiles = num_tiles; + P_DATA->current_structure->tiles.resize(num_tiles); + for(int i = 0 ;i < num_tiles; ++i) + { + memset(&P_DATA->current_structure->tiles[i], 0, sizeof(DB_STRUCTURE_TILE)); + } + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_Structure_FLAGS, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->current_structure, L"null structure" ); + if(std::string(tag_name) == "STRUCTURE_BASE_TILE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_BASE_TILE; + if(std::string(tag_name) == "STRUCTURE_OPEN") P_DATA->current_structure->structure.fFlags |= STRUCTURE_OPEN; + if(std::string(tag_name) == "STRUCTURE_OPENABLE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_OPENABLE; + if(std::string(tag_name) == "STRUCTURE_CLOSEABLE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_CLOSEABLE; + if(std::string(tag_name) == "STRUCTURE_SEARCHABLE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_SEARCHABLE; + if(std::string(tag_name) == "STRUCTURE_HIDDEN") P_DATA->current_structure->structure.fFlags |= STRUCTURE_HIDDEN; + if(std::string(tag_name) == "STRUCTURE_MOBILE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_MOBILE; + if(std::string(tag_name) == "STRUCTURE_PASSABLE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_PASSABLE; + if(std::string(tag_name) == "STRUCTURE_EXPLOSIVE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_EXPLOSIVE; + if(std::string(tag_name) == "STRUCTURE_TRANSPARENT") P_DATA->current_structure->structure.fFlags |= STRUCTURE_TRANSPARENT; + if(std::string(tag_name) == "STRUCTURE_GENERIC") P_DATA->current_structure->structure.fFlags |= STRUCTURE_GENERIC; + if(std::string(tag_name) == "STRUCTURE_TREE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_TREE; + if(std::string(tag_name) == "STRUCTURE_FENCE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_FENCE; + if(std::string(tag_name) == "STRUCTURE_WIREFENCE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_WIREFENCE; + if(std::string(tag_name) == "STRUCTURE_HASITEMONTOP") P_DATA->current_structure->structure.fFlags |= STRUCTURE_HASITEMONTOP; + if(std::string(tag_name) == "STRUCTURE_SPECIAL") P_DATA->current_structure->structure.fFlags |= STRUCTURE_SPECIAL; + if(std::string(tag_name) == "STRUCTURE_LIGHTSOURCE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_LIGHTSOURCE; + if(std::string(tag_name) == "STRUCTURE_VEHICLE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_VEHICLE; + if(std::string(tag_name) == "STRUCTURE_WALL") P_DATA->current_structure->structure.fFlags |= STRUCTURE_WALL; + if(std::string(tag_name) == "STRUCTURE_WALLNWINDOW") P_DATA->current_structure->structure.fFlags |= STRUCTURE_WALLNWINDOW; + if(std::string(tag_name) == "STRUCTURE_SLIDINGDOOR") P_DATA->current_structure->structure.fFlags |= STRUCTURE_SLIDINGDOOR; + if(std::string(tag_name) == "STRUCTURE_DOOR") P_DATA->current_structure->structure.fFlags |= STRUCTURE_DOOR; + if(std::string(tag_name) == "STRUCTURE_MULTI") P_DATA->current_structure->structure.fFlags |= STRUCTURE_MULTI; + if(std::string(tag_name) == "STRUCTURE_CAVEWALL") P_DATA->current_structure->structure.fFlags |= STRUCTURE_CAVEWALL; + if(std::string(tag_name) == "STRUCTURE_DDOOR_LEFT") P_DATA->current_structure->structure.fFlags |= STRUCTURE_DDOOR_LEFT; + if(std::string(tag_name) == "STRUCTURE_DDOOR_RIGHT") P_DATA->current_structure->structure.fFlags |= STRUCTURE_DDOOR_RIGHT; + if(std::string(tag_name) == "STRUCTURE_NORMAL_ROOF") P_DATA->current_structure->structure.fFlags |= STRUCTURE_NORMAL_ROOF; + if(std::string(tag_name) == "STRUCTURE_SLANTED_ROOF") P_DATA->current_structure->structure.fFlags |= STRUCTURE_SLANTED_ROOF; + if(std::string(tag_name) == "STRUCTURE_TALL_ROOF") P_DATA->current_structure->structure.fFlags |= STRUCTURE_TALL_ROOF; + if(std::string(tag_name) == "STRUCTURE_SWITCH") P_DATA->current_structure->structure.fFlags |= STRUCTURE_SWITCH; + if(std::string(tag_name) == "STRUCTURE_ON_LEFT_WALL") P_DATA->current_structure->structure.fFlags |= STRUCTURE_ON_LEFT_WALL; + if(std::string(tag_name) == "STRUCTURE_ON_RIGHT_WALL") P_DATA->current_structure->structure.fFlags |= STRUCTURE_ON_RIGHT_WALL; + if(std::string(tag_name) == "STRUCTURE_CORPSE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_CORPSE; + if(std::string(tag_name) == "STRUCTURE_PERSON") P_DATA->current_structure->structure.fFlags |= STRUCTURE_PERSON; + if(std::string(tag_name) == "STRUCTURE_ANYFENCE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_ANYFENCE; + if(std::string(tag_name) == "STRUCTURE_ANYDOOR") P_DATA->current_structure->structure.fFlags |= STRUCTURE_ANYDOOR; + if(std::string(tag_name) == "STRUCTURE_OBSTACLE") P_DATA->current_structure->structure.fFlags |= STRUCTURE_OBSTACLE; + if(std::string(tag_name) == "STRUCTURE_WALLSTUFF") P_DATA->current_structure->structure.fFlags |= STRUCTURE_WALLSTUFF; + if(std::string(tag_name) == "STRUCTURE_BLOCKSMOVES") P_DATA->current_structure->structure.fFlags |= STRUCTURE_BLOCKSMOVES; + if(std::string(tag_name) == "STRUCTURE_TYPE_DEFINED") P_DATA->current_structure->structure.fFlags |= STRUCTURE_TYPE_DEFINED; + if(std::string(tag_name) == "STRUCTURE_ROOF") P_DATA->current_structure->structure.fFlags |= STRUCTURE_ROOF; + } + FINISH_TRANSITION; + + /**********************************************************************/ + /* STRUCTURE_TILES */ + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_TILES, _myt, false); + TRANSITION_ENTER{ + long num = 0; + if(atts.getLong("number_of",num)) + { + SGP_THROW_IFFALSE(num == P_DATA->current_structure->structure.ubNumberOfTiles, L"inconsistent data"); + } + } + FINISH_TRANSITION; + + /**********************************************************************/ + DB_STRUCTURE_TILE* current_str_tile; + DEFINE_TRANSITION(TR_SD_Tile, _myt, false); + TRANSITION_ENTER{ + long index = 0; + SGP_THROW_IFFALSE( atts.getLong("index",index), L"no attribute 'index'" ); + SGP_THROW_IFFALSE( index >= 0 && index < (long)P_DATA->current_structure->tiles.size(), L"structure index out of range"); + P_DATA->current_str_tile = &P_DATA->current_structure->tiles[index]; + } + TRANSITION_LEAVE{ + P_DATA->current_str_tile = NULL; + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_Tile_offX, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_str_tile, L"null structure tile"); + P_DATA->current_str_tile->bXPosRelToBase = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_Tile_offY, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_str_tile, L"null structure tile"); + P_DATA->current_str_tile->bYPosRelToBase = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_Tile_offBase, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_str_tile, L"null structure tile"); + P_DATA->current_str_tile->sPosRelToBase = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_Tile_VehHitLoc, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_str_tile, L"null structure tile"); + P_DATA->current_str_tile->ubVehicleHitLocation = atoi(char_data.c_str()); + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_Tile_FLAGS, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_str_tile, L"null structure tile"); + if(std::string(tag_name) == "TILE_ON_ROOF") P_DATA->current_str_tile->fFlags |= TILE_ON_ROOF; + if(std::string(tag_name) == "TILE_PASSABLE") P_DATA->current_str_tile->fFlags |= TILE_PASSABLE; + } + FINISH_TRANSITION; + + /**********************************************************************/ + DEFINE_TRANSITION(TR_SD_Tile_profile, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE(P_DATA->current_str_tile, L"null structure tile"); + int y = -1; + if (std::string(tag_name) == "y0") y = 0; + else if(std::string(tag_name) == "y1") y = 1; + else if(std::string(tag_name) == "y2") y = 2; + else if(std::string(tag_name) == "y3") y = 3; + else if(std::string(tag_name) == "y4") y = 4; + + if(y != -1) + { + int x = 0; + vfs::String token; + vfs::CTokenizer tok(char_data); + while(tok.next(token, L',')) + { + if(x >= 0 && x < 5) + { + int z; + SGP_THROW_IFFALSE( vfs::convertTo(token,z), L"" ); + if(z >= 0 && z < 16) + { + P_DATA->current_str_tile->Shape[y][x] = z; + } + } + x++; + } + } + } + FINISH_TRANSITION; + + /**********************************************************************/ + UINT32 structure_data_size; + + STRUCTURE_FILE_REF* pStructureFileRef; + STRUCTURE_FILE_HEADER oHeader; + CStructureDataReader(STRUCTURE_FILE_REF* sfr) + : pStructureFileRef(sfr), current_structure(NULL), current_str_tile(NULL), current_aux(NULL) + { + SGP_THROW_IFFALSE(sfr, L""); + + TR_PASS (STATE_NONE, "STRUCTURE_FILE", STATE_STRUCTURE_FILE); + // HEADER + TR_HANDLE( STATE_STRUCTURE_FILE, "HEADER", STATE_HEADER, TR_Header ); + TR_HANDLE( STATE_HEADER, "usNumberOfStructures", STATE_HEADER_num_structures, TR_Header_NumStructures ); + TR_HANDLE( STATE_HEADER, "usNumberOfImages", STATE_HEADER_num_images, TR_Header_NumImages ); + TR_HANDLE( STATE_HEADER, "usNumberOfStructuresStored", STATE_HEADER_struct_stored, TR_Header_StructStored ); + TR_HANDLE( STATE_HEADER, "usNumberOfImageTileLocsStored", STATE_HEADER_tile_locs_stores, TR_Header_TileLocsStored ); + TR_HANDLE( STATE_HEADER, "usStructureDataSize", STATE_HEADER_data_size, TR_Header_DataSize ); + TR_PASS ( STATE_HEADER, "flags", STATE_HEADER_flags ); + TR_HANDLE( STATE_HEADER_flags, "", STATE_HEADER_flags_any, TR_Header_Flags ); + // AUX IMAGE + TR_HANDLE( STATE_STRUCTURE_FILE, "AUXIMAGE_DATA", STATE_AUXIMAGE_DATA, TR_AUXIMAGE_DATA); + TR_HANDLE( STATE_AUXIMAGE_DATA, "auximage", STATE_AUX_image, TR_AUX_image); + TR_HANDLE( STATE_AUX_image, "tile_loc_index", STATE_AUX_image_tile_index, TR_AUX_image_tile_index); + TR_HANDLE( STATE_AUX_image, "wall_orientation", STATE_AUX_image_wall_orient, TR_AUX_image_wall_orient); + TR_HANDLE( STATE_AUX_image, "number_of_tiles", STATE_AUX_image_num_tiles, TR_AUX_image_num_tiles); + TR_HANDLE( STATE_AUX_image, "number_of_frames", STATE_AUX_image_num_frames, TR_AUX_image_num_frames); + TR_HANDLE( STATE_AUX_image, "current_frame", STATE_AUX_image_cur_frame, TR_AUX_image_cur_frame); + TR_PASS ( STATE_AUX_image, "flags", STATE_AUX_image_FLAGS); + TR_HANDLE( STATE_AUX_image_FLAGS, "", STATE_AUX_image_FLAGS_any, TR_AUX_image_FLAGS); + // AUX TILES + TR_HANDLE( STATE_STRUCTURE_FILE, "TILE_OFFSETS", STATE_TILE_OFFSETS, TR_AUX_TILES); + TR_HANDLE( STATE_TILE_OFFSETS, "offset", STATE_TOFF_offset, TR_AUX_Tile_offset); + // STRUCTURE + TR_HANDLE( STATE_STRUCTURE_FILE, "STRUCTURE_DATA", STATE_STRUCTURE_DATA, TR_Structure_data ); + TR_HANDLE( STATE_STRUCTURE_DATA, "STRUCTURE", STATE_SD_structure, TR_Structure ); +// TR_HANDLE( STATE_SD_structure, "usStructureNumber", STATE_SD_structure_number, TR_Structure_number ); + TR_HANDLE( STATE_SD_structure, "ubArmour", STATE_SD_structure_armour, TR_Structure_armour ); + TR_HANDLE( STATE_SD_structure, "ubHitPoints", STATE_SD_structure_hitpoits, TR_Structure_hitpoints ); + TR_HANDLE( STATE_SD_structure, "ubDensity", STATE_SD_structure_density, TR_Structure_density ); + TR_HANDLE( STATE_SD_structure, "ubWallOrientation", STATE_SD_structure_wallrientation, TR_Structure_wall_orient ); + TR_HANDLE( STATE_SD_structure, "bDestructionPartner", STATE_SD_structure_destr_partner, TR_Structure_destr_partner ); + TR_HANDLE( STATE_SD_structure, "bPartnerDelta", STATE_SD_structure_desct_delta, TR_Structure_partner_delta ); + TR_HANDLE( STATE_SD_structure, "bZTileOffsetX", STATE_SD_structure_ZoffsetX, TR_Structure_offX ); + TR_HANDLE( STATE_SD_structure, "bZTileOffsetY", STATE_SD_structure_ZoffsetY, TR_Structure_offY ); + TR_PASS ( STATE_SD_structure, "flags", STATE_SD_structure_flags ); + TR_HANDLE( STATE_SD_structure_flags, "", STATE_SD_structure_flags_any, TR_Structure_FLAGS ); + TR_HANDLE( STATE_SD_structure, "ubNumberOfTiles", STATE_SD_structure_numtiles, TR_Structure_num_tiles ); + // STRUCTURE TILES + TR_HANDLE( STATE_SD_structure, "TILES", STATE_SD_TILES, TR_SD_TILES); + TR_HANDLE( STATE_SD_TILES, "STRUCTURE_TILE", STATE_SD_TILES_tile, TR_SD_Tile); + TR_HANDLE( STATE_SD_TILES_tile, "bXPosRelToBase", STATE_SD_TILES_tile_OffsetX, TR_SD_Tile_offX); + TR_HANDLE( STATE_SD_TILES_tile, "bYPosRelToBase", STATE_SD_TILES_tile_OffsetY, TR_SD_Tile_offY); + TR_HANDLE( STATE_SD_TILES_tile, "sPosRelToBase", STATE_SD_TILES_tile_OffsetBase, TR_SD_Tile_offBase); + TR_HANDLE( STATE_SD_TILES_tile, "ubVehicleHitLocation", STATE_SD_TILES_tile_vehitLoc, TR_SD_Tile_VehHitLoc); + TR_PASS ( STATE_SD_TILES_tile, "flags", STATE_SD_TILES_tile_flags ); + TR_HANDLE( STATE_SD_TILES_tile_flags, "", STATE_SD_TILES_tile_flags_any, TR_SD_Tile_FLAGS ); + TR_PASS ( STATE_SD_TILES_tile, "profile", STATE_SD_TILES_tile_profile ); + TR_HANDLE( STATE_SD_TILES_tile_profile, "", STATE_SD_TILES_tile_profile_any, TR_SD_Tile_profile ); + } +}; + +#endif // _XML_STRUCTUREDATA_HPP_ diff --git a/TileEngine/XML_TileSet.hpp b/TileEngine/XML_TileSet.hpp new file mode 100644 index 00000000..0858b629 --- /dev/null +++ b/TileEngine/XML_TileSet.hpp @@ -0,0 +1,125 @@ +#ifndef _XML_TILESET_HPP_ +#define _XML_TILESET_HPP_ + +#include "XML_auto_parse.h" +#include "WorldDat.h" +#include + +class CTilesetStates +{ +public: + enum States + { + STATE_NONE, + STATE_JA2SET, + STATE_tilesets, + STATE_ts_tileset, + STATE_ts_tileset_name, + STATE_ts_tileset_ambientid, + STATE_ts_tileset_files, + STATE_ts_tileset_files_file, + }; +}; + +PARSER_CLASS_MACRO(CTilesetReader, CTilesetStates) +{ + typedef CTilesetReader _myt; +public: + /** + * NOOP + */ + PURE_TRANSITION(NOOP, _myt); + + + /** + * Tilesets + */ + DEFINE_TRANSITION_WDATA(TilesetsAttrib, _myt, false, struct TilesetInfo{int numTilesets; int numFiles;}); + TRANSITION_ENTER{ + long T_num, F_num; + if(atts.getLong("numTilesets", T_num)) T_DATA.numTilesets = (int)T_num; + else SGP_THROW(L"Attribute 'numTileset' not found"); + + if(atts.getLong("numFiles",F_num)) T_DATA.numFiles = (int)F_num ; + else SGP_THROW(L"Attribute 'numFiles' not found"); + } + FINISH_TRANSITION; + + /** + * Tileset + */ + TILESET* _current_tileset; + DEFINE_TRANSITION(Tileset, _myt, false); + TRANSITION_ENTER{ + long lindex; + if(atts.getLong("index", lindex)){ + SGP_THROW_IFFALSE(lindex < MAX_TILESETS, _BS(L"tileset index is too large : ") << lindex << _BS::wget ); + P_DATA->_current_tileset = &(P_DATA->_tilesets[ lindex ]); + } + else SGP_THROW(L"Attribute 'index' not found"); + } + TRANSITION_LEAVE{ + P_DATA->_current_tileset = NULL; + } + FINISH_TRANSITION; + + /** + * Tileset Name + */ + DEFINE_TRANSITION(TilesetName, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->_current_tileset != NULL, L"No tileset selected" ); + std::string tmpString = vfs::trimString(char_data, 0, char_data.length()); + wcsncpy( P_DATA->_current_tileset->zName, vfs::String( tmpString ).c_str(), 32 ); + } + FINISH_TRANSITION; + + /** + * Tileset ID + */ + DEFINE_TRANSITION(TilesetAmbientID, _myt, true); + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->_current_tileset != NULL, L"No tileset selected" ); + int tmp; + SGP_THROW_IFFALSE( vfs::convertTo(char_data, tmp), + _BS(L"Could not convert to int : ") << char_data << _BS::wget ); + P_DATA->_current_tileset->ubAmbientID = tmp; + + } + FINISH_TRANSITION; + + /** + * Tileset File + */ + DEFINE_TRANSITION_WDATA(TilesetFile, _myt, true, struct Index{int index;}); + TRANSITION_ENTER{ + long lindex; + if(atts.getLong("index", lindex)){ + SGP_THROW_IFFALSE(lindex < NUMBEROFTILETYPES, + _BS(L"tileset file index is too large : ") << lindex << _BS::wget ); + T_DATA.index = lindex; + } + else SGP_THROW(L"Attribute 'index' not found"); + } + TRANSITION_LEAVE{ + SGP_THROW_IFFALSE( P_DATA->_current_tileset != NULL, L"No tileset selected" ); + std::string tmpString = vfs::trimString(char_data, 0, char_data.length()); + strncpy( P_DATA->_current_tileset->TileSurfaceFilenames[T_DATA.index], tmpString.c_str(), 32); + } + FINISH_TRANSITION; + + + TILESET* _tilesets; + CTilesetReader(TILESET tilesets[ MAX_TILESETS ]) : _tilesets(tilesets), _current_tileset(NULL) + { + TR_PASS ( STATE_NONE, "JA2SET", STATE_JA2SET); + TR_HANDLE( STATE_JA2SET, "tilesets", STATE_tilesets, TilesetsAttrib ); + TR_HANDLE( STATE_tilesets, "Tileset", STATE_ts_tileset, Tileset ); + TR_HANDLE( STATE_ts_tileset, "Name", STATE_ts_tileset_name, TilesetName ); + TR_HANDLE( STATE_ts_tileset, "AmbientID", STATE_ts_tileset_ambientid, TilesetAmbientID ); + TR_PASS ( STATE_ts_tileset, "Files", STATE_ts_tileset_files ); + TR_HANDLE( STATE_ts_tileset_files, "file", STATE_ts_tileset_files_file, TilesetFile ); + } +}; + +#endif // _XML_TILESET_HPP_ diff --git a/TileEngine/environment.cpp b/TileEngine/environment.cpp index d2041f34..f32f0706 100644 --- a/TileEngine/environment.cpp +++ b/TileEngine/environment.cpp @@ -960,12 +960,13 @@ void UpdateTemperature( UINT8 ubTemperatureCode ) INT8 SectorTemperature( UINT32 uiTime, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) { + // SANDRO - updated this code if (bSectorZ > 0) { // cool underground return( 0 ); } - else if ( IsSectorDesert( sSectorX, sSectorY ) ) // is desert + else if ( IsSectorDesert( sSectorX, sSectorY ) && !( guiEnvWeather & ( WEATHER_FORECAST_SHOWERS | WEATHER_FORECAST_THUNDERSHOWERS ) ) ) // is desert { return( gubDesertTemperature ); } diff --git a/TileEngine/overhead map.cpp b/TileEngine/overhead map.cpp index 39cd8bdc..98f1ca65 100644 --- a/TileEngine/overhead map.cpp +++ b/TileEngine/overhead map.cpp @@ -1359,8 +1359,6 @@ void RenderOverheadOverlays() if(pSoldier->bSide==0) { int personIndex = pSoldier->bTeam + 4; - // TODO.RW: Get the correct person index (depending on the pSoldier->bTeam) - //Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, 3 ); Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, personIndex ); } } @@ -1405,9 +1403,6 @@ void RenderOverheadOverlays() if(pSoldier->bSide==0) { int personIndex = pSoldier->bTeam + 4; - // TODO.RW: Get the correct person index (depending on the pSoldier->bTeam) - - //Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, 3 ); Blt8BPPDataTo16BPPBufferTransparent((UINT16*)pDestBuf, uiDestPitchBYTES, hVObject, sX, sY, personIndex ); } } diff --git a/TileEngine/physics.cpp b/TileEngine/physics.cpp index e3357152..a032d36f 100644 --- a/TileEngine/physics.cpp +++ b/TileEngine/physics.cpp @@ -369,9 +369,9 @@ void RemoveAllPhysicsObjects( ) void SimulateObject( REAL_OBJECT *pObject, real deltaT ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SimulateObject"); + if ( !PhysicsUpdateLife( pObject, (float)deltaT ) ) { - // DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"SimulateObject: don't update life, returning"); return; } @@ -486,10 +486,15 @@ BOOLEAN PhysicsUpdateLife( REAL_OBJECT *pObject, real DeltaTime ) } - // End life if we are out of bounds.... - if ( !GridNoOnVisibleWorldTile( pObject->sGridNo ) ) + // WANNE.BMP: Only do this check on normal maps. + // When we do this check on Big Maps it always returns false and we got wrong physics when trowing items! + if (WORLD_COLS <= 160 && WORLD_ROWS <= 160) { - pObject->fAlive = FALSE; + // End life if we are out of bounds.... + if ( !GridNoOnVisibleWorldTile( pObject->sGridNo ) ) + { + pObject->fAlive = FALSE; + } } if ( !pObject->fAlive ) @@ -1496,9 +1501,7 @@ vector_3 FindBestForceForTrajectory( INT32 sSrcGridNo, INT32 sGridNo,INT16 sStar dRange = (float)GetRangeInCellCoordsFromGridNoDiff( sGridNo, sSrcGridNo ); //calculate force needed - { - dForce = (float)( 12.0 * ( sqrt( ( GRAVITY * dRange ) / sin( 2.0 * dzDegrees ) ) ) ); - } + dForce = (float)( 12.0 * ( sqrt( ( GRAVITY * dRange ) / sin( 2.0 * dzDegrees ) ) ) ); do { @@ -1537,12 +1540,6 @@ vector_3 FindBestForceForTrajectory( INT32 sSrcGridNo, INT32 sGridNo,INT16 sStar } while( TRUE ); - // OK, we have our force, calculate change to get through without collide - //if ( ChanceToGetThroughObjectTrajectory( sEndZ, pItem, &vPosition, &vForce, NULL ) == 0 ) - { - //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Chance to get through throw is 0." ); - } - if ( pdMagForce ) { (*pdMagForce) = dForce; @@ -2152,6 +2149,9 @@ FLOAT CalculateForceFromRange( INT16 sRange, FLOAT dDegrees ) FindBestForceForTrajectory( sSrcGridNo, sDestGridNo, GET_SOLDIER_THROW_HEIGHT( 0 ), 0, dDegrees, &gTempObject, &sFinalGridNo, &dMagForce ); + // WANNE: Problem is the FORCE!! + // dMagForce = 460.00; + return( dMagForce ); } @@ -2204,6 +2204,12 @@ void CalculateLaunchItemParamsForThrow( SOLDIERTYPE *pSoldier, INT32 sGridNo, UI { // then we hit! bMissBy = 0; + + // SANDRO - new merc records + if( pSoldier->bTeam == 0 && pSoldier->ubProfile != NO_PROFILE ) + { + gMercProfiles[ pSoldier->ubProfile ].records.usShotsHit++; + } } //if ( 0 ) diff --git a/TileEngine/structure.cpp b/TileEngine/structure.cpp index 319e0ae0..809bcc5d 100644 --- a/TileEngine/structure.cpp +++ b/TileEngine/structure.cpp @@ -23,7 +23,7 @@ #include "Smell.h" #include "SaveLoadMap.h" #include "strategicmap.h" - + #include "sgp_logger.h" #include "Sys Globals.h" //for access to gfEditMode flag @@ -432,25 +432,122 @@ BOOLEAN CreateFileStructureArrays( STRUCTURE_FILE_REF * pFileRef, UINT32 uiDataS return( TRUE ); } +#include +#include +#include "XML_StructureData.hpp" + +void checkStructureValidity(STRUCTURE_FILE_REF *str1, STRUCTURE_FILE_REF* str2, UINT32 size1, UINT32 size2) +{ + if(str1 == str2 && str1 == NULL) + { + return; + } + + if(str1->pubStructureData && str2->pubStructureData) + { + SGP_THROW_IFFALSE( size1 == size2, L""); + //SGP_THROW_IFFALSE( 0 == memcmp(str1->pubStructureData, str2->pubStructureData, size1), L"" ); + UINT8* ptr1 = str1->pubStructureData; + UINT8* ptr2 = str2->pubStructureData; + unsigned int count = 0; + for(; count < size1 && (*ptr1++ == *ptr2++); count++) {} + SGP_THROW_IFFALSE(count == size1, L"bad structure data"); + } + else if(str1->pubStructureData || str2->pubStructureData) + { + SGP_THROW(L"bad structure data"); + } + + int count_tiles_1 = 0, count_tiles_2 = 0; + if(str1->pAuxData && str2->pAuxData) + { + SGP_THROW_IFFALSE(str1->usNumberOfStructures == str2->usNumberOfStructures, L""); + SGP_THROW_IFFALSE(str1->usNumberOfStructuresStored == str2->usNumberOfStructuresStored, L""); + //SGP_THROW_IFFALSE( 0 == memcmp(str1->pAuxData, str2->pAuxData, sizeof(AuxObjectData)*str2->usNumberOfStructures), L"" ); + for(int i = 0; i < str2->usNumberOfStructures; ++i) + { + SGP_THROW_IFFALSE( 0 == memcmp(&str1->pAuxData[i], &str2->pAuxData[i], sizeof(AuxObjectData)), _BS(L"bad aux_image : ") << i << _BS::wget ); + } + + for(int i = 0; i < str1->usNumberOfStructures; ++i){ + count_tiles_1 += str1->pAuxData[i].ubNumberOfTiles; + } + for(int j = 0; j < str2->usNumberOfStructures; ++j){ + count_tiles_2 += str2->pAuxData[j].ubNumberOfTiles; + } + SGP_THROW_IFFALSE(count_tiles_1 == count_tiles_2, L""); + } + else if(str1->pAuxData || str2->pAuxData) + { + SGP_THROW(L"bad aux image data"); + } + + if(str1->pTileLocData && str2->pTileLocData) + { + SGP_THROW_IFFALSE( 0 == memcmp(str1->pTileLocData, str2->pTileLocData, count_tiles_1*sizeof(RelTileLoc)), L"" ); + } + else if(str1->pTileLocData || str2->pTileLocData) + { + SGP_THROW(L"bad aux tile data"); + } +} + STRUCTURE_FILE_REF * LoadStructureFile( STR szFileName ) { // NB should be passed in expected number of structures so we can check equality - UINT32 uiDataSize = 0; - BOOLEAN fOk; - STRUCTURE_FILE_REF * pFileRef; + UINT32 uiDataSize = 0; + BOOLEAN fOk; + STRUCTURE_FILE_REF* pFileRef; - pFileRef = (STRUCTURE_FILE_REF *) MemAlloc( sizeof( STRUCTURE_FILE_REF ) ); - if (pFileRef == NULL) + bool found_jsd_xml_file = false; + extern bool g_bUseXML_Structures; + + if(g_bUseXML_Structures) { - return( NULL ); + vfs::Path filename = std::string(szFileName) + ".xml"; + + if(getVFS()->fileExists(filename)) + { + pFileRef = (STRUCTURE_FILE_REF *) MemAlloc( sizeof( STRUCTURE_FILE_REF ) ); + memset( pFileRef, 0, sizeof( STRUCTURE_FILE_REF ) ); + + CStructureDataReader str_reader(pFileRef); + xml_auto::TGenericXMLParser str_parser(&str_reader); + + SGP_TRYCATCH_RETHROW( str_parser.parseFile(filename), _BS(L"Could not parse file : ") << filename << _BS::wget); + + uiDataSize = str_reader.structure_data_size; + fOk = TRUE; + + found_jsd_xml_file = true; + } + else + { + } } - memset( pFileRef, 0, sizeof( STRUCTURE_FILE_REF ) ); - fOk = LoadStructureData( szFileName, pFileRef, &uiDataSize ); + if(!found_jsd_xml_file) + { + pFileRef = (STRUCTURE_FILE_REF *) MemAlloc( sizeof( STRUCTURE_FILE_REF ) ); + if (pFileRef == NULL) + { + return( NULL ); + } + memset( pFileRef, 0, sizeof( STRUCTURE_FILE_REF ) ); + + if(g_bUseXML_Structures) + { + } + + fOk = LoadStructureData( szFileName, pFileRef, &uiDataSize ); + } + if (!fOk) { + SGP_WARNING("Could not load structure file : ") << szFileName << "[.jsd|.xml]" << sgp::endl << sgp::flush; MemFree( pFileRef ); return( NULL ); } + if (pFileRef->pubStructureData != NULL) { fOk = CreateFileStructureArrays( pFileRef, uiDataSize ); diff --git a/TileEngine/worlddef.cpp b/TileEngine/worlddef.cpp index d41b46ff..74a4e453 100644 --- a/TileEngine/worlddef.cpp +++ b/TileEngine/worlddef.cpp @@ -68,6 +68,8 @@ #include "LoadScreen.h"//dnl ch30 150909 #include "Interface Cursors.h" #include "Simple Render Utils.h"//dnl ch54 111009 +///ddd + #include "gamesettings.h" #endif #define SET_MOVEMENTCOST( a, b, c, d ) ( ( gubWorldMovementCosts[ a ][ b ][ c ] < d ) ? ( gubWorldMovementCosts[ a ][ b ][ c ] = d ) : 0 ); @@ -159,7 +161,11 @@ INT32 *gpDirtyData; UINT32 gSurfaceMemUsage; //UINT8 gubWorldMovementCosts[ WORLD_MAX ][MAXDIR][2]; UINT8 (*gubWorldMovementCosts)[MAXDIR][2] = NULL;//dnl ch43 260909 - +//ddd . +BOOLEAN gubWorldTileInLight[ MAX_ALLOWED_WORLD_MAX ]; +BOOLEAN gubIsCorpseThere[ MAX_ALLOWED_WORLD_MAX ]; +INT32 gubMerkCanSeeThisTile[ MAX_ALLOWED_WORLD_MAX ]; +//ddd // set to nonzero (locs of base gridno of structure are good) to have it defined by structure code INT16 gsRecompileAreaTop = 0; INT16 gsRecompileAreaLeft = 0; @@ -735,6 +741,48 @@ void CompileWorldTerrainIDs( void ) } } +///dddokno { +#pragma optimize("gpt",on) +__forceinline +BOOLEAN IsNotRestrictedWindow(STRUCTURE * pStructure) +{ + + if ( (pStructure->fFlags & STRUCTURE_WALLNWINDOW) && gGameExternalOptions.fCanJumpThroughWindows + && !(pStructure->fFlags & STRUCTURE_SPECIAL) + && (pStructure->fFlags & STRUCTURE_OPEN) + && (pStructure->pDBStructureRef->pDBStructure->bPartnerDelta == NO_PARTNER_STRUCTURE) ) + { + // ;( { + //build_13.sti - : + + LEVELNODE *pNode = NULL;// STRUCTURE *pBase=NULL; + UINT32 uiTileType=0; + //pBase = FindStructure( pStructure->sGridNo, STRUCTURE_WALLNWINDOW ); + //if(pBase!= NULL) + pNode = FindLevelNodeBasedOnStructure( pStructure->sGridNo, pStructure ); + //pNode = gpWorldLevelData[ pStructure->sGridNo ].pStructHead; + if(pNode != NULL) + GetTileType( pNode->usIndex, &uiTileType ); + + UINT16 RestrSubIndex; + GetSubIndexFromTileIndex( pNode->usIndex, (UINT16 *)&RestrSubIndex ); + + // 0 , + if ( _stricmp( gTilesets[ giCurrentTilesetID ].TileSurfaceFilenames[ uiTileType ], "build_13.sti" ) == 0 + //&& ( pNode->usIndex == 814 || pNode->usIndex == 816 || pNode->usIndex == 817 || pNode->usIndex == 823) - ;( + && (RestrSubIndex == 40 || RestrSubIndex == 41 || RestrSubIndex == 37 || RestrSubIndex == 38 + || RestrSubIndex == 43 || RestrSubIndex == 44 || RestrSubIndex == 46 || RestrSubIndex == 47) // + + ) + return FALSE; + + return TRUE; + } + + return FALSE; +} +///dddokno } + void CompileTileMovementCosts( INT32 usGridNo ) { UINT8 ubTerrainID; @@ -845,6 +893,229 @@ void CompileTileMovementCosts( INT32 usGridNo ) } // all other passable structures do not block movement in any way } + + /* + //dddokno{ ============================================================= + else if ( IsNotRestrictedWindow(pStructure) ) + { + // standard door + switch( pStructure->ubWallOrientation ) + { + case OUTSIDE_TOP_LEFT: + SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL ); + SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_JUMPABLEWINDOW ); + SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL ); + + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_WALL ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_JUMPABLEWINDOW_N ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_WALL ); + + // DO CORNERS + SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_WALL ); + SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_WALL ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_WALL ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_WALL ); + + break; + + case INSIDE_TOP_LEFT: + SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_WALL ); + SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_JUMPABLEWINDOW ); + SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_WALL ); + + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_JUMPABLEWINDOW_N ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + + // DO CORNERS + SET_MOVEMENTCOST( usGridNo - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + + break; + + case OUTSIDE_TOP_RIGHT: + SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); + SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_JUMPABLEWINDOW ); + SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); + + SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_JUMPABLEWINDOW_W ); + SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + + // DO CORNERS + SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + + + break; + + case INSIDE_TOP_RIGHT: + SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); + SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_JUMPABLEWINDOW ); + SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); + + SET_MOVEMENTCOST( usGridNo + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + 1, EAST, 0, TRAVELCOST_JUMPABLEWINDOW_W ); + SET_MOVEMENTCOST( usGridNo + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + + // DO CORNERS + SET_MOVEMENTCOST( usGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo - WORLD_COLS, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + SET_MOVEMENTCOST( usGridNo + WORLD_COLS, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + + break; + + + //switch( pStructure->ubWallOrientation ) + //{ + // case OUTSIDE_TOP_LEFT: //3 \# - , + // case INSIDE_TOP_LEFT: //1 - \ + // SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_JUMPABLEWINDOW ); + // SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE); + // SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_OBSTACLE); + // SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_JUMPABLEWINDOW); + // SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); + // //? + // FORCE_SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_NONE ); + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + // FORCE_SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_NONE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo - 1, WEST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + // + + + // break; + + // case OUTSIDE_TOP_RIGHT: //4 #/ // , + + // case INSIDE_TOP_RIGHT: + + // //2 #/ + // //. . + // // , + + + // SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_JUMPABLEWINDOW ); + // SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_JUMPABLEWINDOW ); + // SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); + // //? + // // set values for the tiles EXITED from this location + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + // // make sure no obstacle costs exists before changing path cost to 0 + // if ( gubWorldMovementCosts[ sGridNo + 1 ][ EAST ][ 0 ] < TRAVELCOST_BLOCKED ) + // { + // FORCE_SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_NONE ); + // } + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + // if ( gubWorldMovementCosts[ sGridNo - 1 ][ WEST ][ 0 ] < TRAVELCOST_BLOCKED ) + // { + // FORCE_SET_MOVEMENTCOST( sGridNo - 1, WEST, 0, TRAVELCOST_NONE ); + // } + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + + + // break; + // default: + // // corners aren't jumpable + // for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++) + // { + // SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE ); + // } + // break; + //} + + + + //************************************ . )) + //if ( (pStructure->fFlags & STRUCTURE_WALLNWINDOW) //&& !(pStructure->fFlags & STRUCTURE_SPECIAL) + // && (pStructure->fFlags & STRUCTURE_WALLSTUFF)==0 ) + //if(pStructure->pDBStructureRef->pDBStructure->bPartnerDelta == NO_PARTNER_STRUCTURE) + + // jumpable! + // switch( pStructure->ubWallOrientation ) + // { + // case OUTSIDE_TOP_LEFT: + // case INSIDE_TOP_LEFT: + // // can be jumped north and south + // SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_FENCE ); + // SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_FENCE ); + // SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); + // // set values for the tiles EXITED from this location + // FORCE_SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_NONE ); + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + // FORCE_SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_NONE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo - 1, WEST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + // break; + + // case OUTSIDE_TOP_RIGHT: + // case INSIDE_TOP_RIGHT: + // // can be jumped east and west + // SET_CURRMOVEMENTCOST( NORTH, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( NORTHEAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( EAST, TRAVELCOST_FENCE ); + // SET_CURRMOVEMENTCOST( SOUTHEAST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTH, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( SOUTHWEST, TRAVELCOST_OBSTACLE ); + // SET_CURRMOVEMENTCOST( WEST, TRAVELCOST_FENCE ); + // SET_CURRMOVEMENTCOST( NORTHWEST, TRAVELCOST_OBSTACLE ); + // // set values for the tiles EXITED from this location + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS, NORTH, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS + 1, NORTHEAST, 0, TRAVELCOST_OBSTACLE ); + // // make sure no obstacle costs exists before changing path cost to 0 + // if ( gubWorldMovementCosts[ sGridNo + 1 ][ EAST ][ 0 ] < TRAVELCOST_BLOCKED ) + // { + // FORCE_SET_MOVEMENTCOST( sGridNo + 1, EAST, 0, TRAVELCOST_NONE ); + // } + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS + 1, SOUTHEAST, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS, SOUTH, 0, TRAVELCOST_OBSTACLE ); + // SET_MOVEMENTCOST( sGridNo + WORLD_COLS - 1, SOUTHWEST, 0, TRAVELCOST_OBSTACLE ); + // if ( gubWorldMovementCosts[ sGridNo - 1 ][ WEST ][ 0 ] < TRAVELCOST_BLOCKED ) + // { + // FORCE_SET_MOVEMENTCOST( sGridNo - 1, WEST, 0, TRAVELCOST_NONE ); + // } + // SET_MOVEMENTCOST( sGridNo - WORLD_COLS - 1, NORTHWEST, 0, TRAVELCOST_OBSTACLE ); + // break; + + // //default: + // // corners aren't jumpable + // for (ubDirLoop=0; ubDirLoop < NUM_WORLD_DIRECTIONS; ubDirLoop++) + // { + // SET_CURRMOVEMENTCOST( ubDirLoop, TRAVELCOST_OBSTACLE ); + // } + // break; + // }//switch + //}//}if dddokno============================================================================== + */ + else if (pStructure->fFlags & STRUCTURE_BLOCKSMOVES) { if ( (pStructure->fFlags & STRUCTURE_FENCE) && !(pStructure->fFlags & STRUCTURE_SPECIAL) ) diff --git a/TileEngine/worlddef.h b/TileEngine/worlddef.h index 167174bd..0ccb7910 100644 --- a/TileEngine/worlddef.h +++ b/TileEngine/worlddef.h @@ -33,8 +33,10 @@ extern INT32 guiWorldRows; #define WORLD_MAX (WORLD_COLS*WORLD_ROWS) // WANNE - BMP: The maximum value WORLD_MAX can have. DONE! -#define MAX_ALLOWED_WORLD_MAX 4000000 // (1000 cols x 1000 rows) - +// CptMoore - DC: added MAX values here so it is known that display cover depends on them +#define WORLD_COLS_MAX 2000 +#define WORLD_ROWS_MAX 2000 +#define MAX_ALLOWED_WORLD_MAX WORLD_COLS_MAX*WORLD_ROWS_MAX // (2000 cols x 2000 rows) // @@ -284,6 +286,12 @@ extern MAP_ELEMENT *gpWorldLevelData; // World Movement Costs //UINT8 gubWorldMovementCosts[ WORLD_MAX ][MAXDIR][2]; +//ddd . +extern BOOLEAN gubWorldTileInLight[ MAX_ALLOWED_WORLD_MAX ]; +extern BOOLEAN gubIsCorpseThere[ MAX_ALLOWED_WORLD_MAX ]; // \ ;) +extern INT32 gubMerkCanSeeThisTile[ MAX_ALLOWED_WORLD_MAX ]; // , \ ? +//ddd + extern UINT8 (*gubWorldMovementCosts)[MAXDIR][2];//dnl ch43 260909 //dnl ch44 290909 Translation routine diff --git a/TileEngine/worldman.cpp b/TileEngine/worldman.cpp index 8d577480..65e5388f 100644 --- a/TileEngine/worldman.cpp +++ b/TileEngine/worldman.cpp @@ -3768,3 +3768,37 @@ void SetTreeTopStateForMap() // FOR THE NEXT RENDER LOOP, RE-EVALUATE REDUNDENT TILES InvalidateWorldRedundency( ); } + + + +//--------------------legion 2 Jazz--------------------------------------------------------------- +BOOLEAN IsOknoLevel( INT32 sGridNo ) +{ + STRUCTURE * pStructure; + + pStructure = FindStructure( sGridNo, STRUCTURE_WALLNWINDOW ); + + if ( pStructure != NULL && !( pStructure->fFlags & STRUCTURE_OPEN )) + { + return( TRUE ); + } + + return( FALSE ); + +} + +BOOLEAN IsLegionLevel( INT32 sGridNo ) +{ + STRUCTURE * pStructure; + + pStructure = FindStructure( sGridNo, STRUCTURE_FENCE ); + + if ( pStructure != NULL )//&& !( pStructure->fFlags & STRUCTURE_OPEN )) + { + return( TRUE ); + } + + return( FALSE ); + +} +//------------------------------------------------------------------- diff --git a/TileEngine/worldman.h b/TileEngine/worldman.h index 7de7acff..db7dbb33 100644 --- a/TileEngine/worldman.h +++ b/TileEngine/worldman.h @@ -153,4 +153,8 @@ extern UINT32 gCurrentBackground; void SetTreeTopStateForMap(); +//legion by Jazz +BOOLEAN IsOknoLevel( INT32 sGridNo ); +BOOLEAN IsLegionLevel( INT32 sGridNo ); + #endif \ No newline at end of file diff --git a/Utils/Cinematics Bink.cpp b/Utils/Cinematics Bink.cpp new file mode 100644 index 00000000..05f6d3f3 --- /dev/null +++ b/Utils/Cinematics Bink.cpp @@ -0,0 +1,433 @@ +#include "Types.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Debug.h" +#include "FileMan.h" +#include "smack.h" +#include "DDraw.h" +#include "mss.h" +#include "DirectX Common.h" +#include "DirectDraw Calls.h" +#include "SoundMan.h" +#include "Video.h" + +#include "Cinematics Bink.h" + +#include "vsurface_private.h" + +//#include "Intro.h" +#include +#include + + +#include "radmalw.i" + + +#include + + + +//******************************************************************* +// +// Local Defines +// +//******************************************************************* + + +#define BINK_NUM_FLICS 4 // Maximum number of flics open + + + +//******************************************************************* +// +// Global Variables +// +//******************************************************************* + +BINKFLIC BinkList[BINK_NUM_FLICS]; +UINT32 guiBinkPixelFormat=0; + +//LPDIRECTDRAWSURFACE lpBinkVideoPlayback=NULL; +LPDIRECTDRAWSURFACE2 lpBinkVideoPlayback2=NULL; +HWND hBinkDisplayWindow=0; +UINT32 guiHeight; + + + +//******************************************************************* +// +// Function Prototypes +// +//******************************************************************* + +void BinkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight); +void BinkShutdown(void); +BINKFLIC *BinkPlayFlic(CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, UINT32 uiFlags ); +BOOLEAN BinkPollFlics(void); +BINKFLIC *BinkOpenFlic(const CHAR8 *cFilename); +void BinkSetBlitPosition(BINKFLIC *pBink, UINT32 uiLeft, UINT32 uiTop); +void BinkCloseFlic(BINKFLIC *pBink); +BINKFLIC *BinkGetFreeFlic(void); +void BinkSetupVideo(void); +void BinkShutdownVideo(void); +UINT16 GetNumberOfBits( UINT32 uiMask ); + + + + + +//******************************************************************* +// +// Functions +// +//******************************************************************* + + + +void BinkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight) +{ + //HDIGDRIVER pSoundDriver = NULL; + void* pSoundDriver = NULL; + + + //Get the sound Driver handle + pSoundDriver = SoundGetDriverHandle(); + + //if we got the sound handle, use sound during the intro + if( pSoundDriver ) + { + BinkSoundUseDirectSound( pSoundDriver ); + } + + guiHeight = uiHeight; +} + + +void BinkShutdown(void) +{ + UINT32 uiCount; + + // Close and deallocate any open flics + for(uiCount=0; uiCount < BINK_NUM_FLICS; uiCount++) + { + //if the flic is currently open + if(BinkList[uiCount].uiFlags & BINK_FLIC_OPEN ) + { + //close it + BinkCloseFlic( &BinkList[uiCount] ); + } + } +} + + + +BINKFLIC *BinkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, UINT32 uiFlags ) +{ + BINKFLIC *pBink; + + // Open the flic + if( ( pBink = BinkOpenFlic( cFilename ) ) == NULL ) + { + return(NULL); + } + + if( uiFlags & BINK_FLIC_CENTER_VERTICAL) + { + uiTop = ( guiHeight - pBink->BinkHandle->Height ) / 2; + } + + // Set the blitting position on the screen + BinkSetBlitPosition( pBink, uiLeft, uiTop); + + // We're now playing, flag the flic for the poller to update + pBink->uiFlags |= BINK_FLIC_PLAYING; + + if( uiFlags & BINK_FLIC_AUTOCLOSE ) + { + pBink->uiFlags |= BINK_FLIC_AUTOCLOSE; + } + else + { + pBink->uiFlags |= BINK_FLIC_LOOP; + } + + + return(pBink); +} + +BINKFLIC *BinkOpenFlic( const CHAR8 *cFilename ) +{ + BINKFLIC *pBink; + + // Get an available flic slot from the list + if( !( pBink = BinkGetFreeFlic() ) ) + { + ErrorMsg("BINK ERROR: Out of flic slots, cannot open another"); + return(NULL); + } +#ifndef USE_VFS + // Attempt opening the filename + if(!(pBink->hFileHandle = FileOpen( const_cast(cFilename), FILE_OPEN_EXISTING | FILE_ACCESS_READ, FALSE ) ) ) + { + ErrorMsg("BINK ERROR: Can't open the BINK file"); + return(NULL); + } + + //Get the real file handle for the file man handle for the smacker file + HANDLE hFile = GetRealFileHandleFromFileManFileHandle( pBink->hFileHandle ); +#else + vfs::Path introname(cFilename); + vfs::Path dir,filename; + introname.splitLast(dir,filename); + vfs::Path tempfile = vfs::Path(L"Temp") + filename; + if(!getVFS()->fileExists(tempfile)) + { + try + { + if(!getVFS()->fileExists(introname)) + { + return NULL; + } + vfs::COpenReadFile rfile(introname); + vfs::size_t size = rfile->getSize(); + std::vector data(size); + rfile->read(&data[0],size); + + vfs::COpenWriteFile wfile(tempfile,true); + wfile->write(&data[0],size); + } + catch(std::exception& ex) + { + SGP_RETHROW(_BS(L"Intro file \"") << filename << L"\" could not be extracted" << _BS::wget, ex); + } + } +#endif + +#ifndef USE_VFS + if( !( pBink->BinkHandle = BinkOpen((CHAR8 *)hFile, BINKFILEHANDLE ) ) ) //| SMACKTRACKS +#else + vfs::Path tempfilename; + try + { + vfs::COpenWriteFile wfile(tempfile); + if(!wfile->_getRealPath(tempfilename)) + { + return NULL; + } + } + catch(std::exception& ex) + { + SGP_RETHROW(L"Temporary intro file could not be read", ex); + } + if( !( pBink->BinkHandle = BinkOpen(tempfilename.to_string().c_str(), BINKNOTHREADEDIO /*BINKFILEHANDLE*/ ) ) ) //| SMACKTRACKS +#endif + { + ErrorMsg("BINK ERROR: Bink won't open the BINK file"); + return(NULL); + } + + // Make sure we have a video surface + BinkSetupVideo(); + + pBink->cFilename = cFilename; + + pBink->lpDDS = lpBinkVideoPlayback2; + + pBink->hWindow = hBinkDisplayWindow; + + // Bink flic is now open and ready to go + pBink->uiFlags |= BINK_FLIC_OPEN; + + return( pBink ); +} + + + +BINKFLIC *BinkGetFreeFlic() +{ + UINT32 uiCount; + + //loop through to get a free slot + for( uiCount=0; uiCount < BINK_NUM_FLICS; uiCount++ ) + { + //if this slot is currently not in use + if( !( BinkList[uiCount].uiFlags & BINK_FLIC_OPEN ) ) + { + return( &BinkList[ uiCount ] ); + } + } + + return( NULL ); +} + + +void BinkSetBlitPosition( BINKFLIC *pBink, UINT32 uiLeft, UINT32 uiTop ) +{ + pBink->uiLeft = uiLeft; + pBink->uiTop = uiTop; +} + +void BinkCloseFlic( BINKFLIC *pBink ) +{ + // Deallocate the smack buffers +// SmackBufferClose(pSmack->SmackBuffer); + + // Close the smack flic + BinkClose(pBink->BinkHandle); + + // Attempt opening the filename + FileClose(pBink->hFileHandle); + + // Zero the memory, flags, etc. + memset( pBink, 0, sizeof(BINKFLIC) ); +} + + +BOOLEAN BinkPollFlics(void) +{ + UINT32 uiCount; + BOOLEAN fFlicStatus=FALSE; + DDSURFACEDESC SurfaceDescription; + BINKFLIC *pBink=NULL; + UINT32 uiCopyToBufferFlags = guiBinkPixelFormat; + + //loop through all the open flics + for(uiCount=0; uiCount < BINK_NUM_FLICS; uiCount++) + { + pBink = &BinkList[uiCount]; + + if( pBink->uiFlags & BINK_FLIC_PLAYING ) + { + fFlicStatus = TRUE; + + //do we still have to wait for the frame to be finished being displayed + if( !( BinkWait( pBink->BinkHandle ) ) ) + { + DDLockSurface( pBink->lpDDS, NULL, &SurfaceDescription, 0, NULL); + + BinkDoFrame( pBink->BinkHandle ); + + BinkCopyToBuffer( pBink->BinkHandle, + SurfaceDescription.lpSurface, + SurfaceDescription.lPitch, + pBink->BinkHandle->Height, + pBink->uiLeft, + pBink->uiTop, + uiCopyToBufferFlags ); + + + DDUnlockSurface( pBink->lpDDS, SurfaceDescription.lpSurface); + + // Check to see if the flic is done the last frame + if( pBink->BinkHandle->FrameNum == ( pBink->BinkHandle->Frames-1 ) ) + { + // If flic is looping, reset frame to 0 + if( pBink->uiFlags & BINK_FLIC_LOOP) + { + BinkGoto( pBink->BinkHandle, 0, 0 ); + } + else if( pBink->uiFlags & BINK_FLIC_AUTOCLOSE) + { + BinkCloseFlic( pBink ); + } + } + else + { + BinkNextFrame( BinkList[uiCount].BinkHandle ); + } + + } + } + } + + return( fFlicStatus ); +} + + + +void BinkSetupVideo(void) +{ + DDSURFACEDESC SurfaceDescription; + HRESULT ReturnCode; + UINT16 usRed, usGreen, usBlue; + HVSURFACE hVSurface; + + GetVideoSurface( &hVSurface, FRAME_BUFFER ); + + lpBinkVideoPlayback2 = GetVideoSurfaceDDSurface( hVSurface ); + + ZEROMEM(SurfaceDescription); + SurfaceDescription.dwSize = sizeof (DDSURFACEDESC); + + ReturnCode = IDirectDrawSurface2_GetSurfaceDesc ( lpBinkVideoPlayback2, &SurfaceDescription ); + if (ReturnCode != DD_OK) + { + DirectXAttempt ( ReturnCode, __LINE__, __FILE__ ); + return; + } + /* + usRed = (UINT16) SurfaceDescription.ddpfPixelFormat.dwRBitMask; + usGreen = (UINT16) SurfaceDescription.ddpfPixelFormat.dwGBitMask; + usBlue = (UINT16) SurfaceDescription.ddpfPixelFormat.dwBBitMask; + +// SurfaceDescription.ddpfPixelFormat + + if((usRed==0xf800) && (usGreen==0x07e0) && (usBlue==0x001f)) + guiBinkPixelFormat = BINKSURFACE565; + else + guiBinkPixelFormat = BINKSURFACE555; +*/ + // + // Get bit count for the RGB + // + usRed = GetNumberOfBits( SurfaceDescription.ddpfPixelFormat.dwRBitMask ); + usGreen = GetNumberOfBits( SurfaceDescription.ddpfPixelFormat.dwGBitMask ); + usBlue = GetNumberOfBits( SurfaceDescription.ddpfPixelFormat.dwBBitMask ); + + // 555 + if( usRed == 5 && usGreen == 5 && usBlue == 5 ) + { + guiBinkPixelFormat = BINKSURFACE555; + } + //565 + else if( usRed == 5 && usGreen == 6 && usBlue == 5 ) + { + guiBinkPixelFormat = BINKSURFACE565; + } + //655 + else if( usRed == 6 && usGreen == 5 && usBlue == 5 ) + { + guiBinkPixelFormat = BINKSURFACE655; + } + + //dont know the format, wont get video + else + { + guiBinkPixelFormat = 0; + } +} + +UINT16 GetNumberOfBits( UINT32 uiMask ) +{ + UINT16 usBits = 0; + + while( uiMask ) + { + uiMask = uiMask & ( uiMask - 1 ); + usBits++; + } + return usBits; +} + + +void BinkShutdownVideo(void) +{ +} diff --git a/Utils/Cinematics Bink.h b/Utils/Cinematics Bink.h new file mode 100644 index 00000000..f45ec3d4 --- /dev/null +++ b/Utils/Cinematics Bink.h @@ -0,0 +1,49 @@ +#ifndef _CINEMATICS_BINK__H_ +#define _CINEMATICS_BINK__H_ + + +#include "bink.h" + + + + +// BINKFLIC uiFlags +#define BINK_FLIC_OPEN 0x00000001 // Flic is open +#define BINK_FLIC_PLAYING 0x00000002 // Flic is playing +#define BINK_FLIC_LOOP 0x00000004 // Play flic in a loop +#define BINK_FLIC_AUTOCLOSE 0x00000008 // Close when done +#define BINK_FLIC_CENTER_VERTICAL 0x00000010 // Center the video on screen vertically + + + + +// Paused??? + +struct BINKFLIC +{ + const CHAR8 *cFilename; + HWFILE hFileHandle; + HBINK BinkHandle; +/// SmackBuf *SmackBuffer; + UINT32 uiFlags; + LPDIRECTDRAWSURFACE2 lpDDS; + HWND hWindow; + UINT32 uiFrame; + UINT32 uiLeft, uiTop; +// LPDIRECTDRAW2 lpDD; +// UINT32 uiNumFrames; +// UINT8 *pAudioData; +// UINT8 *pCueData; + +}; + + + +void BinkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight); +BOOLEAN BinkPollFlics(void); +void BinkCloseFlic(BINKFLIC *pBink); +void BinkShutdownVideo(void); +BINKFLIC *BinkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, UINT32 uiFlags ); + + +#endif \ No newline at end of file diff --git a/Utils/Cinematics.cpp b/Utils/Cinematics.cpp index f8b20bd8..cd98d22a 100644 --- a/Utils/Cinematics.cpp +++ b/Utils/Cinematics.cpp @@ -30,8 +30,8 @@ #include "DirectDraw Calls.h" #include "Cinematics.h" #include "soundman.h" -#include "VFS/vfs.h" -#include "VFS/vfs_file_raii.h" +#include +#include #ifdef JA2 #include "video.h" @@ -53,45 +53,45 @@ //-Flags-and-Symbols--------------------------------------------------------------- -#define SMK_NUM_FLICS 4 // Maximum number of flics open +#define SMK_NUM_FLICS 4 // Maximum number of flics open // SMKFLIC uiFlags #define SMK_FLIC_OPEN 0x00000001 // Flic is open -#define SMK_FLIC_PLAYING 0x00000002 // Flic is playing +#define SMK_FLIC_PLAYING 0x00000002 // Flic is playing #define SMK_FLIC_LOOP 0x00000004 // Play flic in a loop -#define SMK_FLIC_AUTOCLOSE 0x00000008 // Close when done +#define SMK_FLIC_AUTOCLOSE 0x00000008 // Close when done //-Globals------------------------------------------------------------------------- SMKFLIC SmkList[SMK_NUM_FLICS]; -HWND hDisplayWindow=0; -UINT32 uiDisplayHeight, uiDisplayWidth; -BOOLEAN fSuspendFlics=FALSE; -UINT32 uiFlicsPlaying=0; -UINT32 guiSmackPixelFormat=SMACKBUFFER565; +HWND hDisplayWindow = 0; +UINT32 uiDisplayHeight, uiDisplayWidth; +BOOLEAN fSuspendFlics = FALSE; +UINT32 uiFlicsPlaying = 0; +UINT32 guiSmackPixelFormat = SMACKBUFFER565; LPDIRECTDRAWSURFACE lpVideoPlayback=NULL; LPDIRECTDRAWSURFACE2 lpVideoPlayback2=NULL; //-Function-Prototypes------------------------------------------------------------- -void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight); -void SmkShutdown(void); +void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight); +void SmkShutdown(void); SMKFLIC *SmkPlayFlic(CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fAutoClose); BOOLEAN SmkPollFlics(void); SMKFLIC *SmkOpenFlic(CHAR8 *cFilename); -void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop); -void SmkCloseFlic(SMKFLIC *pSmack); +void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop); +void SmkCloseFlic(SMKFLIC *pSmack); SMKFLIC *SmkGetFreeFlic(void); -void SmkSetupVideo(void); -void SmkShutdownVideo(void); +void SmkSetupVideo(void); +void SmkShutdownVideo(void); BOOLEAN SmkPollFlics(void) { -UINT32 uiCount; -BOOLEAN fFlicStatus=FALSE; -DDSURFACEDESC SurfaceDescription; + UINT32 uiCount; + BOOLEAN fFlicStatus = FALSE; + DDSURFACEDESC SurfaceDescription; for(uiCount=0; uiCount < SMK_NUM_FLICS; uiCount++) { @@ -103,7 +103,7 @@ DDSURFACEDESC SurfaceDescription; if(!SmackWait(SmkList[uiCount].SmackHandle)) { DDLockSurface(SmkList[uiCount].lpDDS, NULL, &SurfaceDescription, 0, NULL); - SmackToBuffer(SmkList[uiCount].SmackHandle,SmkList[uiCount].uiLeft, + SmackToBuffer(SmkList[uiCount].SmackHandle,SmkList[uiCount].uiLeft, SmkList[uiCount].uiTop, SurfaceDescription.lPitch, SmkList[uiCount].SmackHandle->Height, @@ -124,7 +124,9 @@ DDSURFACEDESC SurfaceDescription; SmkCloseFlic(&SmkList[uiCount]); } else + { SmackNextFrame(SmkList[uiCount].SmackHandle); + } } } } @@ -138,21 +140,19 @@ DDSURFACEDESC SurfaceDescription; // Lesh changed this function only ----------------------------- void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight) { - void *pSoundDriver = NULL; - // Wipe the flic list clean memset(SmkList, 0, sizeof(SMKFLIC)*SMK_NUM_FLICS); // Set playback window properties - hDisplayWindow=hWindow; - uiDisplayWidth=uiWidth; - uiDisplayHeight=uiHeight; + hDisplayWindow = hWindow; + uiDisplayWidth = uiWidth; + uiDisplayHeight= uiHeight; // Use MMX acceleration, if available SmackUseMMX(1); //Get the sound Driver handle - pSoundDriver = SoundGetDriverHandle(); + void* pSoundDriver = SoundGetDriverHandle(); //if we got the sound handle, use sound during the intro if( pSoundDriver ) @@ -161,7 +161,7 @@ void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight) void SmkShutdown(void) { -UINT32 uiCount; + UINT32 uiCount; // Close and deallocate any open flics for(uiCount=0; uiCount < SMK_NUM_FLICS; uiCount++) @@ -171,9 +171,9 @@ UINT32 uiCount; } } -SMKFLIC *SmkPlayFlic(CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fClose) +SMKFLIC *SmkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fClose) { -SMKFLIC *pSmack; + SMKFLIC *pSmack; // Open the flic if((pSmack=SmkOpenFlic(cFilename))==NULL) @@ -190,11 +190,10 @@ SMKFLIC *pSmack; return(pSmack); } -SMKFLIC *SmkOpenFlic(CHAR8 *cFilename) +SMKFLIC *SmkOpenFlic(const CHAR8 *cFilename) { SMKFLIC *pSmack; - // Get an available flic slot from the list if(!(pSmack=SmkGetFreeFlic())) { @@ -228,18 +227,16 @@ SMKFLIC *SmkOpenFlic(CHAR8 *cFilename) return NULL; } vfs::COpenReadFile rfile(introname); - vfs::size_t size = rfile.file().getSize(); + vfs::size_t size = rfile->getSize(); std::vector data(size); - rfile.file().read(&data[0],size); + rfile->read(&data[0],size); vfs::COpenWriteFile wfile(tempfile,true); - wfile.file().write(&data[0],size); + wfile->write(&data[0],size); } - catch(CBasicException& ex) + catch(std::exception& ex) { - BuildString bs; - bs.add(L"Intro file \"").add(filename()).add(L"\" could not be extracted"); - RETHROWEXCEPTION(bs.get(), &ex); + SGP_RETHROW(_BS(L"Intro file \"") << filename << L"\" could not be extracted" << _BS::wget, ex); } } #endif @@ -258,14 +255,14 @@ SMKFLIC *SmkOpenFlic(CHAR8 *cFilename) try { vfs::COpenWriteFile wfile(tempfile); - if(!wfile.file()._getRealPath(tempfilename)) + if(!wfile->_getRealPath(tempfilename)) { return NULL; } } - catch(CBasicException& ex) + catch(std::exception& ex) { - RETHROWEXCEPTION(L"Temporary intro file could not be read", &ex); + SGP_RETHROW(L"Temporary intro file could not be read", ex); } if(!(pSmack->SmackHandle=SmackOpen(tempfilename.to_string().c_str(), SMACKTRACKS, SMACKAUTOEXTRA))) #endif @@ -310,7 +307,7 @@ void SmkCloseFlic(SMKFLIC *pSmack) SMKFLIC *SmkGetFreeFlic(void) { -UINT32 uiCount; + UINT32 uiCount; for(uiCount=0; uiCount < SMK_NUM_FLICS; uiCount++) if(!(SmkList[uiCount].uiFlags & SMK_FLIC_OPEN)) @@ -321,26 +318,24 @@ UINT32 uiCount; void SmkSetupVideo(void) { - DDSURFACEDESC SurfaceDescription; - HRESULT ReturnCode; - UINT16 usRed, usGreen, usBlue; - HVSURFACE hVSurface; - // DEF: -// lpVideoPlayback2=CinematicModeOn(); +// lpVideoPlayback2 = CinematicModeOn(); + HVSURFACE hVSurface; GetVideoSurface( &hVSurface, FRAME_BUFFER ); lpVideoPlayback2 = GetVideoSurfaceDDSurface( hVSurface ); + DDSURFACEDESC SurfaceDescription; ZEROMEM(SurfaceDescription); SurfaceDescription.dwSize = sizeof (DDSURFACEDESC); - ReturnCode = IDirectDrawSurface2_GetSurfaceDesc ( lpVideoPlayback2, &SurfaceDescription ); + HRESULT ReturnCode = IDirectDrawSurface2_GetSurfaceDesc ( lpVideoPlayback2, &SurfaceDescription ); if (ReturnCode != DD_OK) { - DirectXAttempt ( ReturnCode, __LINE__, __FILE__ ); - return; + DirectXAttempt ( ReturnCode, __LINE__, __FILE__ ); + return; } + UINT16 usRed, usGreen, usBlue; usRed = (UINT16) SurfaceDescription.ddpfPixelFormat.dwRBitMask; usGreen = (UINT16) SurfaceDescription.ddpfPixelFormat.dwGBitMask; usBlue = (UINT16) SurfaceDescription.ddpfPixelFormat.dwBBitMask; diff --git a/Utils/Cinematics.h b/Utils/Cinematics.h index e2f969c2..52be5601 100644 --- a/Utils/Cinematics.h +++ b/Utils/Cinematics.h @@ -3,31 +3,31 @@ #include "smack.h" -typedef struct { - - CHAR8 *cFilename; -// HFILE hFileHandle; - HWFILE hFileHandle; - Smack *SmackHandle; - SmackBuf *SmackBuffer; - UINT32 uiFlags; +struct SMKFLIC +{ + const CHAR8 *cFilename; +// HFILE hFileHandle; + HWFILE hFileHandle; + Smack *SmackHandle; + SmackBuf *SmackBuffer; + UINT32 uiFlags; LPDIRECTDRAWSURFACE2 lpDDS; - HWND hWindow; - UINT32 uiFrame; - UINT32 uiLeft, uiTop; -// LPDIRECTDRAW2 lpDD; -// UINT32 uiNumFrames; -// UINT8 *pAudioData; -// UINT8 *pCueData; - } SMKFLIC; + HWND hWindow; + UINT32 uiFrame; + UINT32 uiLeft, uiTop; +// LPDIRECTDRAW2 lpDD; +// UINT32 uiNumFrames; +// UINT8 *pAudioData; +// UINT8 *pCueData; +}; -void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight); -void SmkShutdown(void); -SMKFLIC *SmkPlayFlic(CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fAutoClose); +void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight); +void SmkShutdown(void); +SMKFLIC *SmkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fAutoClose); BOOLEAN SmkPollFlics(void); -SMKFLIC *SmkOpenFlic(CHAR8 *cFilename); -void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop); -void SmkCloseFlic(SMKFLIC *pSmack); +SMKFLIC *SmkOpenFlic(const CHAR8 *cFilename); +void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop); +void SmkCloseFlic(SMKFLIC *pSmack); SMKFLIC *SmkGetFreeFlic(void); /* diff --git a/Utils/Cursors.cpp b/Utils/Cursors.cpp index c1c574de..2da6039f 100644 --- a/Utils/Cursors.cpp +++ b/Utils/Cursors.cpp @@ -1189,6 +1189,16 @@ CursorData CursorDatabase[] = void InitCursors( ) { + //CHRISL: NCTH uses a completely different cursor so if we're in NCTH mode, we want to use different graphics + if(UsingNewCTHSystem() == true){ + strncpy((char *)CursorFileDatabase[2].ubFilename,"CURSORS\\cur_tagr_ncth.sti",MAX_FILENAME_LEN); + strncpy((char *)CursorFileDatabase[3].ubFilename,"CURSORS\\targblak_ncth.sti",MAX_FILENAME_LEN); + strncpy((char *)CursorFileDatabase[5].ubFilename,"CURSORS\\cur_rbst_ncth.sti",MAX_FILENAME_LEN); + strncpy((char *)CursorFileDatabase[6].ubFilename,"CURSORS\\burstblk_ncth.sti",MAX_FILENAME_LEN); + strncpy((char *)CursorFileDatabase[7].ubFilename,"CURSORS\\cur_tr_ncth.sti",MAX_FILENAME_LEN); + strncpy((char *)CursorFileDatabase[8].ubFilename,"CURSORS\\cur_trw_ncth.sti",MAX_FILENAME_LEN); + strncpy((char *)CursorFileDatabase[35].ubFilename,"CURSORS\\cur_try_ncth.sti",MAX_FILENAME_LEN); + } InitCursorDatabase( CursorFileDatabase, CursorDatabase, NUM_CURSOR_FILES ); SetMouseBltHook( (MOUSEBLT_HOOK)BltJA2CursorData ); @@ -1244,8 +1254,99 @@ extern INT16 gsCurMouseOffsetY; extern UINT16 gsCurMouseHeight; extern UINT16 gsCurMouseWidth;*/ +void DrawMouseGraphicsNCTH( ) +{ + ////////////////////////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: This entire cursor drawing function is now OBSOLETE in NCTH. + // Instead of drawing the targeting cursor on limited cursor space (in the MOUSEBUFFER), + // I draw the new indicator directly on the FRAMEBUFFER through a function in + // Tactical\Interface.CPP. It bypasses the cursor system entirely in order to create + // a pseudo-cursor that can potentially be as large as the viewport (or larger). That + // is unfortunately not doable with the cursor system, so this code is now commented out. + + // HEADROCK (HAM): Made several changes here to allow multi-shot CtH display for bursts. + UINT16 * ptrBuf; + UINT32 uiPitch; + UINT32 cnt, i; + UINT32 actualPct = __min(gbCtH[0],99); + UINT16 usCBorderTop = Get16BPPColor( FROMRGB( 155, 155, 155 ) ); + UINT16 usCBorderBottom = Get16BPPColor( FROMRGB( 120, 120, 120 ) ); + UINT16 usCBar = Get16BPPColor( FROMRGB( 255, 255-255*actualPct/99, 0 ) ); + UINT16 usCBack = Get16BPPColor( FROMRGB( 155, 155-155*actualPct/99, 0 ) ); + UINT16 usCBar2 = Get16BPPColor( FROMRGB( 180, 140-140*actualPct/99, 0 ) ); + UINT16 usCBack2 = Get16BPPColor( FROMRGB( 110, 100-100*actualPct/99, 0 ) ); + UINT32 barLength = __min(35,gsCurMouseWidth); + //UINT32 barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2; + UINT32 barY; + + if(gfUICtHBar) + { + // HEADROCK HAM B1/2/2.6: + // This causes the function to display two CTH bars for autofire - the CTH of the first bullet, + // and the CTH of the last bullet in the volley, stored in gbCtH[0] and [1] respectively. + if ( gbCtHAutoFire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) ) + gbCtHBurstCount = 2; + else if ( gbCtHAutoFire ) + gbCtHBurstCount = 0; + + + // Sets the initial offsets of the bars. Burst and Autofire will display them higher above the + // cursor, to avoid obscuring the target or other data. + if (gbCtHBurstCount > 1 && !gbCtHAutoFire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) ) + barY = gsCurMouseOffsetY-__min(55,gsCurMouseHeight)/2; + else if (gbCtHBurstCount && gbCtHAutoFire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) ) + barY = gsCurMouseOffsetY-__min(55,gsCurMouseHeight)/2; + else + barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2; + + for (i=0; i>= 1; + + for(cnt = gsCurMouseOffsetX+barLength/2;cnt > gsCurMouseOffsetX-barLength/2+1;cnt--) + { + ptrBuf[cnt-1 + uiPitch*(3+barY)] = usCBorderBottom; + ptrBuf[cnt-1 + uiPitch*barY] = usCBorderTop; + } + + ptrBuf[gsCurMouseOffsetX+barLength/2 + uiPitch*(1+barY)] = usCBorderBottom; + ptrBuf[gsCurMouseOffsetX-barLength/2 + uiPitch*(1+barY)] = usCBorderTop; + + ptrBuf[gsCurMouseOffsetX+barLength/2 + uiPitch*(2+barY)] = usCBorderBottom; + ptrBuf[gsCurMouseOffsetX-barLength/2 + uiPitch*(2+barY)] = usCBorderTop; + + + for(cnt = 0;cnt < (barLength-2)*actualPct/99;cnt++) + { + ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+2)] = usCBar2; + ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+1)] = usCBar; + } + + for(cnt = (barLength-2)*actualPct/99;cnt < (barLength-2);cnt++) + { + ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+2)] = usCBack2; + ptrBuf[cnt + gsCurMouseOffsetX-barLength/2+1 + uiPitch*(barY+1)] = usCBack; + } + + + UnlockMouseBuffer(); + if (gbCtHBurstCount>1) + barY = barY+5; + } + barY = gsCurMouseOffsetY-__min(35,gsCurMouseHeight)/2; + } + +} + void DrawMouseGraphics( ) { + if(UsingNewCTHSystem() == true){ + DrawMouseGraphicsNCTH(); + return; + } // HEADROCK (HAM): Made several changes here to allow multi-shot CtH display for bursts. UINT16 * ptrBuf; UINT32 uiPitch; @@ -1359,7 +1460,7 @@ void DrawMouseText( ) } - if ( gfUIAutofireBulletCount ) + if ( UsingNewCTHSystem() == false && gfUIAutofireBulletCount ) { // Set dest for gprintf to be different SetFontDestBuffer( MOUSE_BUFFER , 0, 0, 64, 64, FALSE ); @@ -1436,7 +1537,10 @@ void DrawMouseText( ) //if ( ( ( gTacticalStatus.uiFlags & TURNBASED ) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) ) { - if ( gfUIDisplayActionPoints ) + // HEADROCK HAM 4: Added condition - the AP cost will no longer be displayed in the center when + // aiming a weapon. It will instead by displayed on the new NCTH Indicator. + if ( (UsingNewCTHSystem() == false && gfUIDisplayActionPoints) || + (UsingNewCTHSystem() == true && gfUIDisplayActionPoints && !gfUICtHBar) ) { if ( gfUIDisplayActionPointsInvalid ) { diff --git a/Utils/Debug Control.cpp b/Utils/Debug Control.cpp index 36458839..3b0e8771 100644 --- a/Utils/Debug Control.cpp +++ b/Utils/Debug Control.cpp @@ -6,8 +6,7 @@ #include "stdio.h" #endif -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" +#include "sgp_logger.h" #ifdef _ANIMSUBSYSTEM_DEBUG @@ -57,6 +56,13 @@ void AiDbgMessage( CHAR8 *strMessage) #endif +static struct LiveLog { + sgp::Logger_ID id; + LiveLog() { + id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(id, L"LiveLog.txt", false, sgp::Logger::FLUSH_ON_ENDL); + }; +} s_LiveLog; void LiveMessage( CHAR8 *strMessage) { @@ -69,8 +75,7 @@ void LiveMessage( CHAR8 *strMessage) fclose(OutFile); } #else - static CLog& liveMsg = *CLog::create(L"LiveLog.txt",true); - liveMsg << strMessage << CLog::ENDL; + SGP_LOG(s_LiveLog.id, strMessage); #endif } void MPDebugMsg( CHAR8 *strMessage) @@ -84,7 +89,7 @@ void MPDebugMsg( CHAR8 *strMessage) fclose(OutFile); } #else - static CLog& mpMsg = *CLog::create(L"MPDebug.txt", true); - mpMsg << strMessage << CLog::ENDL; + static vfs::Log& mpMsg = *vfs::Log::create(L"MPDebug.txt", true); + mpMsg << strMessage << vfs::Log::endl; #endif } diff --git a/Utils/ExportStrings.cpp b/Utils/ExportStrings.cpp new file mode 100644 index 00000000..666f5a6c --- /dev/null +++ b/Utils/ExportStrings.cpp @@ -0,0 +1,701 @@ +#include "ExportStrings.h" +#include "LocalizedStrings.h" +#include "Map Screen Interface.h" +#include "personnel.h" +#include "soldier profile type.h" +#include "interface.h" +#include "Keys.h" +#include "Merc Contract.h" +#include "Campaign Types.h" +#include "Finances.h" +#include "Laptop.h" + +#include +#include +#include +#include + +namespace Loc +{ + bool Translate(vfs::String::char_t* str, int len, Language lang); + + void ExportMercBio(); + void ExportAIMHistory(); + void ExportAIMPolicy(); + void ExportAlumniName(); + void ExportDialogues(); + void ExportNPCDialogues(); +}; + +////////////////////////////////////////////////////////// + +//#define GERMAN +#include "Text.h" +namespace Loc +{ +#ifdef CHINESE +# include "_ChineseText.cpp" + static Loc::Language gs_Lang = Loc::Chinese; +#endif +#ifdef DUTCH +# include "_DutchText.cpp" + static Loc::Language gs_Lang = Loc::Dutch; +#endif +#ifdef ENGLISH +# include "_EnglishText.cpp" + static Loc::Language gs_Lang = Loc::English; +#endif +#ifdef FRENCH +# include "_FrenchText.cpp" + static Loc::Language gs_Lang = Loc::French; +#endif +#ifdef GERMAN +# include "_GermanText.cpp" + static Loc::Language gs_Lang = Loc::German; +#endif +#ifdef ITALIAN +# include "_ItalianText.cpp" + static Loc::Language gs_Lang = Loc::Italian; +#endif +#ifdef POLISH +# include "_PolishText.cpp" + static Loc::Language gs_Lang = Loc::Polish; +#endif +#ifdef RUSSIAN +# include "_RussianText.cpp" + static Loc::Language gs_Lang = Loc::Russian; +#endif +#ifdef TAIWANESE +# include "_TaiwaneseText.cpp" + static Loc::Language gs_Lang = Loc::Taiwanese; +#endif +} + +#include "Assignments.h" +#include "History.h" + +template +void ExportSection(vfs::PropertyContainer& props, const vfs::String::char_t* section_name, T* strings, int min, int max) +{ + for(int i = min; i < max; ++i) + { + vfs::String str(strings[i]); + //Loc::Translate(&str.r_wcs()[0],str.length(), gs_Lang); + if(!str.empty()) + { + props.setStringProperty(section_name, vfs::toString(i), str); + } + } +} + +template<> +void ExportSection(vfs::PropertyContainer& props, const vfs::String::char_t* section_name, wchar_t* strings, int min, int max) +{ + ExportSection(props,section_name, &strings, min, max); +} + + +bool Loc::ExportStrings() +{ + vfs::PropertyContainer::TagMap tmap; + //tmap.Container(L"LocalizedStrings"); + //tmap.Section(L"Topic"); + //tmap.SectionID(L"name"); + //tmap.Key(L"msg"); + //tmap.KeyID(L"index"); + + vfs::PropertyContainer props; + + //not_required ExportSection(props, L"Ja2Credits", Loc::pCreditsJA2113, 0, 7); + ExportSection(props, L"WeaponType", Loc::WeaponType, 0, MAXITEMS); + ExportSection(props, L"TeamTurn", Loc::TeamTurnString, 0, 10); + ExportSection(props, L"Message", Loc::Message, 0, TEXT_NUM_STR_MESSAGE); + ExportSection(props, L"TownNames", Loc::pTownNames, 0, MAX_TOWNS); + ExportSection(props, L"Time", Loc::sTimeStrings, 0, 6); + ExportSection(props, L"Assignment", Loc::pAssignmentStrings, 0, NUM_ASSIGNMENTS); + ExportSection(props, L"PersonnelAssignment", Loc::pPersonnelAssignmentStrings, 0, NUM_ASSIGNMENTS); + ExportSection(props, L"LongAssignment", Loc::pLongAssignmentStrings, 0, NUM_ASSIGNMENTS); + ExportSection(props, L"Militia", Loc::pMilitiaString, 0, 3); + + ExportSection(props, L"MilitiaButton", Loc::pMilitiaButtonString, 0, 2); + ExportSection(props, L"Condition", Loc::pConditionStrings, 0, 9); + ExportSection(props, L"EpcMenu", Loc::pEpcMenuStrings, 0, MAX_EPC_MENU_STRING_COUNT); + ExportSection(props, L"Contract", Loc::pContractStrings, 0, MAX_CONTRACT_MENU_STRING_COUNT); + ExportSection(props, L"POW", Loc::pPOWStrings, 0, 2); + ExportSection(props, L"InvPanelTitle", Loc::pInvPanelTitleStrings, 0, 5); + ExportSection(props, L"LongAttribute", Loc::pLongAttributeStrings, 0, 10); + ExportSection(props, L"ShortAttribute", Loc::pShortAttributeStrings, 0, 10); + ExportSection(props, L"UpperLeftMapScreen", Loc::pUpperLeftMapScreenStrings, 0, 6); + ExportSection(props, L"Training", Loc::pTrainingStrings, 0, 4); + + ExportSection(props, L"GuardMenu", Loc::pGuardMenuStrings, 0, 10); + ExportSection(props, L"OtherGuardMenu", Loc::pOtherGuardMenuStrings, 0, 10); + ExportSection(props, L"AssignMenu", Loc::pAssignMenuStrings, 0, MAX_ASSIGN_STRING_COUNT); + ExportSection(props, L"MilitiaControlMenu", Loc::pMilitiaControlMenuStrings, 0, MAX_MILCON_STRING_COUNT); + ExportSection(props, L"RemoveMerc", Loc::pRemoveMercStrings, 0, MAX_REMOVE_MERC_COUNT); + ExportSection(props, L"AttributeMenu", Loc::pAttributeMenuStrings, 0, MAX_ATTRIBUTE_STRING_COUNT); + ExportSection(props, L"TrainingMenu", Loc::pTrainingMenuStrings, 0, MAX_TRAIN_STRING_COUNT); + ExportSection(props, L"SquadMenu", Loc::pSquadMenuStrings, 0, MAX_SQUAD_MENU_STRING_COUNT); + ExportSection(props, L"PersonnelTitle", Loc::pPersonnelTitle, 0, 1); + ExportSection(props, L"PersonnelScreen", Loc::pPersonnelScreenStrings, 0, TEXT_NUM_PRSNL); + + ExportSection(props, L"MercSkill", Loc::gzMercSkillText, 0, NUM_SKILLTRAITS_OT); + ExportSection(props, L"TacticalPopupButton", Loc::pTacticalPopupButtonStrings, 0, NUM_ICONS); + ExportSection(props, L"DoorTrap", Loc::pDoorTrapStrings, 0, NUM_DOOR_TRAPS); + ExportSection(props, L"ContractExtend", Loc::pContractExtendStrings, 0, NUM_CONTRACT_EXTEND); + ExportSection(props, L"MapScreenMouseRegionHelp", Loc::pMapScreenMouseRegionHelpText, 0, 6); + ExportSection(props, L"NoiseVol", Loc::pNoiseVolStr, 0, 4); + ExportSection(props, L"NoiseType", Loc::pNoiseTypeStr, 0, 12); + ExportSection(props, L"Direction", Loc::pDirectionStr, 0, 8); + ExportSection(props, L"LandType", Loc::pLandTypeStrings, 0, NUM_TRAVTERRAIN_TYPES); + ExportSection(props, L"Strategic", Loc::gpStrategicString, 0, TEXT_NUM_STRATEGIC_TEXT); + + ExportSection(props, L"GameClock", Loc::gpGameClockString, 0, TEXT_NUM_GAMECLOCK); + ExportSection(props, L"KeyDescription", Loc::sKeyDescriptionStrings, 0, 2); + ExportSection(props, L"WeaponStatsDesc", Loc::gWeaponStatsDesc, 0, 17); + ExportSection(props, L"WeaponStatsFasthelp", Loc::gzWeaponStatsFasthelp, 0, 29); + ExportSection(props, L"WeaponStatsFasthelpTactical",Loc::gzWeaponStatsFasthelpTactical, 0, 29); + ExportSection(props, L"AmmoStatsFasthelp", Loc::gzAmmoStatsFasthelp, 0, 20); + ExportSection(props, L"ArmorStatsFasthelp", Loc::gzArmorStatsFasthelp, 0, 20); + ExportSection(props, L"ExplosiveStatsFasthelp", Loc::gzExplosiveStatsFasthelp, 0, 20); + ExportSection(props, L"MiscItemStatsFasthelp", Loc::gzMiscItemStatsFasthelp, 0, 34); + ExportSection(props, L"MoneyStatsDesc", Loc::gMoneyStatsDesc, 0, TEXT_NUM_MONEY_DESC); + + ExportSection(props, L"Health", Loc::zHealthStr, 0, 7); + ExportSection(props, L"MoneyAmounts", Loc::gzMoneyAmounts, 0, 6); + ExportSection(props, L"ProsLabel", Loc::gzProsLabel, 0, 1); + ExportSection(props, L"ConsLabel", Loc::gzConsLabel, 0, 1); + ExportSection(props, L"TalkMenu", Loc::zTalkMenuStrings, 0, 6); + ExportSection(props, L"Dealer", Loc::zDealerStrings, 0, 4); + ExportSection(props, L"DialogActions", Loc::zDialogActions, 0, 1); + ExportSection(props, L"Vehicle", Loc::pVehicleStrings, 0, 6); + ExportSection(props, L"ShortVehicle", Loc::pShortVehicleStrings, 0, 6); + ExportSection(props, L"VehicleName", Loc::zVehicleName, 0, 6); + + ExportSection(props, L"Tactical", Loc::TacticalStr, 0, TEXT_NUM_TACTICAL_STR); + ExportSection(props, L"ExitingSectorHelp", Loc::pExitingSectorHelpText, 0, TEXT_NUM_EXIT_GUI); + ExportSection(props, L"Repair", Loc::pRepairStrings, 0, 4); + ExportSection(props, L"PreStatBuild", Loc::sPreStatBuildString, 0, 6); + ExportSection(props, L"StatGain", Loc::sStatGainStrings, 0, 11); + ExportSection(props, L"HelicopterEta", Loc::pHelicopterEtaStrings, 0, 10); + ExportSection(props, L"MapLevel", Loc::sMapLevelString, 0, 1); + ExportSection(props, L"Loyal", Loc::gsLoyalString, 0, 1); + ExportSection(props, L"Underground", Loc::gsUndergroundString, 0, 1); + ExportSection(props, L"TimeStings", Loc::gsTimeStrings, 0, 1); + + ExportSection(props, L"Facilities", Loc::sFacilitiesStrings, 0, 7); + ExportSection(props, L"MapPopUpInventory", Loc::pMapPopUpInventoryText, 0, 2); + ExportSection(props, L"TownInfo", Loc::pwTownInfoStrings, 0, 12); + ExportSection(props, L"Mine", Loc::pwMineStrings, 0, 14); + ExportSection(props, L"MiscSector", Loc::pwMiscSectorStrings, 0, 7); + ExportSection(props, L"MapInventoryError", Loc::pMapInventoryErrorString, 0, 7); + ExportSection(props, L"MapInventory", Loc::pMapInventoryStrings, 0, 2); + ExportSection(props, L"MapScreenFastHelp", Loc::pMapScreenFastHelpTextList, 0, 10); + ExportSection(props, L"MovementMenu", Loc::pMovementMenuStrings, 0, 4); + ExportSection(props, L"UpdateMerc", Loc::pUpdateMercStrings, 0, 6); + + ExportSection(props, L"MapScreenBorderButtonHelp", Loc::pMapScreenBorderButtonHelpText,0, 6); + ExportSection(props, L"MapScreenBottomFastHelp", Loc::pMapScreenBottomFastHelp, 0, 8); + ExportSection(props, L"MapScreenBottom", Loc::pMapScreenBottomText, 0, 1); + ExportSection(props, L"MercDead", Loc::pMercDeadString, 0, 1); + ExportSection(props, L"Day", Loc::pDayStrings, 0, 1); + ExportSection(props, L"SenderName", Loc::pSenderNameList, 0, 51); + ExportSection(props, L"Traverse", Loc::pTraverseStrings, 0, 2); + ExportSection(props, L"NewMail", Loc::pNewMailStrings, 0, 1); + ExportSection(props, L"DeleteMail", Loc::pDeleteMailStrings, 0, 2); + ExportSection(props, L"EmailHeader", Loc::pEmailHeaders, 0, 3); + + ExportSection(props, L"EmailTitle", Loc::pEmailTitleText, 0, 1); + ExportSection(props, L"FinanceTitle", Loc::pFinanceTitle, 0, 1); + ExportSection(props, L"FinanceSummary", Loc::pFinanceSummary, 0, 12); + ExportSection(props, L"FinanceHeader", Loc::pFinanceHeaders, 0, 7); + ExportSection(props, L"Transaction", Loc::pTransactionText, 0, TEXT_NUM_FINCANCES); + ExportSection(props, L"TransactionAlternate", Loc::pTransactionAlternateText, 0, 4); + ExportSection(props, L"Skyrider", Loc::pSkyriderText, 0, 7); + ExportSection(props, L"Moral", Loc::pMoralStrings, 0, 6); + ExportSection(props, L"LeftEquipment", Loc::pLeftEquipmentString, 0, 2); + ExportSection(props, L"MapScreenStatus", Loc::pMapScreenStatusStrings, 0, 5); + + ExportSection(props, L"MapScreenPrevNextCharButtonHelp", Loc::pMapScreenPrevNextCharButtonHelpText, 0, 2); + ExportSection(props, L"Eta", Loc::pEtaString, 0, 1); + ExportSection(props, L"TrashItem", Loc::pTrashItemText, 0, 2); + ExportSection(props, L"MapError", Loc::pMapErrorString, 0, 50); + ExportSection(props, L"MapPlot", Loc::pMapPlotStrings, 0, 5); + ExportSection(props, L"Bullseye", Loc::pBullseyeStrings, 0, 5); + ExportSection(props, L"MiscMapScreenMouseRegionHelp", Loc::pMiscMapScreenMouseRegionHelpText, 0, 3); + ExportSection(props, L"MercHeLeave", Loc::pMercHeLeaveString, 0, 5); + ExportSection(props, L"MercSheLeave", Loc::pMercSheLeaveString, 0, 5); + ExportSection(props, L"MercContractOver", Loc::pMercContractOverStrings, 0, 5); + + ExportSection(props, L"ImpPopUp", Loc::pImpPopUpStrings, 0, 12); + ExportSection(props, L"ImpButton", Loc::pImpButtonText, 0, 26); + ExportSection(props, L"ExtraIMP", Loc::pExtraIMPStrings, 0, 4); + ExportSection(props, L"FilesTitle", Loc::pFilesTitle, 0, 1); + ExportSection(props, L"FilesSender", Loc::pFilesSenderList, 0, 7); + ExportSection(props, L"HistoryTitle", Loc::pHistoryTitle, 0, 1); + ExportSection(props, L"HistoryHeader", Loc::pHistoryHeaders, 0, 5); + ExportSection(props, L"History", Loc::pHistoryStrings, 0, TEXT_NUM_HISTORY); + ExportSection(props, L"HistoryLocation", Loc::pHistoryLocations, 0, 1); + ExportSection(props, L"LaptopIcon", Loc::pLaptopIcons, 0, 8); + + ExportSection(props, L"BookMark", Loc::pBookMarkStrings, 0, TEXT_NUM_LAPTOP_BOOKMARKS); + ExportSection(props, L"BookmarkTitle", Loc::pBookmarkTitle, 0, 2); + ExportSection(props, L"Download", Loc::pDownloadString, 0, 2); + ExportSection(props, L"AtmSideButton", Loc::gsAtmSideButtonText, 0, 5); + ExportSection(props, L"AtmStartButton", Loc::gsAtmStartButtonText, 0, 4); + ExportSection(props, L"ATM", Loc::sATMText, 0, 6); + ExportSection(props, L"Error", Loc::pErrorStrings, 0, 5); + ExportSection(props, L"Personnel", Loc::pPersonnelString, 0, 1); + ExportSection(props, L"WebTitle", Loc::pWebTitle, 0, 1); + ExportSection(props, L"WebPagesTitle", Loc::pWebPagesTitles, 0, 36); + + ExportSection(props, L"ShowBookmark", Loc::pShowBookmarkString, 0, 2); + ExportSection(props, L"LaptopTitle", Loc::pLaptopTitles, 0, 5); + ExportSection(props, L"PersonnelDepartedState", Loc::pPersonnelDepartedStateStrings, 0, TEXT_NUM_DEPARTED); + ExportSection(props, L"PersonelTeam", Loc::pPersonelTeamStrings, 0, 8); + ExportSection(props, L"PersonnelCurrentTeamStats", Loc::pPersonnelCurrentTeamStatsStrings, 0, 3); + ExportSection(props, L"PersonnelTeamStats", Loc::pPersonnelTeamStatsStrings, 0, 11); + ExportSection(props, L"MapVertIndex", Loc::pMapVertIndex, 0, 17); + ExportSection(props, L"MapHortIndex", Loc::pMapHortIndex, 0, 17); + ExportSection(props, L"MapDepthIndex", Loc::pMapDepthIndex, 0, 4); + ExportSection(props, L"ContractButton", Loc::pContractButtonString, 0, 1); + + ExportSection(props, L"UpdatePanelButton", Loc::pUpdatePanelButtons, 0, 2); + ExportSection(props, L"LargeTactical", Loc::LargeTacticalStr, 0, TEXT_NUM_LARGESTR); + ExportSection(props, L"InsContract", Loc::InsContractText, 0, TEXT_NUM_INS_CONTRACT); + ExportSection(props, L"InsInfo", Loc::InsInfoText, 0, TEXT_NUM_INS_INFO); + ExportSection(props, L"MercAccount", Loc::MercAccountText, 0, TEXT_NUM_MERC_ACCOUNT); + ExportSection(props, L"MercAccountPage", Loc::MercAccountPageText, 0, 2); + ExportSection(props, L"MercInfo", Loc::MercInfo, 0, TEXT_NUM_MERC_FILES); + ExportSection(props, L"MercNoAccount", Loc::MercNoAccountText, 0, TEXT_NUM_MERC_NO_ACC); + ExportSection(props, L"MercHomePage", Loc::MercHomePageText, 0, TEXT_NUM_MERC); + ExportSection(props, L"Funeral", Loc::sFuneralString, 0, TEXT_NUM_FUNERAL); + + ExportSection(props, L"Florist", Loc::sFloristText, 0, TEXT_NUM_FLORIST); + ExportSection(props, L"OrderForm", Loc::sOrderFormText, 0, TEXT_NUM_FLORIST_ORDER); + ExportSection(props, L"FloristGallery", Loc::sFloristGalleryText, 0, TEXT_NUM_FLORIST_GALLERY); + ExportSection(props, L"FloristCards", Loc::sFloristCards, 0, TEXT_NUM_FLORIST_CARDS); + ExportSection(props, L"BobbyROrderForm", Loc::BobbyROrderFormText, 0, TEXT_NUM_BOBBYR_MAILORDER); + ExportSection(props, L"BobbyRFilter", Loc::BobbyRFilter, 0, TEXT_NUM_BOBBYR_FILTER); + ExportSection(props, L"BobbyR", Loc::BobbyRText, 0, TEXT_NUM_BOBBYR_GUNS); + ExportSection(props, L"BobbyRaysFront", Loc::BobbyRaysFrontText, 0, TEXT_NUM_BOBBYR); + ExportSection(props, L"AimSort", Loc::AimSortText, 0, TEXT_NUM_AIM_SORT); + ExportSection(props, L"AimPolicy", Loc::AimPolicyText, 0, TEXT_NUM_AIM_POLICIES); + + ExportSection(props, L"AimMember", Loc::AimMemberText, 0, 4); + ExportSection(props, L"CharacterInfo", Loc::CharacterInfo, 0, TEXT_NUM_AIM_MEMBER_CHARINFO); + ExportSection(props, L"VideoConfercing", Loc::VideoConfercingText, 0, TEXT_NUM_AIM_MEMBER_VCONF); + ExportSection(props, L"AimPopUp", Loc::AimPopUpText, 0, TEXT_NUM_AIM_MEMBER_POPUP); + ExportSection(props, L"AimLink", Loc::AimLinkText, 0, TEXM_NUM_AIM_LINK); + ExportSection(props, L"AimHistory", Loc::AimHistoryText, 0, TEXT_NUM_AIM_HISTORY); + ExportSection(props, L"AimFi", Loc::AimFiText, 0, TEXT_NUM_AIM_FI); + ExportSection(props, L"AimAlumni", Loc::AimAlumniText, 0, TEXT_NUM_AIM_ALUMNI); + ExportSection(props, L"AimScreen", Loc::AimScreenText, 0, TEXT_NUM_AIM_SCREEN); + ExportSection(props, L"AimBottomMenu", Loc::AimBottomMenuText, 0, TEXT_NUM_AIM_MENU); + + ExportSection(props, L"SKI", Loc::SKI_Text, 0, TEXT_NUM_SKI_TEXT); + ExportSection(props, L"SkiAtm", Loc::SkiAtmText, 0, NUM_SKI_ATM_BUTTONS); + ExportSection(props, L"SkiAtmText", Loc::gzSkiAtmText, 0, TEXT_NUM_SKI_ATM_MODE_TEXT); + ExportSection(props, L"SkiMessageBox", Loc::SkiMessageBoxText, 0, TEXT_NUM_SKI_MBOX_TEXT); + ExportSection(props, L"Options", Loc::zOptionsText, 0, TEXT_NUM_OPT_TEXT); + ExportSection(props, L"SaveLoad", Loc::zSaveLoadText, 0, TEXT_NUM_SLG_TEXT); + ExportSection(props, L"MarksMapScreen", Loc::zMarksMapScreenText, 0, 25); + ExportSection(props, L"LandMarkInSector", Loc::pLandMarkInSectorString, 0, 1); + ExportSection(props, L"MilitiaConfirm", Loc::pMilitiaConfirmStrings, 0, 11); + ExportSection(props, L"MoneyWithdrawMessage", Loc::gzMoneyWithdrawMessageText, 0, TEXT_NUM_MONEY_WITHDRAW); + + ExportSection(props, L"Copyright", Loc::gzCopyrightText, 0, 1); + ExportSection(props, L"OptionsToggle", Loc::zOptionsToggleText, 0, 48); + ExportSection(props, L"OptionsScreenHelp", Loc::zOptionsScreenHelpText, 0, 48); + ExportSection(props, L"GIOScreen", Loc::gzGIOScreenText, 0, TEXT_NUM_GIO_TEXT); + ExportSection(props, L"MPJScreen", Loc::gzMPJScreenText, 0, TEXT_NUM_MPJ_TEXT); + ExportSection(props, L"MPJHelpText", Loc::gzMPJHelpText, 0, 10); + ExportSection(props, L"MPHScreen", Loc::gzMPHScreenText, 0, TEXT_NUM_MPH_TEXT); + ExportSection(props, L"DeliveryLocation", Loc::pDeliveryLocationStrings, 0, 17); + ExportSection(props, L"SkillAtZeroWarning", Loc::pSkillAtZeroWarning, 0, 1); + ExportSection(props, L"IMPBeginScreen", Loc::pIMPBeginScreenStrings, 0, 1); + ExportSection(props, L"IMPFinishButton", Loc::pIMPFinishButtonText, 0, 1); + + ExportSection(props, L"IMPFinish", Loc::pIMPFinishStrings, 0, 1); + ExportSection(props, L"IMPVoices", Loc::pIMPVoicesStrings, 0, 1); + ExportSection(props, L"DepartedMercPortrait", Loc::pDepartedMercPortraitStrings, 0, 3); + ExportSection(props, L"PersTitle", Loc::pPersTitleText, 0, 1); + ExportSection(props, L"PausedGame", Loc::pPausedGameText, 0, 3); + ExportSection(props, L"MessageStrings", Loc::pMessageStrings, 0, TEXT_NUM_MSG); + ExportSection(props, L"ItemPickupHelpPopup", Loc::ItemPickupHelpPopup, 0, 5); + ExportSection(props, L"DoctorWarning", Loc::pDoctorWarningString, 0, 2); + ExportSection(props, L"MilitiaButtonsHelp", Loc::pMilitiaButtonsHelpText, 0, 4); + ExportSection(props, L"MapScreenJustStartedHelp", Loc::pMapScreenJustStartedHelpText, 0, 2); + + ExportSection(props, L"AntiHacker", Loc::pAntiHackerString, 0, TEXT_NUM_ANTIHACKERSTR); + ExportSection(props, L"LaptopHelp", Loc::gzLaptopHelpText, 0, TEXT_NUM_LAPTOP_BN_BOOKMARK_TEXT); + ExportSection(props, L"HelpScreen", Loc::gzHelpScreenText, 0, TEXT_NUM_HLP); + ExportSection(props, L"NonPersistantPBI", Loc::gzNonPersistantPBIText, 0, 10); + ExportSection(props, L"MiscString", Loc::gzMiscString, 0, 5); + ExportSection(props, L"IntroScreen", Loc::gzIntroScreen, 0, 1); + ExportSection(props, L"NewNoise", Loc::pNewNoiseStr, 0, 11/*MAX_NOISES*/); + ExportSection(props, L"MapScreenSortButtonHelp", Loc::wMapScreenSortButtonHelpText, 0, 6); + ExportSection(props, L"BrokenLink", Loc::BrokenLinkText, 0, TEXT_NUM_BROKEN_LINK); + ExportSection(props, L"BobbyRShipment", Loc::gzBobbyRShipmentText, 0, TEXT_NUM_BOBBYR_SHIPMENT); + + ExportSection(props, L"CreditNames", Loc::gzCreditNames, 0, 15); + ExportSection(props, L"CreditNameTitle", Loc::gzCreditNameTitle, 0, 15); + ExportSection(props, L"CreditNameFunny", Loc::gzCreditNameFunny, 0, 15); + ExportSection(props, L"RepairsDone", Loc::sRepairsDoneString, 0, 7); + ExportSection(props, L"GioDifConfirm", Loc::zGioDifConfirmText, 0, TEXT_NUM_GIO_CFS); + ExportSection(props, L"LateLocalized", Loc::gzLateLocalizedString, 0, 64); + ExportSection(props, L"CWStrings", Loc::gzCWStrings, 0, 1); + ExportSection(props, L"TooltipStrings", Loc::gzTooltipStrings, 0, TEXT_NUM_STR_TT); + ExportSection(props, L"New113Message", Loc::New113Message, 0, TEXT_NUM_MSG113); + + ExportSection(props, L"New113HAMMessage", Loc::New113HAMMessage, 0, 22); + ExportSection(props, L"New113MERCMercMail", Loc::New113MERCMercMailTexts, 0, 4); + ExportSection(props, L"New113AIMMercMail", Loc::New113AIMMercMailTexts, 0, 16); + ExportSection(props, L"MissingIMPSkills", Loc::MissingIMPSkillsDescriptions, 0, 2); + ExportSection(props, L"NewInvMessage", Loc::NewInvMessage, 0, TEXT_NUM_NIV); + ExportSection(props, L"MPServerMessage", Loc::MPServerMessage, 0, 13); + ExportSection(props, L"MPClientMessage", Loc::MPClientMessage, 0, 69); + ExportSection(props, L"MPEdges", Loc::gszMPEdgesText, 0, 5); + ExportSection(props, L"MPTeamName", Loc::gszMPTeamNames, 0, 5); + ExportSection(props, L"MPMapscreen", Loc::gszMPMapscreenText, 0, 9); + + ExportSection(props, L"MPSScreen", Loc::gzMPSScreenText, 0, TEXT_NUM_MPS_TEXT); + ExportSection(props, L"MPCScreen", Loc::gzMPCScreenText, 0, TEXT_NUM_MPC_TEXT); + ExportSection(props, L"MPChatToggle", Loc::gzMPChatToggleText, 0, 2); + ExportSection(props, L"MPChatbox", Loc::gzMPChatboxText, 0, 2); + + props.writeToXMLFile(L"Localization/GameStrings.xml",tmap); + props.writeToIniFile(L"Localization/GameStrings.ini",true); + + Loc::ExportMercBio(); + Loc::ExportAIMHistory(); + Loc::ExportAIMPolicy(); + Loc::ExportAlumniName(); + Loc::ExportDialogues(); + Loc::ExportNPCDialogues(); + + return true; +} + +#include +#include "Encrypted File.h" + +namespace Loc +{ + wchar_t ToPolish(wchar_t siChar) + { + switch( siChar ) + { + case 165: siChar = 260; break; + case 198: siChar = 262; break; + case 202: siChar = 280; break; + case 163: siChar = 321; break; + case 209: siChar = 323; break; + case 211: siChar = 211; break; + + case 140: siChar = 346; break; + case 175: siChar = 379; break; + case 143: siChar = 377; break; + case 185: siChar = 261; break; + case 230: siChar = 263; break; + case 234: siChar = 281; break; + + case 179: siChar = 322; break; + case 241: siChar = 324; break; + case 243: siChar = 243; break; + case 156: siChar = 347; break; + case 191: siChar = 380; break; + case 159: siChar = 378; break; + } + return siChar; + } + + wchar_t ToRussian(wchar_t siChar) + { + switch( siChar ) + { + //capital letters + case 168: siChar = 1025; break; //U+0401 d0 81 CYRILLIC CAPITAL LETTER IO + case 192: siChar = 1040; break; //U+0410 A d0 90 CYRILLIC CAPITAL LETTER A + case 193: siChar = 1041; break; + case 194: siChar = 1042; break; + case 195: siChar = 1043; break; + case 196: siChar = 1044; break; + case 197: siChar = 1045; break; + case 198: siChar = 1046; break; + case 199: siChar = 1047; break; + case 200: siChar = 1048; break; + case 201: siChar = 1049; break; + case 202: siChar = 1050; break; + case 203: siChar = 1051; break; + case 204: siChar = 1052; break; + case 205: siChar = 1053; break; + case 206: siChar = 1054; break; + case 207: siChar = 1055; break; + case 208: siChar = 1056; break; + case 209: siChar = 1057; break; + case 210: siChar = 1058; break; + case 211: siChar = 1059; break; + case 212: siChar = 1060; break; + case 213: siChar = 1061; break; + case 214: siChar = 1062; break; + case 215: siChar = 1063; break; + case 216: siChar = 1064; break; + case 217: siChar = 1065; break; + case 218: siChar = 1066; break; + case 219: siChar = 1067; break; + case 220: siChar = 1068; break; + case 221: siChar = 1069; break; + case 222: siChar = 1070; break; + case 223: siChar = 1071; break; //U+042F d0 af CYRILLIC CAPITAL LETTER YA + + //small letters + case 185: siChar = 8470; break; // ¹ + case 178: siChar = 1030; break; // ² + case 161: siChar = 1038; break; // ¡ + case 179: siChar = 1110; break; // ³ + case 162: siChar = 1118; break; // ¢ + case 165: siChar = 1168; break; // ¥ + case 170: siChar = 1028; break; // ª + case 175: siChar = 1031; break; // ¯ + case 180: siChar = 1169; break; // ´ + case 186: siChar = 1108; break; // º + case 191: siChar = 1111; break; // ¿ + + case 184: siChar = 1105; break; //U+0451 d1 91 CYRILLIC SMALL LETTER IO + case 224: siChar = 1072; break; //U+0430 a d0 b0 CYRILLIC SMALL LETTER A + case 225: siChar = 1073; break; + case 226: siChar = 1074; break; + case 227: siChar = 1075; break; + case 228: siChar = 1076; break; + case 229: siChar = 1077; break; + case 230: siChar = 1078; break; + case 231: siChar = 1079; break; + case 232: siChar = 1080; break; + case 233: siChar = 1081; break; + case 234: siChar = 1082; break; + case 235: siChar = 1083; break; + case 236: siChar = 1084; break; + case 237: siChar = 1085; break; + case 238: siChar = 1086; break; + case 239: siChar = 1087; break; //U+043F d0 bf CYRILLIC SMALL LETTER PE + case 240: siChar = 1088; break; //U+0440 p d1 80 CYRILLIC SMALL LETTER ER + case 241: siChar = 1089; break; + case 242: siChar = 1090; break; + case 243: siChar = 1091; break; + case 244: siChar = 1092; break; + case 245: siChar = 1093; break; + case 246: siChar = 1094; break; + case 247: siChar = 1095; break; + case 248: siChar = 1096; break; + case 249: siChar = 1097; break; + case 250: siChar = 1098; break; + case 251: siChar = 1099; break; + case 252: siChar = 1100; break; + case 253: siChar = 1101; break; + case 254: siChar = 1102; break; + case 255: siChar = 1103; break; //U+044F d1 8f CYRILLIC SMALL LETTER YA + } + return siChar; + } + bool Translate(vfs::String::char_t* str, int len, Language lang) + { + if(lang == English || lang == German) + { + return true; + } + else if(lang == Russian) + { + for(int i=0; i(i), pInfoString); + + file.read((vfs::Byte*)pAddInfo, SIZE_MERC_ADDITIONAL_INFO); + DecodeString(pAddInfo, SIZE_MERC_ADDITIONAL_INFO); + Loc::Translate(pAddInfo, SIZE_MERC_ADDITIONAL_INFO, lang); + props.setStringProperty(L"Add", vfs::toString(i), pAddInfo); + } + props.writeToXMLFile(L"Localization/AimBiographies.xml", vfs::PropertyContainer::TagMap()); +} + +void Loc::ExportAIMHistory() +{ + Loc::Language lang = gs_Lang; + #define AIM_HISTORY_LINE_SIZE 400 * 2 + vfs::String::char_t pHistLine[AIM_HISTORY_LINE_SIZE]; + vfs::COpenReadFile rfile("BINARYDATA\\AimHist.edt"); + vfs::tReadableFile& file = rfile.file(); + + vfs::PropertyContainer props; + for(int i=0; i<23; ++i) + { + memset(pHistLine,0,AIM_HISTORY_LINE_SIZE*sizeof(wchar_t)); + // + file.read((vfs::Byte*)pHistLine, AIM_HISTORY_LINE_SIZE); + DecodeString(pHistLine,AIM_HISTORY_LINE_SIZE); + Loc::Translate(pHistLine, AIM_HISTORY_LINE_SIZE, lang); + props.setStringProperty(L"Line", vfs::toString(i), pHistLine); + } + props.writeToXMLFile(L"Localization/AimHistory.xml", vfs::PropertyContainer::TagMap()); +} + + +void Loc::ExportAIMPolicy() +{ + Loc::Language lang = gs_Lang; + #define AIM_HISTORY_LINE_SIZE 400 * 2 + vfs::String::char_t pPolLine[AIM_HISTORY_LINE_SIZE]; + vfs::COpenReadFile rfile("BINARYDATA\\AimPol.edt"); + vfs::tReadableFile& file = rfile.file(); + + vfs::PropertyContainer props; + for(int i=0; i<46; ++i) + { + memset(pPolLine,0,400*sizeof(wchar_t)); + // + file.read((vfs::Byte*)pPolLine, AIM_HISTORY_LINE_SIZE); + DecodeString(pPolLine,AIM_HISTORY_LINE_SIZE); + Loc::Translate(pPolLine, AIM_HISTORY_LINE_SIZE, lang); + props.setStringProperty(L"Line", vfs::toString(i), pPolLine); + } + props.writeToXMLFile(L"Localization/AimPolicy.xml", vfs::PropertyContainer::TagMap()); +} + +void Loc::ExportAlumniName() +{ + Loc::Language lang = gs_Lang; + #define AIM_ALUMNI_NAME_SIZE 80 * 2 + vfs::String::char_t pAlumniName[AIM_ALUMNI_NAME_SIZE]; + vfs::COpenReadFile rfile("BINARYDATA\\AlumName.edt"); + vfs::tReadableFile& file = rfile.file(); + + vfs::PropertyContainer props; + for(int i=0; i<51; ++i) + { + memset(pAlumniName,0,AIM_ALUMNI_NAME_SIZE*sizeof(wchar_t)); + // + file.read((vfs::Byte*)pAlumniName, AIM_ALUMNI_NAME_SIZE); + DecodeString(pAlumniName,AIM_ALUMNI_NAME_SIZE); + Loc::Translate(pAlumniName, AIM_ALUMNI_NAME_SIZE, lang); + props.setStringProperty(L"Line", vfs::toString(i), pAlumniName); + } + props.writeToXMLFile(L"Localization/AlumniName.xml", vfs::PropertyContainer::TagMap()); +} + +#include + +void Loc::ExportDialogues() +{ + Loc::Language lang = gs_Lang; + #define DIALOGUESIZE 480 + vfs::String::char_t pDiagLine[DIALOGUESIZE]; + + vfs::CVirtualFileSystem::Iterator it = getVFS()->begin(L"MercEdt/*.edt"); + for(; !it.end(); it.next()) + { + vfs::PropertyContainer props; + vfs::COpenReadFile rfile(it.value()); + vfs::tReadableFile& file = rfile.file(); + + std::wstringstream wss; + wss.str(file.getName().c_str()); + int id=0; + wss >> id; + + for(int i=0; i<200; ++i) + { + memset(pDiagLine,0,DIALOGUESIZE*sizeof(wchar_t)); + // + if(file.read((vfs::Byte*)pDiagLine, DIALOGUESIZE) > 0) + { + DecodeString(pDiagLine,DIALOGUESIZE); + Loc::Translate(pDiagLine, DIALOGUESIZE, lang); + if(wcslen(pDiagLine)) + { + props.setStringProperty(vfs::toString(id),vfs::toString(i), pDiagLine); + } + } + } + vfs::Path x(L"Localization/Dialogue"); + x += vfs::Path(file.getName().c_wcs() + L".xml"); + props.writeToXMLFile(x, vfs::PropertyContainer::TagMap()); + } +} + +void Loc::ExportNPCDialogues() +{ + Loc::Language lang = gs_Lang; + #define DIALOGUESIZE 480 + #define CIVQUOTESIZE 320 + vfs::String::char_t pDiagLine[DIALOGUESIZE]; + + vfs::CVirtualFileSystem::Iterator it = getVFS()->begin(L"npcdata/*.edt"); + for(; !it.end(); it.next()) + { + vfs::PropertyContainer props; + vfs::COpenReadFile rfile(it.value()); + vfs::tReadableFile& file = rfile.file(); + + vfs::String::str_t const& ws = file.getName().c_wcs(); + vfs::String::str_t::size_type pos = ws.find_first_of(L"."); + vfs::String id = ws.substr(0,pos); + + int SIZE; + if(vfs::matchPattern(L"civ*", id)) + { + SIZE = CIVQUOTESIZE; + } + else + { + SIZE = DIALOGUESIZE; + } + + for(int i=0; i<200; ++i) + { + memset(pDiagLine,0,DIALOGUESIZE*sizeof(wchar_t)); + // + if(file.read((vfs::Byte*)pDiagLine, SIZE) > 0) + { + DecodeString(pDiagLine,SIZE); + Loc::Translate(pDiagLine, SIZE, lang); + if(wcslen(pDiagLine)) + { + props.setStringProperty(id,vfs::toString(i), pDiagLine); + } + } + } + vfs::Path x(L"Localization/NpcDialogue"); + x += vfs::Path(file.getName().c_wcs() + L".xml"); + props.writeToXMLFile(x, vfs::PropertyContainer::TagMap()); + } +} diff --git a/Utils/ExportStrings.h b/Utils/ExportStrings.h new file mode 100644 index 00000000..f2156ed5 --- /dev/null +++ b/Utils/ExportStrings.h @@ -0,0 +1,9 @@ +#ifndef _EXPORTSTRINGS_H_ +#define _EXPORTSTRINGS_H_ + +namespace Loc +{ + bool ExportStrings(); +} + +#endif // _EXPORTSTRINGS_H_ \ No newline at end of file diff --git a/Utils/INIReader.cpp b/Utils/INIReader.cpp index 5ea92fb0..36656609 100644 --- a/Utils/INIReader.cpp +++ b/Utils/INIReader.cpp @@ -10,8 +10,11 @@ // Kaiden: INI reading function definitions: -#include "VFS/vfs.h" +#include +#ifdef USE_VFS +std::set CIniReader::m_merge_files; +#endif std::stack iniErrorMessages; template @@ -29,6 +32,13 @@ void PushErrorMessage(std::string const& filename, iniErrorMessages.push(errMessage.str()); } +#ifdef USE_VFS +void CIniReader::RegisterFileForMerging(vfs::Path const& filename) +{ + m_merge_files.insert(filename); +} +#endif + CIniReader::CIniReader(const STR8 szFileName) { memset(m_szFileName,0,sizeof(m_szFileName)); @@ -43,7 +53,26 @@ CIniReader::CIniReader(const STR8 szFileName) } #else strncpy(m_szFileName,szFileName, std::min(strlen(szFileName), sizeof(m_szFileName)-1)); - m_oProps.initFromIniFile(vfs::Path(szFileName)); + if(m_merge_files.find(szFileName) == m_merge_files.end()) + { + m_oProps.initFromIniFile(vfs::Path(szFileName)); + } + else + { + vfs::CProfileStack* profs = getVFS()->getProfileStack(); + vfs::CProfileStack::Iterator it = profs->begin(); + std::stack rev_order; + for(; !it.end(); it.next()) { rev_order.push(it.value()); } + while(!rev_order.empty()) + { + vfs::IBaseFile* file = rev_order.top()->getFile(szFileName); + if(file) + { + m_oProps.initFromIniFile(vfs::tReadableFile::cast(file)); + } + rev_order.pop(); + } + } #endif } @@ -79,7 +108,28 @@ CIniReader::CIniReader(const STR8 szFileName, BOOLEAN Force_Custom_Data_Path) } #else strncpy(m_szFileName,szFileName, std::min(strlen(szFileName), sizeof(m_szFileName)-1)); - CIniReader_File_Found = m_oProps.initFromIniFile(vfs::Path(szFileName)); + if(m_merge_files.find(szFileName) == m_merge_files.end()) + { + CIniReader_File_Found = m_oProps.initFromIniFile(vfs::Path(szFileName)); + } + else + { + CIniReader_File_Found = TRUE; + vfs::CProfileStack* profs = getVFS()->getProfileStack(); + vfs::CProfileStack::Iterator it = profs->begin(); + std::stack rev_order; + for(; !it.end(); it.next()) { rev_order.push(it.value()); } + while(!rev_order.empty()) + { + vfs::IBaseFile* file = rev_order.top()->getFile(szFileName); + if(file) + { + CIniReader_File_Found = ((CIniReader_File_Found != FALSE) && m_oProps.initFromIniFile(vfs::tReadableFile::cast(file))) ? TRUE : FALSE; + } + rev_order.pop(); + } + } + #endif } @@ -99,7 +149,7 @@ int CIniReader::ReadInteger(const STR8 szSection, const STR8 szKey, int iDefault #ifndef USE_VFS return GetPrivateProfileInt(szSection, szKey, iDefaultValue, m_szFileName); #else - return m_oProps.getIntProperty(szSection, szKey, iDefaultValue); + return (int)(m_oProps.getIntProperty(szSection, szKey, iDefaultValue)); #endif } @@ -107,9 +157,9 @@ int CIniReader::ReadInteger(const STR8 szSection, const STR8 szKey, int iDefault int CIniReader::ReadInteger(const STR8 szSection, const STR8 szKey, int defaultValue, int minValue, int maxValue) { #ifndef USE_VFS - int iniValueReadFromFile = GetPrivateProfileInt(szSection, szKey, defaultValue, m_szFileName); + int iniValueReadFromFile = (int)(GetPrivateProfileInt(szSection, szKey, defaultValue, m_szFileName)); #else - int iniValueReadFromFile = m_oProps.getIntProperty(szSection, szKey, defaultValue); + int iniValueReadFromFile = (int)(m_oProps.getIntProperty(szSection, szKey, defaultValue)); #endif //AssertGE(iniValueReadFromFile, minValue); //AssertLE(iniValueReadFromFile, maxValue); @@ -195,7 +245,7 @@ FLOAT CIniReader::ReadFloat(const STR8 szSection, const STR8 szKey, FLOAT defaul return iniValueReadFromFile; } -BOOLEAN CIniReader::ReadBoolean(const STR8 szSection, const STR8 szKey, bool defaultValue) +BOOLEAN CIniReader::ReadBoolean(const STR8 szSection, const STR8 szKey, bool defaultValue, bool bolDisplayError) { #ifndef USE_VFS char szResult[255]; @@ -209,12 +259,12 @@ BOOLEAN CIniReader::ReadBoolean(const STR8 szSection, const STR8 szKey, bool def else if (strcmp(szResult, "FALSE") == 0) return FALSE; #else - utf8string str = m_oProps.getStringProperty(szSection, szKey, L""); - if( StrCmp::Equal(str, L"true") ) + vfs::String str = m_oProps.getStringProperty(szSection, szKey, L""); + if( vfs::StrCmp::Equal(str, L"true") ) { return TRUE; } - else if( StrCmp::Equal(str, L"false") ) + else if( vfs::StrCmp::Equal(str, L"false") ) { return FALSE; } @@ -222,10 +272,12 @@ BOOLEAN CIniReader::ReadBoolean(const STR8 szSection, const STR8 szKey, bool def char szDefault[255]; sprintf(szDefault, "%s", defaultValue? "TRUE" : "FALSE"); #endif - std::stringstream errMessage; - errMessage << "The value [" << szSection << "][" << szKey << "] = \"" << szResult << "\" " - << "in file [" << this->m_szFileName << "] is neither TRUE nor FALSE. The value " << szDefault << " will be used."; - iniErrorMessages.push(errMessage.str()); + if(bolDisplayError){ + std::stringstream errMessage; + errMessage << "The value [" << szSection << "][" << szKey << "] = \"" << szResult << "\" " + << "in file [" << this->m_szFileName << "] is neither TRUE nor FALSE. The value " << szDefault << " will be used."; + iniErrorMessages.push(errMessage.str()); + } return defaultValue; } diff --git a/Utils/INIReader.h b/Utils/INIReader.h index c53e9bba..0b586b08 100644 --- a/Utils/INIReader.h +++ b/Utils/INIReader.h @@ -6,7 +6,7 @@ #include #include -#include "VFS/PropertyContainer.h" +#include // Kaiden: This will read any value out of // an INI file as long as the correct type is specified. @@ -42,7 +42,7 @@ public: DOUBLE ReadDouble(const STR8 szSection, const STR8 szKey, DOUBLE defaultValue, DOUBLE minValue, DOUBLE maxValue); FLOAT ReadFloat (const STR8 szSection, const STR8 szKey, FLOAT defaultValue, FLOAT minValue, FLOAT maxValue); - BOOLEAN ReadBoolean(const STR8 szSection, const STR8 szKey, bool bolDefaultValue); + BOOLEAN ReadBoolean(const STR8 szSection, const STR8 szKey, bool bolDefaultValue, bool bolDisplayError = true); void ReadString(const STR8 szSection, const STR8 szKey, const STR8 szDefaultValue, STR8 input_buffer, size_t buffer_size); @@ -51,13 +51,19 @@ public: BOOLEAN Is_CIniReader_File_Found(void) {return (CIniReader_File_Found);} void Clear(); + +#ifdef USE_VFS + static void RegisterFileForMerging(vfs::Path const& filename); +#endif private: - CPropertyContainer m_oProps; + vfs::PropertyContainer m_oProps; char m_szFileName[MAX_PATH]; BOOLEAN CIniReader_File_Found; UINT32 ReadUINT(const STR8 szSection, const STR8 szKey, UINT32 defaultValue, UINT32 minValue, UINT32 maxValue); - +#ifdef USE_VFS + static std::set m_merge_files; +#endif }; #endif//INIREADER_H \ No newline at end of file diff --git a/Utils/ImportStrings.cpp b/Utils/ImportStrings.cpp new file mode 100644 index 00000000..1d4131c4 --- /dev/null +++ b/Utils/ImportStrings.cpp @@ -0,0 +1,38 @@ +#include "ImportStrings.h" +#include "LocalizedStrings.h" +#include "Language Defines.h" + +#include +#include + +#include + +void Loc::ImportStrings() +{ + Loc::AssociateWithFile(Loc::AIM_BIOGRAPHY, L"Localization/AimBiographies.xml"); + Loc::AssociateWithFile(Loc::AIM_HISTORY, L"Localization/AimHistory.xml"); + Loc::AssociateWithFile(Loc::AIM_POLICY, L"Localization/AimPolicy.xml"); + Loc::AssociateWithFile(Loc::GAME_STRINGS, L"Localization/GameStrings.xml"); + + vfs::String bio, add, bio2; + Loc::GetString(Loc::AIM_BIOGRAPHY,L"Bio",L"0",add); + Loc::GetString(Loc::AIM_BIOGRAPHY,L"Add",L"10",bio); + Loc::GetString(Loc::AIM_BIOGRAPHY,L"Bio",23,bio2); + + for(int i=0; i<200; ++i) + { + std::wstringstream wss; + for(int exp=2; exp>=0; --exp) + { + int t = (int)std::pow((double)10,(double)exp); + wss << (i % (t*10)) / t; + } + vfs::String s = wss.str() + L".EDT.xml"; + vfs::Path filename(L"Localization/Dialogue"); + filename += vfs::Path(s); + if(getVFS()->fileExists(filename)) + { + Loc::AssociateWithFile(Loc::DIALOGUE,filename,vfs::toString(i)); + } + } +} diff --git a/Utils/ImportStrings.h b/Utils/ImportStrings.h new file mode 100644 index 00000000..30bd0b78 --- /dev/null +++ b/Utils/ImportStrings.h @@ -0,0 +1,9 @@ +#ifndef _IMPORTSTRINGS_H_ +#define _IMPORTSTRINGS_H_ + +namespace Loc +{ + void ImportStrings(); +} + +#endif // _IMPORTSTRINGS_H_ diff --git a/Utils/LocalizedStrings.cpp b/Utils/LocalizedStrings.cpp new file mode 100644 index 00000000..62153401 --- /dev/null +++ b/Utils/LocalizedStrings.cpp @@ -0,0 +1,127 @@ +#include "LocalizedStrings.h" + +#include +#include + +bool g_bUseXML_Strings = false; + +namespace Loc +{ + void Init(Topic t, vfs::String const& section); + void Clear(Topic t); + void ClearAll(); + + class _Strings + { + public: + _Strings() : initialized(false) {}; + bool initialized; + vfs::PropertyContainer stringMap; + }; + class _PropState + { + public: + _PropState() : loaded(false) {}; + bool loaded; + vfs::Path filename; + }; + + typedef std::map tSectionState; + + static std::map _localizedStrings; + static std::map _topicFiles; +}; + + + +bool Loc::AssociateWithFile(Loc::Topic t, vfs::Path const& sFilename) +{ + _topicFiles[t][L"_ALL"].filename = sFilename; + _topicFiles[t][L"_ALL"].loaded = false; + return true; +} + +bool Loc::AssociateWithFile(Topic t, vfs::Path const& sFilename, vfs::String const& section) +{ + _topicFiles[t][section].filename = sFilename; + _topicFiles[t][section].loaded = false; + return false; +} + + +bool Loc::GetString(Loc::Topic t, vfs::String const& section, vfs::String const& key, vfs::String& value) +{ + Init(t,section); + return _localizedStrings[t].getStringProperty(section, key, value); +} +bool Loc::GetString(Loc::Topic t, vfs::String const& section, int key, vfs::String& value) +{ + return GetString(t, section, vfs::toString(key), value); +} + +bool Loc::GetString(Topic t, vfs::String const& section, vfs::String const& key, vfs::String::char_t* value, vfs::UInt32 len) +{ + Init(t,section); + return _localizedStrings[t].getStringProperty(section, key, value, len); +} +bool Loc::GetString(Topic t, vfs::String const& section, int key, vfs::String::char_t* value, vfs::UInt32 len) +{ + return GetString(t, section, vfs::toString(key), value, len); +} + +vfs::String const& Loc::GetString(Topic t, vfs::String const& section, vfs::String const& key) +{ + Init(t,section); + return _localizedStrings[t].getStringProperty(section, key); +} +vfs::String const& Loc::GetString(Topic t, vfs::String const& section, int key) +{ + return GetString(t,section,vfs::toString(key)); +} + + + +void Loc::Init(Topic t, vfs::String const& section) +{ + _PropState& state = _topicFiles[t][L"_ALL"]; + if(!state.filename.empty() && !state.loaded) + { + _localizedStrings[t].initFromXMLFile(state.filename, vfs::PropertyContainer::TagMap()); + state.loaded = true; + } + state = _topicFiles[t][section]; + if(!state.filename.empty() && !state.loaded) + { + _localizedStrings[t].initFromXMLFile(state.filename, vfs::PropertyContainer::TagMap()); + state.loaded = true; + } +} + +void Loc::Clear(Topic t) +{ + _localizedStrings[t].clearContainer(); + tSectionState::iterator it = _topicFiles[t].begin(); + for(; it != _topicFiles[t].end(); ++it) + { + it->second.loaded = false; + } + +} + +void Loc::ClearAll() +{ + std::map::iterator sit = _topicFiles.begin(); + for(; sit != _topicFiles.end(); ++sit) + { + tSectionState::iterator it = sit->second.begin(); + for(; it != sit->second.end(); ++it) + { + it->second.loaded = false; + } + } + _localizedStrings.clear(); +} + + + + diff --git a/Utils/LocalizedStrings.h b/Utils/LocalizedStrings.h new file mode 100644 index 00000000..5e10f80e --- /dev/null +++ b/Utils/LocalizedStrings.h @@ -0,0 +1,59 @@ +#ifndef _LOCALIZEDSTRINGS_H_ +#define _LOCALIZEDSTRINGS_H_ + +#include + +//#define USE_LOCALIZATION + +namespace Loc +{ + enum Language + { + Chinese, + Dutch, + English, + French, + German, + Italian, + Polish, + Russian, + Taiwanese, + }; + + static const wchar_t* LangSuffix [] = { + L"_cn", + L"_nl", + L"_en", + L"_fr", + L"_de", + L"_it", + L"_pl", + L"_ru", + L"_tw", + }; + + enum Topic + { + AIM_BIOGRAPHY, + AIM_HISTORY, + AIM_POLICY, + GAME_STRINGS, + DIALOGUE, + }; + + bool AssociateWithFile(Topic t, vfs::Path const& sFilename); + bool AssociateWithFile(Topic t, vfs::Path const& sFilename, vfs::String const& section); + + bool GetString(Topic t, vfs::String const& section, vfs::String const& key, vfs::String& value); + bool GetString(Topic t, vfs::String const& section, int key, vfs::String& value); + + bool GetString(Topic t, vfs::String const& section, vfs::String const& key, vfs::String::char_t* value, vfs::UInt32 len); + bool GetString(Topic t, vfs::String const& section, int key, vfs::String::char_t* value, vfs::UInt32 len); + + vfs::String const& GetString(Topic t, vfs::String const& section, vfs::String const& key); + vfs::String const& GetString(Topic t, vfs::String const& section, int key); +}; + +extern bool g_bUseXML_Strings; + +#endif // _LOCALIZEDSTRINGS_H_ diff --git a/Utils/Multi Language Graphic Utils.cpp b/Utils/Multi Language Graphic Utils.cpp index e2847f8c..d38408a6 100644 --- a/Utils/Multi Language Graphic Utils.cpp +++ b/Utils/Multi Language Graphic Utils.cpp @@ -20,6 +20,9 @@ BOOLEAN GetMLGFilename( SGPFILENAME filename, UINT16 usMLGGraphicID ) case MLG_AIMSYMBOL: sprintf( filename, "LAPTOP\\AimSymbol.sti" ); return TRUE; + case MLG_AIMSYMBOL_SMALL: + sprintf( filename, "LAPTOP\\AimSymbol_Small.sti" ); + return TRUE; case MLG_BOBBYNAME: sprintf( filename, "LAPTOP\\BobbyName.sti" ); return TRUE; @@ -138,6 +141,10 @@ BOOLEAN GetMLGFilename( SGPFILENAME filename, UINT16 usMLGGraphicID ) //Same graphic (no translation needed) sprintf( filename, "LAPTOP\\AimSymbol.sti" ); return TRUE; + case MLG_AIMSYMBOL_SMALL: + //Same graphic (no translation needed) + sprintf( filename, "LAPTOP\\AimSymbol_Small.sti" ); + return TRUE; case MLG_BOBBYNAME: //Same graphic (no translation needed) sprintf( filename, "LAPTOP\\BobbyName.sti" ); @@ -298,6 +305,9 @@ BOOLEAN GetMLGFilename( SGPFILENAME filename, UINT16 usMLGGraphicID ) case MLG_AIMSYMBOL: sprintf( filename, "%s\\AimSymbol_%s.sti", zLanguage, zLanguage ); break; + case MLG_AIMSYMBOL_SMALL: + sprintf( filename, "%s\\AimSymbol_Small_%s.sti", zLanguage, zLanguage ); + break; case MLG_BOBBYNAME: sprintf( filename, "%s\\BobbyName_%s.sti", zLanguage, zLanguage ); break; @@ -419,6 +429,9 @@ BOOLEAN GetMLGFilename( SGPFILENAME filename, UINT16 usMLGGraphicID ) case MLG_AIMSYMBOL: sprintf( filename, "LAPTOP\\AimSymbol.sti" ); return TRUE; + case MLG_AIMSYMBOL_SMALL: + sprintf( filename, "LAPTOP\\AimSymbol_Small.sti" ); + return TRUE; case MLG_BOBBYNAME: sprintf( filename, "LAPTOP\\BobbyName.sti" ); return TRUE; diff --git a/Utils/Multi Language Graphic Utils.h b/Utils/Multi Language Graphic Utils.h index 4270d466..13ffb918 100644 --- a/Utils/Multi Language Graphic Utils.h +++ b/Utils/Multi Language Graphic Utils.h @@ -4,6 +4,7 @@ enum { MLG_AIMSYMBOL, + MLG_AIMSYMBOL_SMALL, MLG_BOBBYNAME, MLG_BOBBYRAYAD21, MLG_BOBBYRAYLINK, diff --git a/Utils/Music Control.cpp b/Utils/Music Control.cpp index 5727f929..2e47dd3b 100644 --- a/Utils/Music Control.cpp +++ b/Utils/Music Control.cpp @@ -14,27 +14,36 @@ #include "fade screen.h" #endif -extern int iScreenMode; +//extern int iScreenMode; -UINT32 uiMusicHandle=NO_SAMPLE; -UINT32 uiMusicVolume=50; -BOOLEAN fMusicPlaying=FALSE; -BOOLEAN fMusicFadingOut=FALSE; -BOOLEAN fMusicFadingIn=FALSE; +static UINT32 uiMusicHandle = NO_SAMPLE; +static BOOLEAN fMusicPlaying = FALSE; -BOOLEAN gfMusicEnded = FALSE; +static BOOLEAN fMusicFadingOut = FALSE; +static BOOLEAN fMusicFadingIn = FALSE; +static UINT32 uiMusicVolume = 50; -UINT8 gubMusicMode = 0; -UINT8 gubOldMusicMode = 0; +static BOOLEAN gfMusicEnded = FALSE; -INT8 gbVictorySongCount = 0; -INT8 gbDeathSongCount = 0; +static UINT8 gubMusicMode = 0; -INT8 bNothingModeSong; -INT8 bEnemyModeSong; -INT8 bBattleModeSong; +static UINT8 gubOldMusicMode = 0; + +static INT8 gbVictorySongCount = 0; +static INT8 gbDeathSongCount = 0; + +static INT8 bNothingModeSong; +static INT8 bEnemyModeSong; +static INT8 bBattleModeSong; + +static BOOLEAN gfUseCreatureMusic = FALSE; + +static INT8 gbFadeSpeed = 1; + +static BOOLEAN gfDontRestartSong = FALSE; +// unused +//BOOLEAN gfForceMusicToTense = FALSE; -INT8 gbFadeSpeed = 1; CHAR8 *szMusicList[NUM_MUSIC]= { @@ -55,39 +64,40 @@ CHAR8 *szMusicList[NUM_MUSIC]= "MUSIC\\creature battle.wav", }; -BOOLEAN gfForceMusicToTense = FALSE; -BOOLEAN gfDontRestartSong = FALSE; +BOOLEAN StartMusicBasedOnMode(void); +void DoneFadeOutDueToEndMusic(void); +void MusicStopCallback(void *pData); +BOOLEAN MusicStop(void); +BOOLEAN MusicFadeOut(void); +BOOLEAN MusicFadeIn(void); -BOOLEAN StartMusicBasedOnMode( ); -void DoneFadeOutDueToEndMusic( void ); -extern void HandleEndDemoInCreatureLevel( ); +//extern void HandleEndDemoInCreatureLevel( ); + +//BOOLEAN NoEnemiesInSight( ) +//{ +// SOLDIERTYPE *pSoldier; +// INT32 cnt; +// +// // Loop through our guys +// // End the turn of player charactors +// cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; +// +// // look for all mercs on the same team, +// for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++, pSoldier++ ) +// { +// if ( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE ) +// { +// if ( pSoldier->aiData.bOppCnt != 0 ) +// { +// return( FALSE ); +// } +// } +// } +// +// return( TRUE ); +//} -BOOLEAN NoEnemiesInSight( ) -{ - SOLDIERTYPE *pSoldier; - INT32 cnt; - - // Loop through our guys - // End the turn of player charactors - cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; - - // look for all mercs on the same team, - for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++, pSoldier++ ) - { - if ( pSoldier->bActive && pSoldier->stats.bLife >= OKLIFE ) - { - if ( pSoldier->aiData.bOppCnt != 0 ) - { - return( FALSE ); - } - } - } - - return( TRUE ); -} - -void MusicStopCallback( void *pData ); //******************************************************************************** // MusicPlay @@ -109,28 +119,28 @@ BOOLEAN MusicPlay(UINT32 uiNum) MusicStop(); memset(&spParms, 0xff, sizeof(SOUNDPARMS)); - spParms.uiPriority=PRIORITY_MAX; - spParms.uiVolume=0; - spParms.uiLoop=1; // Lesh: only 1 line added + spParms.uiPriority = PRIORITY_MAX; + spParms.uiVolume = 0; + spParms.uiLoop = 1; // Lesh: only 1 line added spParms.EOSCallback = MusicStopCallback; //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "About to call SoundPlayStreamedFile" ); - uiMusicHandle=SoundPlayStreamedFile(szMusicList[uiNum], &spParms); + uiMusicHandle = SoundPlayStreamedFile(szMusicList[uiNum], &spParms); - if(uiMusicHandle!=SOUND_ERROR) + if(uiMusicHandle != SOUND_ERROR) { //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Music PLay %d %d", uiMusicHandle, gubMusicMode ) ); - gfMusicEnded = FALSE; - fMusicPlaying=TRUE; + gfMusicEnded = FALSE; + fMusicPlaying = TRUE; MusicFadeIn(); - return(TRUE); + return TRUE; } //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Music PLay %d %d", uiMusicHandle, gubMusicMode ) ); - return(FALSE); + return FALSE; } //******************************************************************************** @@ -149,32 +159,31 @@ BOOLEAN MusicSetVolume(UINT32 uiVolume) //if( 1==iScreenMode ) /* on Windowed mode, skip the music? was coded for WINDOWED_MODE that way...*/ //return FALSE; + uiMusicVolume = __min(uiVolume, 127); - uiMusicVolume=__min(uiVolume, 127); - - if(uiMusicHandle!=NO_SAMPLE) + if(uiMusicHandle != NO_SAMPLE) { - // get volume and if 0 stop music! - if ( uiMusicVolume == 0 ) - { - gfDontRestartSong = TRUE; - MusicStop( ); - return( TRUE ); - } + // get volume and if 0 stop music! + if (uiMusicVolume == 0) + { + gfDontRestartSong = TRUE; + MusicStop(); + return TRUE; + } SoundSetVolume(uiMusicHandle, uiMusicVolume); - return(TRUE); + return TRUE; } // If here, check if we need to re-start music // Have we re-started? - if ( uiMusicVolume > 0 && uiOldMusicVolume == 0 ) + if (uiMusicVolume > 0 && uiOldMusicVolume == 0) { - StartMusicBasedOnMode( ); + StartMusicBasedOnMode(); } - return(FALSE); + return FALSE; } //******************************************************************************** @@ -187,7 +196,7 @@ BOOLEAN MusicSetVolume(UINT32 uiVolume) //******************************************************************************** UINT32 MusicGetVolume(void) { - return(uiMusicVolume); + return uiMusicVolume; } //******************************************************************************** @@ -198,25 +207,24 @@ UINT32 MusicGetVolume(void) // Returns: TRUE if the music was stopped, FALSE if an error occurred // //******************************************************************************** -BOOLEAN MusicStop(void) +static BOOLEAN MusicStop(void) { // WANNE: We want music in windowed mode //if( 1==iScreenMode ) /* on Windowed mode, skip the music? was coded for WINDOWED_MODE that way...*/ // return(FALSE); - - if(uiMusicHandle!=NO_SAMPLE) + if(uiMusicHandle != NO_SAMPLE) { //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Music Stop %d %d", uiMusicHandle, gubMusicMode ) ); SoundStop(uiMusicHandle); - fMusicPlaying=FALSE; + fMusicPlaying = FALSE; uiMusicHandle = NO_SAMPLE; - return(TRUE); + return TRUE; } //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Music Stop %d %d", uiMusicHandle, gubMusicMode ) ); - return(FALSE); + return FALSE; } //******************************************************************************** @@ -227,14 +235,14 @@ BOOLEAN MusicStop(void) // Returns: TRUE if the music has begun fading, FALSE if an error occurred // //******************************************************************************** -BOOLEAN MusicFadeOut(void) +static BOOLEAN MusicFadeOut(void) { - if(uiMusicHandle!=NO_SAMPLE) + if(uiMusicHandle != NO_SAMPLE) { - fMusicFadingOut=TRUE; - return(TRUE); + fMusicFadingOut = TRUE; + return TRUE; } - return(FALSE); + return FALSE; } //******************************************************************************** @@ -245,14 +253,14 @@ BOOLEAN MusicFadeOut(void) // Returns: TRUE if the music has begun fading in, FALSE if an error occurred // //******************************************************************************** -BOOLEAN MusicFadeIn(void) +static BOOLEAN MusicFadeIn(void) { - if(uiMusicHandle!=NO_SAMPLE) + if(uiMusicHandle != NO_SAMPLE) { - fMusicFadingIn=TRUE; - return(TRUE); + fMusicFadingIn = TRUE; + return TRUE; } - return(FALSE); + return FALSE; } //******************************************************************************** @@ -264,7 +272,7 @@ BOOLEAN MusicFadeIn(void) // Returns: TRUE always // //******************************************************************************** -BOOLEAN MusicPoll( BOOLEAN fForce ) +BOOLEAN MusicPoll(BOOLEAN /*fForce*/) { //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll"); @@ -281,99 +289,96 @@ BOOLEAN MusicPoll( BOOLEAN fForce ) //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: Handle Sound every sound overhead time"); // Handle Sound every sound overhead time.... - if ( COUNTERDONE( MUSICOVERHEAD ) ) + if (COUNTERDONE(MUSICOVERHEAD)) { - //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: Reset counter"); + //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: Reset counter"); // Reset counter - RESETCOUNTER( MUSICOVERHEAD ); + RESETCOUNTER(MUSICOVERHEAD); - if(fMusicFadingIn) + if (fMusicFadingIn) { //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: music fading in"); - if(uiMusicHandle!=NO_SAMPLE) + if(uiMusicHandle != NO_SAMPLE) { - iVol=SoundGetVolume(uiMusicHandle); - iVol=__min( (INT32)uiMusicVolume, iVol+gbFadeSpeed ); + iVol = SoundGetVolume(uiMusicHandle); + iVol = __min( (INT32)uiMusicVolume, iVol+gbFadeSpeed ); SoundSetVolume(uiMusicHandle, iVol); - if(iVol==(INT32)uiMusicVolume) + if(iVol == (INT32)uiMusicVolume) { - fMusicFadingIn=FALSE; + fMusicFadingIn = FALSE; gbFadeSpeed = 1; } } } - else if(fMusicFadingOut) + else if (fMusicFadingOut) { //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: music fading out"); - if(uiMusicHandle!=NO_SAMPLE) + if(uiMusicHandle != NO_SAMPLE) { - iVol=SoundGetVolume(uiMusicHandle); - iVol=(iVol >=1)? iVol-gbFadeSpeed : 0; + iVol = SoundGetVolume(uiMusicHandle); + iVol = (iVol >=1)? iVol-gbFadeSpeed : 0; - iVol=__max( (INT32)iVol, 0 ); + iVol = __max( (INT32)iVol, 0 ); SoundSetVolume(uiMusicHandle, iVol); - if(iVol==0) + if(iVol == 0) { MusicStop(); - fMusicFadingOut=FALSE; + fMusicFadingOut = FALSE; gbFadeSpeed = 1; } } } - //#endif - - if ( gfMusicEnded ) + if (gfMusicEnded) { //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: music ended"); // OK, based on our music mode, play another! //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Music End Loop %d %d", uiMusicHandle, gubMusicMode ) ); // If we were in victory mode, change! - if ( gbVictorySongCount == 1 || gbDeathSongCount == 1 ) + if (gbVictorySongCount == 1 || gbDeathSongCount == 1) { - if ( gbDeathSongCount == 1 && guiCurrentScreen == GAME_SCREEN ) + if (gbDeathSongCount == 1 && guiCurrentScreen == GAME_SCREEN) { CheckAndHandleUnloadingOfCurrentWorld(); } - if ( gbVictorySongCount == 1 ) + if (gbVictorySongCount == 1) { - SetMusicMode( MUSIC_TACTICAL_NOTHING ); + SetMusicMode(MUSIC_TACTICAL_NOTHING); } } else { - if ( !gfDontRestartSong ) + if (!gfDontRestartSong) { //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll: don't restart song, StartMusicBasedOnMode"); - StartMusicBasedOnMode( ); + StartMusicBasedOnMode(); } } gfMusicEnded = FALSE; - gfDontRestartSong = FALSE; + gfDontRestartSong = FALSE; } } //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"MusicPoll done"); - return(TRUE); + return TRUE; } -BOOLEAN SetMusicMode( UINT8 ubMusicMode ) +static BOOLEAN SetMusicMode(UINT8 ubMusicMode, BOOLEAN fForce) { static INT8 bPreviousMode = 0; - // OK, check if we want to restore - if ( ubMusicMode == MUSIC_RESTORE ) + if (ubMusicMode == MUSIC_RESTORE) { - if ( bPreviousMode == MUSIC_TACTICAL_VICTORY || bPreviousMode == MUSIC_TACTICAL_DEATH ) - { - bPreviousMode = MUSIC_TACTICAL_NOTHING; - } + if (bPreviousMode == MUSIC_TACTICAL_VICTORY || bPreviousMode == MUSIC_TACTICAL_DEATH) + { + bPreviousMode = MUSIC_TACTICAL_NOTHING; + } ubMusicMode = bPreviousMode; } @@ -384,7 +389,7 @@ BOOLEAN SetMusicMode( UINT8 ubMusicMode ) } // if different, start a new music song - if ( gubOldMusicMode != ubMusicMode ) + if (fForce || gubOldMusicMode != ubMusicMode) { // Set mode.... gubMusicMode = ubMusicMode; @@ -394,108 +399,106 @@ BOOLEAN SetMusicMode( UINT8 ubMusicMode ) gbVictorySongCount = 0; gbDeathSongCount = 0; - if(uiMusicHandle!=NO_SAMPLE ) + if(uiMusicHandle != NO_SAMPLE) { // Fade out old music - MusicFadeOut( ); + MusicFadeOut(); } else { // Change music! - StartMusicBasedOnMode( ); + StartMusicBasedOnMode(); } - } + gubOldMusicMode = gubMusicMode; - return( TRUE ); + return TRUE; } -BOOLEAN StartMusicBasedOnMode( ) +static BOOLEAN StartMusicBasedOnMode(void) { static BOOLEAN fFirstTime = TRUE; - if ( fFirstTime ) + if (fFirstTime) { fFirstTime = FALSE; - bNothingModeSong = (INT8) (NOTHING_A_MUSIC + Random( 4 )); - - bEnemyModeSong = (INT8) (TENSOR_A_MUSIC + Random( 3 )); - - bBattleModeSong = (INT8) (BATTLE_A_MUSIC + Random( 2 )); - + bNothingModeSong = (INT8) (NOTHING_A_MUSIC + Random(4)); + bEnemyModeSong = (INT8) (TENSOR_A_MUSIC + Random(3)); + bBattleModeSong = (INT8) (BATTLE_A_MUSIC + Random(2)); } //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "StartMusicBasedOnMode() %d %d", uiMusicHandle, gubMusicMode ) ); // Setup a song based on mode we're in! - switch( gubMusicMode ) + switch(gubMusicMode) { case MUSIC_MAIN_MENU: // ATE: Don't fade in gbFadeSpeed = (INT8)uiMusicVolume; - MusicPlay( MENUMIX_MUSIC ); + MusicPlay(MENUMIX_MUSIC); break; case MUSIC_LAPTOP: gbFadeSpeed = (INT8)uiMusicVolume; - MusicPlay( MARIMBAD2_MUSIC ); + MusicPlay(MARIMBAD2_MUSIC); break; case MUSIC_TACTICAL_NOTHING: // ATE: Don't fade in gbFadeSpeed = (INT8)uiMusicVolume; - if( gfUseCreatureMusic ) + if(gfUseCreatureMusic) { - MusicPlay( CREEPY_MUSIC ); + MusicPlay(CREEPY_MUSIC); } else { - MusicPlay( bNothingModeSong ); - bNothingModeSong = (INT8) (NOTHING_A_MUSIC + Random( 4 ) ); + MusicPlay(bNothingModeSong); + bNothingModeSong = (INT8) (NOTHING_A_MUSIC + Random(4)); } break; case MUSIC_TACTICAL_ENEMYPRESENT: // ATE: Don't fade in EnemyPresent... gbFadeSpeed = (INT8)uiMusicVolume; - if( gfUseCreatureMusic ) + if(gfUseCreatureMusic) { - MusicPlay( CREEPY_MUSIC ); + MusicPlay(CREEPY_MUSIC); } else { - MusicPlay( bEnemyModeSong ); - bEnemyModeSong = (INT8) (TENSOR_A_MUSIC + Random( 3 )); + MusicPlay(bEnemyModeSong); + bEnemyModeSong = (INT8) (TENSOR_A_MUSIC + Random(3)); } break; case MUSIC_TACTICAL_BATTLE: // ATE: Don't fade in gbFadeSpeed = (INT8)uiMusicVolume; - if( gfUseCreatureMusic ) + if(gfUseCreatureMusic) { - MusicPlay( CREATURE_BATTLE_MUSIC ); + MusicPlay(CREATURE_BATTLE_MUSIC); } else { - MusicPlay( bBattleModeSong ); + MusicPlay(bBattleModeSong); } - bBattleModeSong = (INT8) (BATTLE_A_MUSIC + Random( 2 )); + bBattleModeSong = (INT8) (BATTLE_A_MUSIC + Random(2)); break; case MUSIC_TACTICAL_VICTORY: // ATE: Don't fade in EnemyPresent... gbFadeSpeed = (INT8)uiMusicVolume; - MusicPlay( TRIUMPH_MUSIC ); + MusicPlay(TRIUMPH_MUSIC); gbVictorySongCount++; - if( gfUseCreatureMusic && !gbWorldSectorZ ) - { //We just killed all the creatures that just attacked the town. + if(gfUseCreatureMusic && !gbWorldSectorZ) + { + //We just killed all the creatures that just attacked the town. gfUseCreatureMusic = FALSE; } break; @@ -504,55 +507,90 @@ BOOLEAN StartMusicBasedOnMode( ) // ATE: Don't fade in EnemyPresent... gbFadeSpeed = (INT8)uiMusicVolume; - MusicPlay( DEATH_MUSIC ); + MusicPlay(DEATH_MUSIC); gbDeathSongCount++; break; default: - MusicFadeOut( ); + MusicFadeOut(); break; } - return( TRUE ); + return TRUE; } +BOOLEAN SetMusicMode(UINT8 ubMusicMode) +{ + return SetMusicMode(ubMusicMode, FALSE); +} -void MusicStopCallback( void *pData ) +static void MusicStopCallback(void *pData) { //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "Music EndCallback %d %d", uiMusicHandle, gubMusicMode ) ); - gfMusicEnded = TRUE; + gfMusicEnded = TRUE; uiMusicHandle = NO_SAMPLE; //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Music EndCallback completed" ); } -void SetMusicFadeSpeed( INT8 bFadeSpeed ) +void SetMusicFadeSpeed(INT8 bFadeSpeed) { gbFadeSpeed = bFadeSpeed; } -void FadeMusicForXSeconds( UINT32 uiDelay ) +UINT8 GetMusicMode(void) { - INT16 sNumTimeSteps, sNumVolumeSteps; - - // get # time steps in delay.... - sNumTimeSteps = (INT16)( uiDelay / 10 ); - - // Devide this by music volume... - sNumVolumeSteps = (INT16)( uiMusicVolume / sNumTimeSteps ); - - // Set fade delay... - SetMusicFadeSpeed( (INT8)sNumVolumeSteps ); + return gubMusicMode; } - -void DoneFadeOutDueToEndMusic( void ) +BOOLEAN UsingCreatureMusic(void) { - // Quit game.... - InternalLeaveTacticalScreen( MAINMENU_SCREEN ); - //SetPendingNewScreen( MAINMENU_SCREEN ); + return gfUseCreatureMusic; } +void UseCreatureMusic(BOOLEAN fUseCreatureMusic) +{ + if (gfUseCreatureMusic != fUseCreatureMusic) + { + // this means a change + gfUseCreatureMusic = fUseCreatureMusic; + SetMusicMode(gubMusicMode, TRUE); // same as before + } +} + +BOOLEAN IsMusicPlaying(void) +{ + return fMusicPlaying; +} + +UINT32 GetMusicHandle(void) +{ + return uiMusicHandle; +} + +// unused +//void FadeMusicForXSeconds( UINT32 uiDelay ) +//{ +// INT16 sNumTimeSteps, sNumVolumeSteps; +// +// // get # time steps in delay.... +// sNumTimeSteps = (INT16)( uiDelay / 10 ); +// +// // Devide this by music volume... +// sNumVolumeSteps = (INT16)( uiMusicVolume / sNumTimeSteps ); +// +// // Set fade delay... +// SetMusicFadeSpeed( (INT8)sNumVolumeSteps ); +//} + +// unused +//void DoneFadeOutDueToEndMusic( void ) +//{ +// // Quit game.... +// InternalLeaveTacticalScreen( MAINMENU_SCREEN ); +// //SetPendingNewScreen( MAINMENU_SCREEN ); +//} + diff --git a/Utils/Music Control.h b/Utils/Music Control.h index 676a1f42..f6b9c16b 100644 --- a/Utils/Music Control.h +++ b/Utils/Music Control.h @@ -1,7 +1,8 @@ #ifndef _MUSIC_CONTROL_H_ #define _MUSIC_CONTROL_H_ -enum MusicList { +enum MusicList +{ MARIMBAD2_MUSIC, MENUMIX_MUSIC, NOTHING_A_MUSIC, @@ -20,8 +21,8 @@ enum MusicList { NUM_MUSIC }; -enum MusicMode { - +enum MusicMode +{ MUSIC_NONE, MUSIC_RESTORE, MUSIC_MAIN_MENU, @@ -33,23 +34,34 @@ enum MusicMode { MUSIC_LAPTOP, }; -extern UINT32 uiMusicHandle; -extern BOOLEAN fMusicPlaying; -extern UINT8 gubMusicMode; -extern BOOLEAN gfForceMusicToTense; +//extern UINT32 uiMusicHandle; +//extern BOOLEAN fMusicPlaying; +//extern UINT8 gubMusicMode; +//extern BOOLEAN gfForceMusicToTense; +UINT8 GetMusicMode(void); +BOOLEAN SetMusicMode(UINT8 ubMusicMode); -BOOLEAN SetMusicMode( UINT8 ubMusicMode ); +// only for editor (editscreen.cpp) BOOLEAN MusicPlay(UINT32 uiNum); -BOOLEAN MusicSetVolume(UINT32 uiVolume); + UINT32 MusicGetVolume(void); -BOOLEAN MusicStop(void); -BOOLEAN MusicFadeOut(void); -BOOLEAN MusicFadeIn(void); -BOOLEAN MusicPoll( BOOLEAN fForce ); +BOOLEAN MusicSetVolume(UINT32 uiVolume); -void SetMusicFadeSpeed( INT8 bFadeSpeed ); +BOOLEAN MusicPoll(BOOLEAN fForce); -void FadeMusicForXSeconds( UINT32 uiDelay ); +void SetMusicFadeSpeed(INT8 bFadeSpeed); + +BOOLEAN UsingCreatureMusic(void); +void UseCreatureMusic(BOOLEAN fUseCreatureMusic); + +// only for luaglobal.cpp +BOOLEAN IsMusicPlaying(void); +UINT32 GetMusicHandle(void); + +//BOOLEAN MusicStop(void); +//BOOLEAN MusicFadeOut(void); +//BOOLEAN MusicFadeIn(void); +//void FadeMusicForXSeconds( UINT32 uiDelay ); #endif diff --git a/Utils/Slider.cpp b/Utils/Slider.cpp index ba3cd4ca..10ff5fbd 100644 --- a/Utils/Slider.cpp +++ b/Utils/Slider.cpp @@ -624,10 +624,10 @@ void CalculateNewSliderIncrement( UINT32 uiSliderID, UINT16 usPos ) if( pSlider->uiFlags & SLIDER_VERTICAL ) { - if( usPos >= (UINT16)(pSlider->usHeight * (FLOAT).99 ) ) + if( usPos >= (UINT16)(pSlider->usHeight * 0.99f ) ) fLastSpot = TRUE; - if( usPos <= (UINT16)(pSlider->usHeight * (FLOAT).01 ) ) + if( usPos <= (UINT16)(pSlider->usHeight * 0.01f ) ) fFirstSpot = TRUE; diff --git a/Utils/Text Input.cpp b/Utils/Text Input.cpp index 768e4a61..c94d62f4 100644 --- a/Utils/Text Input.cpp +++ b/Utils/Text Input.cpp @@ -21,7 +21,7 @@ #include "Sound Control.h" #endif -#include "VFS/Tools/ParserTools.h" +#include STR16 szClipboard; BOOLEAN gfNoScroll = FALSE; diff --git a/Utils/Text.h b/Utils/Text.h index f7e05d6f..fb192c64 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -7,6 +7,8 @@ #define STRING_LENGTH 255 +extern CHAR16 gszAimPages[ 6 ][ 20 ]; +extern CHAR16 zGrod[][500]; extern STR16 pCreditsJA2113[]; extern CHAR16 ShortItemNames[MAXITEMS][80]; extern CHAR16 ItemNames[MAXITEMS][80]; @@ -30,6 +32,7 @@ extern STR16 pAssignmentStrings[]; extern STR16 pConditionStrings[]; extern CHAR16 pTownNames[MAX_TOWNS][MAX_TOWN_NAME_LENGHT]; // Lesh: look mapscreen.h for definitions extern STR16 pPersonnelScreenStrings[]; +extern STR16 pPersonnelRecordsHelpTexts[]; // added by SANDRO extern STR16 pPersonnelTitle[]; extern STR16 pUpperLeftMapScreenStrings[]; extern STR16 pTacticalPopupButtonStrings[]; @@ -76,7 +79,7 @@ extern STR16 pMapScreenBorderButtonHelpText[]; extern STR16 pMapScreenBottomFastHelp[]; extern STR16 pMapScreenBottomText[]; extern STR16 pMercDeadString[]; -extern STR16 pSenderNameList[]; +extern CHAR16 pSenderNameList[500][128]; extern STR16 pTraverseStrings[]; extern STR16 pNewMailStrings[]; extern STR16 pDeleteMailStrings[]; @@ -153,6 +156,7 @@ extern STR16 pMilitiaButtonsHelpText[]; extern STR16 pMapScreenJustStartedHelpText[]; extern STR16 pLandMarkInSectorString[]; extern STR16 gzMercSkillText[]; +extern STR16 gzMercSkillTextNew[]; // added by SANDRO extern STR16 gzNonPersistantPBIText[]; extern STR16 gzMiscString[]; @@ -172,6 +176,14 @@ extern STR16 gzIMPCharacterTraitText[]; extern STR16 gzIMPColorChoosingText[]; extern STR16 sColorChoiceExplanationTexts[]; extern STR16 gzIMPDisabilityTraitText[]; +extern STR16 sEnemyTauntsFireGun[]; +extern STR16 sEnemyTauntsFireLauncher[]; +extern STR16 sEnemyTauntsThrow[]; +extern STR16 sEnemyTauntsChargeKnife[]; +extern STR16 sEnemyTauntsRunAway[]; +extern STR16 sEnemyTauntsSeekNoise[]; +extern STR16 sEnemyTauntsAlert[]; +extern STR16 sEnemyTauntsGotHit[]; //**** // HEADROCK HAM 3.6: New arrays for facility operation messages @@ -179,9 +191,13 @@ extern STR16 gzFacilityErrorMessage[]; extern STR16 gzFacilityAssignmentStrings[]; extern STR16 gzFacilityRiskResultStrings[]; +// HEADROCK HAM 4: Text for the new CTH indicator. +extern STR16 gzNCTHlabels[]; + enum { ANTIHACKERSTR_EXITGAME, + TEXT_NUM_ANTIHACKERSTR, }; extern STR16 pAntiHackerString[]; @@ -266,8 +282,8 @@ enum MSG_HISTORY_UPDATED, MSG_GL_BURST_CURSOR_ON, MSG_GL_BURST_CURSOR_OFF, - MSG_DROP_ALL_ON, - MSG_DROP_ALL_OFF, + MSG_SOLDIER_TOOLTIPS_ON, // changed by SANDRO + MSG_SOLDIER_TOOLTIPS_OFF, // changed by SANDRO MSG_GL_LOW_ANGLE, MSG_GL_HIGH_ANGLE, MSG_FORCED_TURN_MODE, @@ -278,8 +294,9 @@ enum MSG_END_TURN_AUTO_SAVE, #endif MSG_MPSAVEDIRECTORY,//84 - MSG_CLIENT - + MSG_CLIENT, + MSG_NAS_AND_OIV_INCOMPATIBLE, + TEXT_NUM_MSG, }; extern STR16 pMessageStrings[]; @@ -357,6 +374,23 @@ enum STR_NO_SEMI_AUTO, STR_NO_MORE_ITEMS_TO_STEAL, STR_NO_MORE_ITEM_IN_HAND, + + //add new camo text + STR_DESERT_WORN_OFF, + STR_DESERT_WASHED_OFF, + + STR_JUNGLE_WORN_OFF, + STR_JUNGLE_WASHED_OFF, + + STR_URBAN_WORN_OFF, + STR_URBAN_WASHED_OFF, + + STR_SNOW_WORN_OFF, + STR_SNOW_WASHED_OFF, + + STR_CANNOT_ATTACH_SLOT, + + TEXT_NUM_STR_MESSAGE, }; // WANNE: Tooltips @@ -399,6 +433,12 @@ enum STR_TT_NO_VEST, STR_TT_NO_LEGGING, STR_TT_CAT_ARMOR_2, + // Following added - SANDRO + STR_TT_SKILL_TRAIT_1, + STR_TT_SKILL_TRAIT_2, + STR_TT_SKILL_TRAIT_3, + + TEXT_NUM_STR_TT }; #define LARGE_STRING_LENGTH 200 @@ -415,17 +455,44 @@ extern CHAR16 zTalkMenuStrings[][ SMALL_STRING_LENGTH ]; extern STR16 gzMoneyAmounts[6]; extern CHAR16 gzProsLabel[10]; extern CHAR16 gzConsLabel[10]; +// HEADROCK HAM 4: Text for the UDB tabs +extern STR16 gzItemDescTabButtonText[ 3 ]; +extern STR16 gzItemDescTabButtonShortText[ 3 ]; +extern STR16 gzItemDescGenHeaders[ 4 ]; +extern STR16 gzItemDescGenIndexes[ 4 ]; +// HEADROCK HAM 4: Added list of condition strings +extern STR16 gConditionDesc[ 9 ]; + extern CHAR16 gMoneyStatsDesc[][ 13 ]; -// HEADROCK: Altered value to 16 -extern CHAR16 gWeaponStatsDesc[][ 16 ]; +// HEADROCK: Altered value to 16 //WarmSteel - And I need 17. +extern CHAR16 gWeaponStatsDesc[][ 17 ]; // HEADROCK: Added externs for Item Description Box icon and stat tooltips // Note that I've inflated some of these to 20 to avoid issues. -extern STR16 gzWeaponStatsFasthelp[ 29 ]; -extern STR16 gzWeaponStatsFasthelpTactical[ 29 ]; +extern STR16 gzWeaponStatsFasthelp[ 32 ]; +extern STR16 gzWeaponStatsFasthelpTactical[ 32 ]; extern STR16 gzAmmoStatsFasthelp[ 20 ]; extern STR16 gzArmorStatsFasthelp[ 20 ]; extern STR16 gzExplosiveStatsFasthelp[ 20 ]; extern STR16 gzMiscItemStatsFasthelp[ 34 ]; +// HEADROCK HAM 4: New tooltip texts +extern STR16 gzUDBButtonTooltipText[ 3 ]; +extern STR16 gzUDBHeaderTooltipText[ 4 ]; +extern STR16 gzUDBGenIndexTooltipText[ 4 ]; +extern STR16 gzUDBAdvIndexTooltipText[ 5 ]; +extern STR16 szUDBGenWeaponsStatsTooltipText[ 22 ]; +extern STR16 szUDBGenWeaponsStatsExplanationsTooltipText[ 22 ]; +extern STR16 szUDBGenArmorStatsTooltipText[ 3 ]; +extern STR16 szUDBGenArmorStatsExplanationsTooltipText[ 3 ]; +extern STR16 szUDBGenAmmoStatsTooltipText[ 3 ]; +extern STR16 szUDBGenAmmoStatsExplanationsTooltipText[ 3 ]; +extern STR16 szUDBGenExplosiveStatsTooltipText[ 18 ]; +extern STR16 szUDBGenExplosiveStatsExplanationsTooltipText[ 18 ]; +extern STR16 szUDBGenSecondaryStatsTooltipText[ 26 ]; +extern STR16 szUDBGenSecondaryStatsExplanationsTooltipText[ 26 ]; +extern STR16 szUDBAdvStatsTooltipText[ 44 ]; +extern STR16 szUDBAdvStatsExplanationsTooltipText[ 44 ]; +extern STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[ 44 ]; + // Headrock: End Externs extern STR16 sKeyDescriptionStrings[2]; extern CHAR16 zHealthStr[][13]; @@ -583,6 +650,7 @@ enum NO_LOS_TO_TALK_TARGET, ATTACHMENT_REMOVED, VEHICLE_CAN_NOT_BE_ADDED, + TEXT_NUM_TACTICAL_STR }; enum{ @@ -601,6 +669,7 @@ enum{ EXIT_GUI_SINGLE_TRAVERSAL_WILL_SEPARATE_SQUADS_HELPTEXT, EXIT_GUI_ALL_TRAVERSAL_WILL_MOVE_CURRENT_SQUAD_HELPTEXT, EXIT_GUI_ESCORTED_CHARACTERS_CANT_LEAVE_SECTOR_ALONE_STR, + TEXT_NUM_EXIT_GUI }; extern STR16 pExitingSectorHelpText[]; @@ -610,6 +679,7 @@ enum LARGESTR_NOONE_LEFT_CAPABLE_OF_BATTLE_STR, LARGESTR_NOONE_LEFT_CAPABLE_OF_BATTLE_AGAINST_CREATURES_STR, LARGESTR_HAVE_BEEN_CAPTURED, + TEXT_NUM_LARGESTR }; @@ -620,6 +690,7 @@ enum INS_CONTRACT_NEXT, INS_CONTRACT_ACCEPT, INS_CONTRACT_CLEAR, + TEXT_NUM_INS_CONTRACT }; extern STR16 InsContractText[]; @@ -629,6 +700,7 @@ enum { INS_INFO_PREVIOUS, INS_INFO_NEXT, + TEXT_NUM_INS_INFO, }; extern STR16 InsInfoText[]; @@ -645,6 +717,7 @@ enum MERC_ACCOUNT_TOTAL, MERC_ACCOUNT_AUTHORIZE_CONFIRMATION, MERC_ACCOUNT_NOT_ENOUGH_MONEY, + TEXT_NUM_MERC_ACCOUNT, }; extern STR16 MercAccountText[]; @@ -680,6 +753,7 @@ enum MERC_FILES_HIRE_TO_MANY_PEOPLE_WARNING, MERC_FILES_MERC_UNAVAILABLE, + TEXT_NUM_MERC_FILES, }; extern STR16 MercInfo[]; @@ -690,6 +764,7 @@ enum MERC_NO_ACC_OPEN_ACCOUNT, MERC_NO_ACC_CANCEL, MERC_NO_ACC_NO_ACCOUNT_OPEN_ONE, + TEXT_NUM_MERC_NO_ACC, }; extern STR16 MercNoAccountText[]; @@ -703,6 +778,7 @@ enum MERC_VIEW_ACCOUNT, MERC_VIEW_FILES, MERC_SPECK_COM, + TEXT_NUM_MERC, }; extern STR16 MercHomePageText[]; @@ -722,6 +798,7 @@ enum FUNERAL_FUNERAL_ETTIQUETTE, FUNERAL_OUR_CONDOLENCES, //10 FUNERAL_OUR_SYMPATHIES, + TEXT_NUM_FUNERAL, }; extern STR16 sFuneralString[]; @@ -742,6 +819,8 @@ enum FLORIST_ADVERTISEMENT_6, FLORIST_ADVERTISEMENT_7, FLORIST_ADVERTISEMENT_8, + FLORIST_ADVERTISEMENT_9, + TEXT_NUM_FLORIST, }; extern STR16 sFloristText[]; @@ -771,6 +850,7 @@ enum FLORIST_ORDER_STANDARDIZED_CARDS, FLORIST_ORDER_BILLING_INFO, //20 FLORIST_ORDER_NAME, + TEXT_NUM_FLORIST_ORDER, }; extern STR16 sOrderFormText[]; @@ -784,6 +864,7 @@ enum FLORIST_GALLERY_CLICK_TO_ORDER, FLORIST_GALLERY_ADDIFTIONAL_FEE, FLORIST_GALLERY_HOME, + TEXT_NUM_FLORIST_GALLERY, }; extern STR16 sFloristGalleryText[]; @@ -793,6 +874,7 @@ enum { FLORIST_CARDS_CLICK_SELECTION, FLORIST_CARDS_BACK, + TEXT_NUM_FLORIST_CARDS, }; extern STR16 sFloristCards[]; @@ -825,6 +907,7 @@ enum BOBBYR_PACKAGE_WEIGHT, BOBBYR_MINIMUM_WEIGHT, BOBBYR_GOTOSHIPMENT_PAGE, + TEXT_NUM_BOBBYR_MAILORDER, }; extern STR16 BobbyROrderFormText[]; @@ -871,6 +954,7 @@ enum BOBBYR_FILTER_MISC_FACE, BOBBYR_FILTER_MISC_LBEGEAR, BOBBYR_FILTER_MISC_MISC, + TEXT_NUM_BOBBYR_FILTER }; @@ -908,7 +992,7 @@ enum BOBBYR_MORE_THEN_10_PURCHASES, BOBBYR_MORE_NO_MORE_IN_STOCK, BOBBYR_NO_MORE_STOCK, - + TEXT_NUM_BOBBYR_GUNS, }; extern STR16 BobbyRText[]; @@ -927,6 +1011,7 @@ enum BOBBYR_ARMOR, BOBBYR_ADVERTISMENT_3, BOBBYR_UNDER_CONSTRUCTION, + TEXT_NUM_BOBBYR }; extern STR16 BobbyRaysFrontText[]; @@ -945,7 +1030,8 @@ enum MERCENARY_FILES, ALUMNI_GALLERY, ASCENDING, - DESCENDING + DESCENDING, + TEXT_NUM_AIM_SORT }; extern STR16 AimSortText[]; @@ -958,6 +1044,7 @@ enum AIM_POLICIES_NEXT_PAGE, AIM_POLICIES_DISAGREE, AIM_POLICIES_AGREE, + TEXT_NUM_AIM_POLICIES }; extern STR16 AimPolicyText[]; @@ -968,6 +1055,7 @@ extern STR16 AimPolicyText[]; enum { AIM_MEMBER_CLICK_INSTRUCTIONS, + TEXT_NUM_AIM_MEMBER_TEXT }; extern STR16 AimMemberText[]; @@ -998,7 +1086,14 @@ enum AIM_MEMBER_ADDTNL_INFO, AIM_MEMBER_ACTIVE_MEMBERS, //20 AIM_MEMBER_OPTIONAL_GEAR, + AIM_MEMBER_OPTIONAL_GEAR_NSGI, AIM_MEMBER_MEDICAL_DEPOSIT_REQ, + AIM_MEMBER_GEAR_KIT_ONE, + AIM_MEMBER_GEAR_KIT_TWO, //25 + AIM_MEMBER_GEAR_KIT_THREE, + AIM_MEMBER_GEAR_KIT_FOUR, + AIM_MEMBER_GEAR_KIT_FIVE, + TEXT_NUM_AIM_MEMBER_CHARINFO, }; extern STR16 CharacterInfo[]; @@ -1022,6 +1117,7 @@ enum AIM_MEMBER_VIDEO_CONF_WITH, AIM_MEMBER_CONNECTING, AIM_MEMBER_WITH_MEDICAL, //14 + TEXT_NUM_AIM_MEMBER_VCONF }; extern STR16 VideoConfercingText[]; @@ -1040,7 +1136,7 @@ enum AIM_MEMBER_PRERECORDED_MESSAGE, AIM_MEMBER_MESSAGE_RECORDED, - + TEXT_NUM_AIM_MEMBER_POPUP }; extern STR16 AimPopUpText[]; @@ -1048,6 +1144,7 @@ extern STR16 AimPopUpText[]; enum { AIM_LINK_TITLE, + TEXM_NUM_AIM_LINK, }; extern STR16 AimLinkText[]; @@ -1060,6 +1157,7 @@ enum AIM_HISTORY_HOME, AIM_HISTORY_AIM_ALUMNI, AIM_HISTORY_NEXT, + TEXT_NUM_AIM_HISTORY, }; extern STR16 AimHistoryText[]; @@ -1081,7 +1179,9 @@ enum AIM_FI_RIGHT_CLICK, AIM_FI_TO_ENTER_SORT_PAGE, AIM_FI_AWAY, - AIM_FI_DEAD, + AIM_FI_DEAD, + AIM_FI_ON_ASSIGN, + TEXT_NUM_AIM_FI, }; extern STR16 AimFiText[]; @@ -1094,6 +1194,7 @@ enum AIM_ALUMNI_PAGE_3, AIM_ALUMNI_ALUMNI, AIM_ALUMNI_DONE, + TEXT_NUM_AIM_ALUMNI, }; extern STR16 AimAlumniText[]; @@ -1115,7 +1216,7 @@ enum AIM_BOBBYR_ADD1, AIM_BOBBYR_ADD2, AIM_BOBBYR_ADD3, - + TEXT_NUM_AIM_SCREEN }; extern STR16 AimScreenText[]; @@ -1129,6 +1230,7 @@ enum AIM_POLICIES, AIM_HISTORY, AIM_LINKS, + TEXT_NUM_AIM_MENU }; extern STR16 AimBottomMenuText[]; @@ -1140,6 +1242,7 @@ enum { MAP_SCREEN_MAP_LEVEL, MAP_SCREEN_NO_MILITIA_TEXT, + TEXT_NUM_MAP_SCREEN, }; extern STR16 zMarksMapScreenText[]; @@ -1244,6 +1347,7 @@ enum STR_DIALOG_CREATURES_KILL_CIVILIANS, STR_DIALOG_ENEMIES_ATTACK_UNCONCIOUSMERCS, STR_DIALOG_CREATURES_ATTACK_UNCONCIOUSMERCS, + TEXT_NUM_STRATEGIC_TEXT }; //Strings used in conjunction with above enumerations @@ -1252,6 +1356,7 @@ extern STR16 gpStrategicString[]; enum { STR_GAMECLOCK_DAY_NAME, + TEXT_NUM_GAMECLOCK, }; extern STR16 gpGameClockString[]; @@ -1272,6 +1377,7 @@ enum SKI_TEXT_NO_MORE_ROOM_IN_PLAYER_OFFER_AREA, SKI_TEXT_MINUTES, SKI_TEXT_DROP_ITEM_TO_GROUND, + TEXT_NUM_SKI_TEXT }; extern STR16 SKI_Text[]; @@ -1307,6 +1413,7 @@ enum SKI_ATM_MODE_TEXT_SELECT_FROM_MERC, SKI_ATM_MODE_TEXT_SELECT_INUSUFFICIENT_FUNDS, SKI_ATM_MODE_TEXT_BALANCE, + TEXT_NUM_SKI_ATM_MODE_TEXT, }; extern STR16 gzSkiAtmText[]; @@ -1322,6 +1429,7 @@ enum SKI_DONE_BUTTON_HELP_TEXT, SKI_PLAYERS_CURRENT_BALANCE, + TEXT_NUM_SKI_MBOX_TEXT }; extern STR16 SkiMessageBoxText[]; @@ -1362,7 +1470,9 @@ enum SLG_BR_AWESOME_TEXT, SLG_INV_RES_ERROR, - SLG_INV_CUSTUM_ERROR, + SLG_INV_CUSTUM_ERROR, + + TEXT_NUM_SLG_TEXT, }; extern STR16 zSaveLoadText[]; @@ -1383,6 +1493,7 @@ enum OPT_MUSIC, OPT_RETURN_TO_MAIN, OPT_NEED_AT_LEAST_SPEECH_OR_SUBTITLE_OPTION_ON, + TEXT_NUM_OPT_TEXT, }; extern STR16 zOptionsText[]; @@ -1400,7 +1511,7 @@ enum MONEY_DESC_BALANCE, MONEY_DESC_AMOUNT_2_WITHDRAW, MONEY_DESC_TO_WITHDRAW, - + TEXT_NUM_MONEY_DESC, }; @@ -1409,6 +1520,7 @@ enum { MONEY_TEXT_WITHDRAW_MORE_THEN_MAXIMUM, CONFIRMATION_TO_DEPOSIT_MONEY_TO_ACCOUNT, + TEXT_NUM_MONEY_WITHDRAW }; @@ -1433,7 +1545,7 @@ enum GIO_HARD_TEXT, GIO_INSANE_TEXT, - GIO_OK_TEXT, + GIO_START_TEXT, GIO_CANCEL_TEXT, GIO_GAME_SAVE_STYLE_TEXT, @@ -1452,6 +1564,41 @@ enum GIO_INV_NEW_TEXT, GIO_LOAD_MP_GAME, GIO_INITIAL_GAME_SETTINGS_MP, + //////////////////////////////////// + // SANDRO - added following + GIO_TRAITS_TEXT, + GIO_TRAITS_OLD_TEXT, + GIO_TRAITS_NEW_TEXT, + GIO_IMP_NUMBER_TITLE_TEXT, + GIO_IMP_NUMBER_1, + GIO_IMP_NUMBER_2, + GIO_IMP_NUMBER_3, + GIO_IMP_NUMBER_4, + GIO_IMP_NUMBER_5, + GIO_IMP_NUMBER_6, + GIO_DROPALL_TITLE_TEXT, + GIO_DROPALL_OFF_TEXT, + GIO_DROPALL_ON_TEXT, + GIO_TERRORISTS_TITLE_TEXT, + GIO_TERRORISTS_RANDOM_TEXT, + GIO_TERRORISTS_ALL_TEXT, + GIO_CACHES_TITLE_TEXT, + GIO_CACHES_RANDOM_TEXT, + GIO_CACHES_ALL_TEXT, + GIO_PROGRESS_TITLE_TEXT, + GIO_PROGRESS_VERY_SLOW_TEXT, + GIO_PROGRESS_SLOW_TEXT, + GIO_PROGRESS_NORMAL_TEXT, + GIO_PROGRESS_FAST_TEXT, + GIO_PROGRESS_VERY_FAST_TEXT, + + // WANNE: New strings for start new game screen (for NAS) + GIO_INV_SETTING_OLD_TEXT, + GIO_INV_SETTING_NEW_TEXT, + GIO_INV_SETTING_NEW_NAS_TEXT, + + //////////////////////////////////// + TEXT_NUM_GIO_TEXT }; extern STR16 gzGIOScreenText[]; @@ -1474,9 +1621,12 @@ enum MPJ_PING_TEXT, MPJ_HANDLE_INVALID, MPJ_SERVERIP_INVALID, - MPJ_SERVERPORT_INVALID + MPJ_SERVERPORT_INVALID, + TEXT_NUM_MPJ_TEXT }; +extern STR16 gzMPJHelpText[]; + extern STR16 gzMPJScreenText[]; //Multiplayer Host Screen enum @@ -1512,11 +1662,40 @@ enum MPH_ENABLECIV_TEXT, MPH_USENIV_TEXT, MPH_OVERRIDEMAXAI_TEXT, - MPH_SYNC_CLIENT_MP_DIR, + MPH_SYNC_GAME_DIRECTORY, MPH_FILE_TRANSFER_DIR_TEXT, MPH_FILE_TRANSFER_DIR_INVALID, MPH_FILE_TRANSFER_DIR_TEXT_ADDITIONAL, MPH_FILE_TRANSFER_DIR_NOT_EXIST, + MPH_1, + MPH_2, + MPH_3, + MPH_4, + MPH_5, + MPH_6, + MPH_YES, + MPH_NO, + MPH_MORNING, + MPH_AFTERNOON, + MPH_NIGHT, + MPH_CASH_LOW, + MPH_CASH_MEDIUM, + MPH_CASH_HIGH, + MPH_CASH_UNLIMITED, + MPH_TIME_NEVER, + MPH_TIME_SLOW, + MPH_TIME_MEDIUM, + MPH_TIME_FAST, + MPH_DAMAGE_VERYLOW, + MPH_DAMAGE_LOW, + MPH_DAMAGE_NORMAL, + MPH_HIRE_RANDOM, + MPH_HIRE_NORMAL, + MPH_EDGE_RANDOM, + MPH_EDGE_SELECTABLE, + MPH_DISABLE, + MPH_ALLOW, + TEXT_NUM_MPH_TEXT, }; extern STR16 gzMPHScreenText[]; enum @@ -1533,7 +1712,8 @@ enum MPS_ACCURACY_TEXT, MPS_DMGDONE_TEXT, MPS_DMGTAKEN_TEXT, - MPS_WAITSERVER_TEXT + MPS_WAITSERVER_TEXT, + TEXT_NUM_MPS_TEXT, }; extern STR16 gzMPSScreenText[]; enum @@ -1545,6 +1725,7 @@ enum MPC_HELP1_TEXT, MPC_HELP2_TEXT, MPC_READY_TEXT, + TEXT_NUM_MPC_TEXT, }; extern STR16 gzMPCScreenText[]; // Multiplayer Starting Edges @@ -1594,7 +1775,7 @@ enum BOOKMARK_TEXT_MCGILLICUTTY_MORTUARY, BOOKMARK_TEXT_UNITED_FLORAL_SERVICE, BOOKMARK_TEXT_INSURANCE_BROKERS_FOR_AIM_CONTRACTS, - + TEXT_NUM_LAPTOP_BN_BOOKMARK_TEXT }; @@ -1602,6 +1783,7 @@ enum enum { HLP_SCRN_TXT__EXIT_SCREEN, + TEXT_NUM_HLP }; extern STR16 gzHelpScreenText[]; @@ -1623,6 +1805,7 @@ enum MAPINV_CANT_PICKUP_IN_COMBAT, MAPINV_CANT_DROP_IN_COMBAT, MAPINV_NOT_IN_SECTOR_TO_DROP, + TEXT_NUM_MAPINV }; @@ -1631,6 +1814,7 @@ enum { BROKEN_LINK_TXT_ERROR_404, BROKEN_LINK_TXT_SITE_NOT_FOUND, + TEXT_NUM_BROKEN_LINK, }; extern STR16 BrokenLinkText[]; @@ -1641,6 +1825,7 @@ enum BOBBYR_SHIPMENT__ORDER_NUM, BOBBYR_SHIPMENT__NUM_ITEMS, BOBBYR_SHIPMENT__ORDERED_ON, + TEXT_NUM_BOBBYR_SHIPMENT, }; extern STR16 gzBobbyRShipmentText[]; @@ -1652,6 +1837,7 @@ enum GIO_CFS_EXPERIENCED, GIO_CFS_EXPERT, GIO_CFS_INSANE, + TEXT_NUM_GIO_CFS, }; extern STR16 zGioDifConfirmText[]; @@ -1691,6 +1877,8 @@ extern STR16 New113Message[]; extern STR16 New113MERCMercMailTexts[]; extern STR16 MissingIMPSkillsDescriptions[]; +extern STR16 New113AIMMercMailTexts[]; // WANNE: new WF Merc text, that does not exist in Email.edt + // HEADROCK: HAM Messages extern STR16 New113HAMMessage[]; enum @@ -1719,6 +1907,24 @@ enum MSG113_RTM_SNEAKING_OFF, MSG113_RTM_SNEAKING_ON, MSG113_RTM_ENEMIES_SPOOTED, + // added by SANDRO + MSG113_THIEF_SUCCESSFUL, + MSG113_NOT_ENOUGH_APS_TO_STEAL_ALL, + MSG113_DO_WE_WANT_SURGERY_FIRST, + MSG113_DO_WE_WANT_SURGERY, + MSG113_SURGERY_BEFORE_DOCTOR_ASSIGNMENT, + MSG113_SURGERY_BEFORE_PATIENT_ASSIGNMENT, + MSG113_SURGERY_ON_TACTICAL_AUTOBANDAGE, + MSG113_SURGERY_FINISHED, + MSG113_LOSES_ONE_POINT_MAX_HEALTH, + MSG113_LOSES_X_POINTS_MAX_HEALTH, + MSG113_REGAINED_ONE_POINTS_OF_STAT, + MSG113_REGAINED_X_POINTS_OF_STATS, + MSG113_ENEMY_AMBUSH_PREVENTED, + MSG113_BLOODCATS_AMBUSH_PREVENTED, + MSG113_SOLDIER_HIT_TO_GROIN, + + TEXT_NUM_MSG113, }; //CHRISL: NewInv messages @@ -1727,7 +1933,6 @@ extern STR16 NewInvMessage[]; // WANNE - MP: New multiplayer messages extern STR16 MPServerMessage[]; extern STR16 MPClientMessage[]; -extern STR16 MPHelp[]; // WANNE: Some Chinese specific strings that needs to be in unicode! extern STR16 ChineseSpecString1; @@ -1748,6 +1953,7 @@ enum NIV_SELL_ALL, NIV_DELETE_ALL, NIV_NO_CLIMB, + TEXT_NUM_NIV, }; // OJW - MP diff --git a/Utils/Utils_VS2005.vcproj b/Utils/Utils_VS2005.vcproj new file mode 100644 index 00000000..bdabfabc --- /dev/null +++ b/Utils/Utils_VS2005.vcproj @@ -0,0 +1,755 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Utils/Utils_VS2008.vcproj b/Utils/Utils_VS2008.vcproj index f2a3fd2b..fafecee4 100644 --- a/Utils/Utils_VS2008.vcproj +++ b/Utils/Utils_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -148,7 +148,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -213,7 +213,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -378,6 +378,14 @@ RelativePath="Animated ProgressBar.h" > + + + + @@ -406,14 +414,26 @@ RelativePath="Event Pump.h" > + + + + + + @@ -490,10 +510,18 @@ RelativePath="WordWrap.h" > + + + + @@ -578,6 +606,10 @@ RelativePath="Animated ProgressBar.cpp" > + + @@ -606,14 +638,26 @@ RelativePath="Event Pump.cpp" > + + + + + + @@ -690,6 +734,10 @@ RelativePath="XML_Items.cpp" > + + diff --git a/Utils/Utils_VS2010.vcxproj b/Utils/Utils_VS2010.vcxproj new file mode 100644 index 00000000..b578f2b2 --- /dev/null +++ b/Utils/Utils_VS2010.vcxproj @@ -0,0 +1,315 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {082F6E91-D049-4314-BE9D-D9509E853B01} + Win32Proj + Utils + Utils + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/Utils/Utils_VS2010.vcxproj.filters b/Utils/Utils_VS2010.vcxproj.filters new file mode 100644 index 00000000..0acf8db6 --- /dev/null +++ b/Utils/Utils_VS2010.vcxproj.filters @@ -0,0 +1,321 @@ + + + + + {85134125-f317-490e-9a9d-d210267ff98b} + + + {2c5f371b-8372-46d7-8b88-8c1885ddf7ef} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Utils/XMLProperties.cpp b/Utils/XMLProperties.cpp index ddbeacbd..b75f3b92 100644 --- a/Utils/XMLProperties.cpp +++ b/Utils/XMLProperties.cpp @@ -1,12 +1,16 @@ +#include +#include +#include +#include + +#include +#include + #include "XML_Parser.h" -#include "vfs_types.h" -#include "PropertyContainer.h" #include "XMLWriter.h" +#include "Debug.h" -#include "VFS/vfs_file_raii.h" -#include "VFS/File/vfs_file.h" - -CPropertyContainer::TagMap::TagMap() +vfs::PropertyContainer::TagMap::TagMap() { // setup default map _map[L"Container"] = L"Container"; @@ -15,7 +19,7 @@ CPropertyContainer::TagMap::TagMap() _map[L"Key"] = L"Key"; _map[L"KeyID"] = L"name"; } -utf8string const& CPropertyContainer::TagMap::container(utf8string::char_t* container) +vfs::String const& vfs::PropertyContainer::TagMap::container(vfs::String::char_t* container) { if(container) { @@ -23,7 +27,7 @@ utf8string const& CPropertyContainer::TagMap::container(utf8string::char_t* cont } return _map[L"Container"]; } -utf8string const& CPropertyContainer::TagMap::section(utf8string::char_t* section) +vfs::String const& vfs::PropertyContainer::TagMap::section(vfs::String::char_t* section) { if(section) { @@ -31,7 +35,7 @@ utf8string const& CPropertyContainer::TagMap::section(utf8string::char_t* sectio } return _map[L"Section"]; } -utf8string const& CPropertyContainer::TagMap::sectionID(utf8string::char_t* section_id) +vfs::String const& vfs::PropertyContainer::TagMap::sectionID(vfs::String::char_t* section_id) { if(section_id) { @@ -39,7 +43,7 @@ utf8string const& CPropertyContainer::TagMap::sectionID(utf8string::char_t* sect } return _map[L"SectionID"]; } -utf8string const& CPropertyContainer::TagMap::key(utf8string::char_t* key) +vfs::String const& vfs::PropertyContainer::TagMap::key(vfs::String::char_t* key) { if(key) { @@ -47,7 +51,7 @@ utf8string const& CPropertyContainer::TagMap::key(utf8string::char_t* key) } return _map[L"Key"]; } -utf8string const& CPropertyContainer::TagMap::keyID(utf8string::char_t* key_id) +vfs::String const& vfs::PropertyContainer::TagMap::keyID(vfs::String::char_t* key_id) { if(key_id) { @@ -56,7 +60,7 @@ utf8string const& CPropertyContainer::TagMap::keyID(utf8string::char_t* key_id) return _map[L"KeyID"]; } -bool CPropertyContainer::writeToXMLFile(vfs::Path const& sFileName, CPropertyContainer::TagMap& tagmap) +bool vfs::PropertyContainer::writeToXMLFile(vfs::Path const& sFileName, vfs::PropertyContainer::TagMap& tagmap) { XMLWriter xmlw; @@ -68,8 +72,8 @@ bool CPropertyContainer::writeToXMLFile(vfs::Path const& sFileName, CPropertyCon xmlw.addAttributeToNextValue(tagmap.sectionID(),sit->first.utf8()); xmlw.openNode(tagmap.section()); - CPropertyContainer::CSection& section = sit->second; - CPropertyContainer::CSection::tProps::iterator kit = section.mapProps.begin(); + vfs::PropertyContainer::Section& section = sit->second; + vfs::PropertyContainer::Section::tProps::iterator kit = section.mapProps.begin(); for(; kit != section.mapProps.end(); ++kit) { xmlw.addAttributeToNextValue(tagmap.keyID(), kit->first.utf8()); @@ -99,11 +103,11 @@ class CPropertyXMLParser : public IXMLParser }; public: CPropertyXMLParser( - CPropertyContainer& container, - CPropertyContainer::TagMap& tagmap, + vfs::PropertyContainer& container, + vfs::PropertyContainer::TagMap& tagmap, XML_Parser &parser, IXMLParser* caller = NULL) - : IXMLParser("",parser,caller), + : IXMLParser("",&parser,caller), _container(container), _tagmap(tagmap), current_state(DO_ELEMENT_NONE) // doesn't matter where we come from, we start fresh @@ -112,27 +116,27 @@ public: virtual void onEndElement(const XML_Char* name); virtual void onTextElement(const XML_Char *str, int len); private: - CPropertyContainer& _container; - CPropertyContainer::TagMap& _tagmap; + vfs::PropertyContainer& _container; + vfs::PropertyContainer::TagMap& _tagmap; DOM_OBJECT current_state; - utf8string current_section; - utf8string current_key; + vfs::String current_section; + vfs::String current_key; }; void CPropertyXMLParser::onStartElement(const XML_Char *name, const XML_Char **atts) { - utf8string utf8_name(name); - if(current_state == DO_ELEMENT_NONE && StrCmp::Equal(utf8_name,_tagmap.container())) + vfs::String utf8_name(name); + if(current_state == DO_ELEMENT_NONE && vfs::StrCmp::Equal(utf8_name,_tagmap.container())) { current_state = DO_ELEMENT_Container; } - else if(current_state == DO_ELEMENT_Container && StrCmp::Equal(utf8_name, _tagmap.section())) + else if(current_state == DO_ELEMENT_Container && vfs::StrCmp::Equal(utf8_name, _tagmap.section())) { current_state = DO_ELEMENT_Section; current_section = this->getAttribute(_tagmap.sectionID().utf8().c_str(),atts); } - else if(current_state == DO_ELEMENT_Section && StrCmp::Equal(utf8_name, _tagmap.key())) + else if(current_state == DO_ELEMENT_Section && vfs::StrCmp::Equal(utf8_name, _tagmap.key())) { current_state = DO_ELEMENT_Key; current_key = this->getAttribute(_tagmap.keyID().utf8().c_str(),atts); @@ -142,17 +146,17 @@ void CPropertyXMLParser::onStartElement(const XML_Char *name, const XML_Char **a void CPropertyXMLParser::onEndElement(const XML_Char* name) { - utf8string utf8_name(name); - if(current_state == DO_ELEMENT_Key && StrCmp::Equal(utf8_name, _tagmap.key())) + vfs::String utf8_name(name); + if(current_state == DO_ELEMENT_Key && vfs::StrCmp::Equal(utf8_name, _tagmap.key())) { _container.setStringProperty(current_section, current_key, vfs::trimString(sCharData,0,sCharData.length())); current_state = DO_ELEMENT_Section; } - else if(current_state == DO_ELEMENT_Section && StrCmp::Equal(utf8_name, _tagmap.section())) + else if(current_state == DO_ELEMENT_Section && vfs::StrCmp::Equal(utf8_name, _tagmap.section())) { current_state = DO_ELEMENT_Container; } - else if(current_state == DO_ELEMENT_Container && StrCmp::Equal(utf8_name, _tagmap.container())) + else if(current_state == DO_ELEMENT_Container && vfs::StrCmp::Equal(utf8_name, _tagmap.container())) { current_state = DO_ELEMENT_NONE; } @@ -166,25 +170,23 @@ void CPropertyXMLParser::onTextElement(const XML_Char *str, int len) } } -bool CPropertyContainer::initFromXMLFile(vfs::Path const& sFileName, CPropertyContainer::TagMap& tagmap) +bool vfs::PropertyContainer::initFromXMLFile(vfs::Path const& sFileName, vfs::PropertyContainer::TagMap& tagmap) { vfs::tReadableFile *file = NULL; bool delete_file = false; - try + if(getVFS()->fileExists(sFileName)) { vfs::COpenReadFile rfile(sFileName); file = &rfile.file(); rfile.release(); } - catch(CBasicException& ex) + else { - logException(ex); vfs::CFile* rfile = new vfs::CFile(sFileName); delete_file = true; file = vfs::tReadableFile::cast(rfile); if(!file->openRead()) { - file->close(); delete file; return false; } @@ -198,7 +200,7 @@ bool CPropertyContainer::initFromXMLFile(vfs::Path const& sFileName, CPropertyCo std::vector buffer(size+1); - TRYCATCH_RETHROW( file->read(&buffer[0],size), L"" ); + SGP_TRYCATCH_RETHROW( file->read(&buffer[0],size), L"" ); buffer[size] = 0; file->close(); @@ -213,10 +215,10 @@ bool CPropertyContainer::initFromXMLFile(vfs::Path const& sFileName, CPropertyCo { std::wstringstream wss; wss << L"XML Parser Error in Groups.xml: " - << utf8string::as_utf16(XML_ErrorString(XML_GetErrorCode(parser))) + << vfs::String::as_utf16(XML_ErrorString(XML_GetErrorCode(parser))) << L" at line " << XML_GetCurrentLineNumber(parser); - THROWEXCEPTION(wss.str().c_str()); + SGP_THROW(wss.str().c_str()); //return false; } diff --git a/Utils/XMLWriter.cpp b/Utils/XMLWriter.cpp index 0a860f51..8b1c407a 100644 --- a/Utils/XMLWriter.cpp +++ b/Utils/XMLWriter.cpp @@ -1,21 +1,30 @@ #include "XMLWriter.h" +#include "sgp_logger.h" -#include "VFS/vfs_file_raii.h" -#include "VFS/File/vfs_file.h" +#include +#include -void XMLWriter::addValue(utf8string const& key) +void XMLWriter::addValue(vfs::String const& key) { m_ssBuffer << indent() << "<" << key.utf8(); insertAttributesIntoBuffer(); m_ssBuffer << " />\n"; } -void XMLWriter::addComment(utf8string const& comment) +void XMLWriter::addComment(vfs::String const& comment) { m_ssBuffer << indent() << "\n"; } -void XMLWriter::openNode(utf8string const& key) +void XMLWriter::addFlag(UINT32 const& flags, UINT32 const& flag, vfs::String strFlag) +{ + if( ( flags & flag) == flag ) + { + this->addValue(strFlag); + } +} + +void XMLWriter::openNode(vfs::String const& key) { std::string utf8key = key.utf8(); m_ssBuffer << indent() << "<" << utf8key; @@ -49,9 +58,9 @@ bool XMLWriter::writeToFile(vfs::Path const& sFileName) vfs::COpenWriteFile file(sFileName,true,true); return writeToFile( &file.file() ); } - catch(CBasicException& ex) + catch(vfs::Exception& ex) { - logException(ex); + SGP_ERROR(ex.what()); vfs::CFile file(sFileName); if(file.openWrite(true,true)) { @@ -70,9 +79,9 @@ bool XMLWriter::writeToFile(vfs::tWritableFile* pFile) pFile->write(str.c_str(), str.length() * sizeof(std::string::value_type)); return true; } - catch(CBasicException& ex) + catch(vfs::Exception& ex) { - logException(ex); + SGP_ERROR(ex.what()); return false; } } diff --git a/Utils/XMLWriter.h b/Utils/XMLWriter.h index 7ca99930..0825b03e 100644 --- a/Utils/XMLWriter.h +++ b/Utils/XMLWriter.h @@ -2,8 +2,8 @@ #define _XMLWRITER_H_ #include "FileMan.h" -#include "VFS/Interface/vfs_file_interface.h" -#include "utf8string.h" +#include +#include #include #include @@ -23,7 +23,7 @@ public: {}; template - void addAttributeToNextValue(utf8string const& attribute, ValueType const& value) + void addAttributeToNextValue(vfs::String const& attribute, ValueType const& value) { std::stringstream temp_buffer; temp_buffer << value; @@ -31,27 +31,28 @@ public: } template - void addValue(utf8string const& key, ValueType const& value) + void addValue(vfs::String const& key, ValueType const& value) { std::string utf8key = key.utf8(); m_ssBuffer << indent() << "<" << utf8key; insertAttributesIntoBuffer(); - m_ssBuffer << "> " << value << " \n"; + m_ssBuffer << ">" << value << "\n"; } template<> - void addValue(utf8string const& key, std::string const& value) + void addValue(vfs::String const& key, std::string const& value) { std::string utf8key = key.utf8(); m_ssBuffer << indent() << "<" << utf8key; insertAttributesIntoBuffer(); - m_ssBuffer << "> " << handleSpecialCharacters(value) << " \n"; + m_ssBuffer << ">" << handleSpecialCharacters(value) << "\n"; } - void addValue(utf8string const& key); - void addComment(utf8string const& comment); + void addValue(vfs::String const& key); + void addComment(vfs::String const& comment); + void addFlag(UINT32 const& flags, UINT32 const& flag, vfs::String strFlag); - void openNode(utf8string const& key); + void openNode(vfs::String const& key); bool closeNode(); bool writeToFile(vfs::Path const& sFileName); diff --git a/Utils/XML_Items.cpp b/Utils/XML_Items.cpp index 684b9ccf..b818f2ce 100644 --- a/Utils/XML_Items.cpp +++ b/Utils/XML_Items.cpp @@ -54,6 +54,7 @@ struct INVTYPE curItem; INVTYPE * curArray; UINT32 maxArraySize; + INT8 curStance; UINT32 currentDepth; UINT32 maxReadDepth; @@ -62,6 +63,9 @@ typedef itemParseData; BOOLEAN localizedTextOnly; +// HEADROCK HAM 4: Inherits data between stance-based modifiers +void InheritStanceModifiers( itemParseData *pData ); + static void XMLCALL itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) { @@ -86,6 +90,28 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at if ( !localizedTextOnly ) memset(&pData->curItem,0,sizeof(INVTYPE)); + // HEADROCK HAM 4: With the new stance-based variables, it is necessary to set vars to have an impossible + // value. That way when they are later recorded in the item structs, a parent->child inheritence can occur + // for children that do not have data put into them from XML. + // -10000 has been selected to pose as "no value". Modders should never even reduce the value of any of + // these tags below -100 anyway, and although it's not the best solution that's the only one I came up with. + + for (INT8 X = 0; X < 3; X++) + { + pData->curItem.flatbasemodifier[X] = -10000; + pData->curItem.percentbasemodifier[X] = -10000; + pData->curItem.flataimmodifier[X] = -10000; + pData->curItem.percentaimmodifier[X] = -10000; + pData->curItem.percentcapmodifier[X] = -10000; + pData->curItem.percenthandlingmodifier[X] = -10000; + pData->curItem.targettrackingmodifier[X] = -10000; + pData->curItem.percentdropcompensationmodifier[X] = -10000; + pData->curItem.maxcounterforcemodifier[X] = -10000; + pData->curItem.counterforceaccuracymodifier[X] = -10000; + pData->curItem.counterforcefrequencymodifier[X] = -10000; + pData->curItem.aimlevelsmodifier[X] = -10000; + } + pData->maxReadDepth++; //we are not skipping this element } else if(pData->curElement == ELEMENT && @@ -96,6 +122,8 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at strcmp(name, "szBRName") == 0 || strcmp(name, "szBRDesc") == 0 || strcmp(name, "usItemClass") == 0 || + strcmp(name, "nasAttachmentClass") == 0 || + strcmp(name, "nasLayoutClass") == 0 || strcmp(name, "ubClassIndex") == 0 || strcmp(name, "ubCursor") == 0 || strcmp(name, "bSoundType") == 0 || @@ -213,15 +241,68 @@ itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **at strcmp(name, "StealthBonus") == 0 || strcmp(name, "SciFi") == 0 || strcmp(name, "NewInv") == 0 || + strcmp(name, "AttachmentSystem") == 0 || //zilpin: pellet spread patterns externalized in XML strcmp(name, "spreadPattern") == 0 || - strcmp(name, "fFlags") == 0 )) + // HEADROCK HAM 4: new NCTH variables. + strcmp(name, "ScopeMagFactor") == 0 || + strcmp(name, "ProjectionFactor") == 0 || + strcmp(name, "PercentAccuracyModifier") == 0 || + strcmp(name, "RecoilModifierX") == 0 || + strcmp(name, "RecoilModifierY") == 0 || + strcmp(name, "PercentRecoilModifier") == 0 || + + strcmp(name, "fFlags") == 0 )) { pData->curElement = ELEMENT_PROPERTY; //DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("itemStartElementHandle: going into element, name = %s",name) ); pData->maxReadDepth++; //we are not skipping this element } + // HEADROCK HAM 4: New depth: Stance-based variables + else if(pData->curElement == ELEMENT && + (strcmp(name, "STAND_MODIFIERS") == 0 || + strcmp(name, "CROUCH_MODIFIERS") == 0 || + strcmp(name, "PRONE_MODIFIERS") == 0)) + { + pData->curElement = ELEMENT_SUBLIST; + + // Set current stance. + if (strcmp(name, "STAND_MODIFIERS") == 0) + { + pData->curStance = 0; + } + else if (strcmp(name, "CROUCH_MODIFIERS") == 0) + { + pData->curStance = 1; + } + else // prone + { + pData->curStance = 2; + } + + pData->maxReadDepth++; + } + + // HEADROCK HAM 4: Read stance-based variables + else if(pData->curElement == ELEMENT_SUBLIST && + (strcmp(name, "FlatBase") == 0 || + strcmp(name, "PercentBase") == 0 || + strcmp(name, "FlatAim") == 0 || + strcmp(name, "PercentAim") == 0 || + strcmp(name, "PercentCap") == 0 || + strcmp(name, "PercentHandling") == 0 || + strcmp(name, "PercentTargetTrackingSpeed") == 0 || + strcmp(name, "PercentDropCompensation") == 0 || + strcmp(name, "PercentMaxCounterForce") == 0 || + strcmp(name, "PercentCounterForceAccuracy") == 0 || + strcmp(name, "PercentCounterForceFrequency") == 0 || + strcmp(name, "AimLevels") == 0)) + { + pData->curElement = ELEMENT_SUBLIST_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } pData->szCharData[0] = '\0'; } @@ -264,7 +345,12 @@ itemEndElementHandle(void *userData, const XML_Char *name) if(pData->curItem.uiIndex < pData->maxArraySize) { if ( pData->curItem.usItemClass != 0 ) + { + // HEADROCK HAM 4: Inherit stance-base modifiers upwards. + InheritStanceModifiers( pData ); + pData->curArray[pData->curItem.uiIndex] = pData->curItem; //write the item into the table + } else if ( sizeof(pData->curItem.szItemName)>0 && localizedTextOnly ) { wcscpy(pData->curArray[pData->curItem.uiIndex].szItemName,pData->curItem.szItemName); @@ -429,6 +515,16 @@ itemEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curItem.usItemClass = (UINT32) atol(pData->szCharData); } + else if(strcmp(name, "nasAttachmentClass") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.nasAttachmentClass = (UINT32) atol(pData->szCharData); + } + else if(strcmp(name, "nasLayoutClass") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.nasLayoutClass = (UINT32) atol(pData->szCharData); + } else if(strcmp(name, "ubClassIndex") == 0) { pData->curElement = ELEMENT; @@ -767,6 +863,11 @@ itemEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curItem.newinv = (BOOLEAN) atol(pData->szCharData); } + else if(strcmp(name, "AttachmentSystem") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.ubAttachmentSystem = (UINT8) atol(pData->szCharData); + } else if(strcmp(name, "HideMuzzleFlash") == 0) { pData->curElement = ELEMENT; @@ -840,7 +941,12 @@ itemEndElementHandle(void *userData, const XML_Char *name) else if(strcmp(name, "DefaultAttachment") == 0) { pData->curElement = ELEMENT; - pData->curItem.defaultattachment = (UINT16) atol(pData->szCharData); + for(UINT8 cnt = 0; cnt < MAX_DEFAULT_ATTACHMENTS; cnt++){ + if(pData->curItem.defaultattachments[cnt] == 0){ + pData->curItem.defaultattachments[cnt] = (UINT16) atol(pData->szCharData); + break; + } + } } else if(strcmp(name, "BrassKnuckles") == 0) { @@ -1028,12 +1134,118 @@ itemEndElementHandle(void *userData, const XML_Char *name) pData->curItem.bestlaserrange = (INT16) atol(pData->szCharData); } //zilpin: pellet spread patterns externalized in XML - else if(strcmp(name, "spreadPattern") == 0) + if(strcmp(name, "spreadPattern") == 0) { pData->curElement = ELEMENT; pData->curItem.spreadPattern = FindSpreadPatternIndex( pData->szCharData ); } + ////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Read new variables from XML + else if(strcmp(name, "ScopeMagFactor") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.scopemagfactor = (FLOAT) atof(pData->szCharData); + } + else if(strcmp(name, "ProjectionFactor") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.projectionfactor = (FLOAT) atof(pData->szCharData); + } + else if(strcmp(name, "PercentAccuracyModifier") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.percentaccuracymodifier = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "RecoilModifierX") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.RecoilModifierX = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "RecoilModifierY") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.RecoilModifierY = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentRecoilModifier") == 0) + { + pData->curElement = ELEMENT; + pData->curItem.PercentRecoilModifier = (INT16) atol(pData->szCharData); + } + + + ////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Read stance-based variables and put them into the right place. + else if(strcmp(name, "FlatBase") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.flatbasemodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentBase") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.percentbasemodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "FlatAim") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.flataimmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentAim") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.percentaimmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentCap") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.percentcapmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentHandling") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.percenthandlingmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentTargetTrackingSpeed") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.targettrackingmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentDropCompensation") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.percentdropcompensationmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentMaxCounterForce") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.maxcounterforcemodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentCounterForceAccuracy") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.counterforceaccuracymodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "PercentCounterForceFrequency") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.counterforcefrequencymodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "AimLevels") == 0) + { + pData->curElement = ELEMENT_SUBLIST; + pData->curItem.aimlevelsmodifier[pData->curStance] = (INT16) atol(pData->szCharData); + } + + ////////////////////////////////////////////////////////////////// + // HEADROCK HAM 4: Close opened Stance Tags. + else if(strcmp(name, "STAND_MODIFIERS") == 0 || + strcmp(name, "CROUCH_MODIFIERS") == 0 || + strcmp(name, "PRONE_MODIFIERS") == 0) + { + pData->curElement = ELEMENT; + } + pData->maxReadDepth--; } @@ -1425,6 +1637,8 @@ BOOLEAN WriteItemStats() FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].usItemClass); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].nasAttachmentClass); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].nasLayoutClass); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].ubClassIndex); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].ubCursor); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].bSoundType); @@ -1468,6 +1682,7 @@ BOOLEAN WriteItemStats() FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].biggunlist ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].scifi ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].newinv ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].ubAttachmentSystem ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].notineditor ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].defaultundroppable ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].unaerodynamic ); @@ -1514,7 +1729,12 @@ BOOLEAN WriteItemStats() FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].discardedlauncheritem ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].rocketrifle); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].cannon); - FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].defaultattachment ); + + for(UINT8 cnt2 = 0; cnt2 < MAX_DEFAULT_ATTACHMENTS; cnt2++){ + if(Item[cnt].defaultattachments[cnt2] != 0){ + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].defaultattachments[cnt2] ); + } + } FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].brassknuckles ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].crowbar ); @@ -1572,6 +1792,57 @@ BOOLEAN WriteItemStats() FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].fingerprintid ); FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].ammocrate ); + // HEADROCK HAM 4: Print out new values + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].scopemagfactor ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].projectionfactor ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].percentaccuracymodifier ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].RecoilModifierX ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].RecoilModifierY ); + FilePrintf(hFile,"\t\t%d\r\n", Item[cnt].PercentRecoilModifier ); + + // HEADROCK HAM 4: Print out stance-based values + FilePrintf(hFile,"\t\t\r\n"); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].flatbasemodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentbasemodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].flataimmodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentcapmodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percenthandlingmodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].targettrackingmodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentdropcompensationmodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].maxcounterforcemodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].counterforceaccuracymodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].counterforcefrequencymodifier[0] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].aimlevelsmodifier[0] ); + FilePrintf(hFile,"\t\t\r\n"); + + FilePrintf(hFile,"\t\t\r\n"); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].flatbasemodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentbasemodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].flataimmodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentcapmodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percenthandlingmodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].targettrackingmodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentdropcompensationmodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].maxcounterforcemodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].counterforceaccuracymodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].counterforcefrequencymodifier[1] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].aimlevelsmodifier[1] ); + FilePrintf(hFile,"\t\t\r\n"); + + FilePrintf(hFile,"\t\t\r\n"); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].flatbasemodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentbasemodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].flataimmodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentcapmodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percenthandlingmodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].targettrackingmodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].percentdropcompensationmodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].maxcounterforcemodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].counterforceaccuracymodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].counterforcefrequencymodifier[2] ); + FilePrintf(hFile,"\t\t\t%d\r\n", Item[cnt].aimlevelsmodifier[2] ); + FilePrintf(hFile,"\t\t\r\n"); + FilePrintf(hFile,"\t\r\n"); } FilePrintf(hFile,"\r\n"); @@ -1580,3 +1851,76 @@ BOOLEAN WriteItemStats() return( TRUE ); } + +// HEADROCK HAM 4: This function runs just before the items are written into the item array. It causes all stance bonuses +// to inherit their properties from the bonus "above" them, as long as they don't already have their own value defined. +void InheritStanceModifiers( itemParseData *pData ) +{ + + // Create a two-dimensional temp array to hold all the data about stance modifiers. + INT16 TempArray[12][3]; + INT8 count = 0; + INT8 arrcount = 0; + + // Copy stance modifier data into this array + for (count = 0; count < 3; count++) + { + TempArray[0][count] = pData->curItem.flatbasemodifier[count]; + TempArray[1][count] = pData->curItem.percentbasemodifier[count]; + TempArray[2][count] = pData->curItem.flataimmodifier[count]; + TempArray[3][count] = pData->curItem.percentaimmodifier[count]; + TempArray[4][count] = pData->curItem.percentcapmodifier[count]; + TempArray[5][count] = pData->curItem.percenthandlingmodifier[count]; + TempArray[6][count] = pData->curItem.targettrackingmodifier[count]; + TempArray[7][count] = pData->curItem.percentdropcompensationmodifier[count]; + TempArray[8][count] = pData->curItem.maxcounterforcemodifier[count]; + TempArray[9][count] = pData->curItem.counterforceaccuracymodifier[count]; + TempArray[10][count] = pData->curItem.counterforcefrequencymodifier[count]; + TempArray[11][count] = pData->curItem.aimlevelsmodifier[count]; + } + + for (arrcount = 0; arrcount < 12; arrcount++) + { + if (TempArray[arrcount][2] == -10000) + { + if (TempArray[arrcount][1] == -10000) + { + TempArray[arrcount][1] = TempArray[arrcount][0]; + TempArray[arrcount][2] = TempArray[arrcount][0]; + } + else + { + TempArray[arrcount][2] = TempArray[arrcount][1]; + } + } + else if (TempArray[arrcount][1] == -10000) + { + TempArray[arrcount][1] = TempArray[arrcount][0]; + } + for (INT8 X = 0; X < 3; X++) + { + if (TempArray[arrcount][X] == -10000) + { + TempArray[arrcount][X] = 0; + } + } + } + + // Copy stance modifier data back out of the temp array + for (count = 0; count < 3; count++) + { + pData->curItem.flatbasemodifier[count] = TempArray[0][count]; + pData->curItem.percentbasemodifier[count] = TempArray[1][count]; + pData->curItem.flataimmodifier[count] = TempArray[2][count]; + pData->curItem.percentaimmodifier[count] = TempArray[3][count]; + pData->curItem.percentcapmodifier[count] = TempArray[4][count]; + pData->curItem.percenthandlingmodifier[count] = TempArray[5][count]; + pData->curItem.targettrackingmodifier[count] = TempArray[6][count]; + pData->curItem.percentdropcompensationmodifier[count] = TempArray[7][count]; + pData->curItem.maxcounterforcemodifier[count] = TempArray[8][count]; + pData->curItem.counterforceaccuracymodifier[count] = TempArray[9][count]; + pData->curItem.counterforcefrequencymodifier[count] = TempArray[10][count]; + pData->curItem.aimlevelsmodifier[count] = TempArray[11][count]; + } + +} diff --git a/Utils/XML_Parser.h b/Utils/XML_Parser.h index def484fa..4c2a9dbe 100644 --- a/Utils/XML_Parser.h +++ b/Utils/XML_Parser.h @@ -2,15 +2,61 @@ #define _XML_PARSER_H_ #include "expat.h" -#include "XML.h" +//#include "XML.h" +#include + +template +class LazyCondition +{ +public: + typedef bool (*cond_fct)(OperandType op1, OperandType op2); + LazyCondition(OperandType op1, OperandType op2, cond_fct fct) + : _op1(op1), _op2(op2), _fct(fct) + {}; + bool check() + { + return _fct(_op1,_op2); + } +private: + OperandType _op1; + OperandType _op2; + cond_fct _fct; +}; + +inline bool lazyStrEqual(const char* str1, const char* str2) +{ + return strcmp(str1,str2) == 0; +} + +class LazyStrEqual : public LazyCondition +{ +public: + LazyStrEqual(const char* str1, const char* str2) + : LazyCondition(str1, str2, lazyStrEqual) + {}; +}; + +class LazyTrue : public LazyCondition +{ + static bool True(bool a, bool b){return true;}; +public: + LazyTrue() : LazyCondition(true,true,LazyTrue::True) {}; +}; + class IXMLParser { public: const XML_Char* ElementName; public: - IXMLParser(const XML_Char *element_name, XML_Parser &parser, IXMLParser* caller=NULL) - : _parser(parser), _caller(caller), ElementName(element_name) {}; + IXMLParser(const XML_Char *element_name, XML_Parser* parser, IXMLParser* caller=NULL) + : _caller(caller), ElementName(element_name) + { + if(parser) + { + this->setParser(parser); + } + }; ~IXMLParser() {}; /** @@ -35,9 +81,9 @@ public: } void grabParser() { - XML_SetUserData(_parser,this); - XML_SetElementHandler(_parser, IXMLParser::onStartCallback, IXMLParser::onEndCallback); - XML_SetCharacterDataHandler(_parser, IXMLParser::onTextCallback); + XML_SetUserData(*_parser,this); + XML_SetElementHandler(*_parser, IXMLParser::onStartCallback, IXMLParser::onEndCallback); + XML_SetCharacterDataHandler(*_parser, IXMLParser::onTextCallback); } /** @@ -48,8 +94,88 @@ public: virtual void onEndElement(const XML_Char* name) {}; virtual void onTextElement(const XML_Char *str, int len) - {}; + { + }; + + class Attributes + { + public: + Attributes(const XML_Char** atts) : _atts(atts) {}; + XML_Char const* get(const XML_Char* attr_name) const + { + const XML_Char** atts = _atts; + while(*atts) + { + if(strcmp(*atts++,attr_name) == 0) + { + return *atts; + } + atts++; + } + return ""; + } + bool getLong(const XML_Char* attr_name, long& attr) const + { + XML_Char const* result = this->get(attr_name); + if( strcmp(result,"") != 0) + { + attr = (int)atol(result); + return true; + } + return false; + } + bool getDouble(const XML_Char* attr_name, double &attr) const + { + XML_Char const* result = this->get(attr_name); + if( strcmp(result,"") != 0) + { + attr = atof(result); + return true; + } + return false; + } + private: + const XML_Char** _atts; + }; + + template + class ParserState + { + public: + ParserState(const StateType start_state) + : _my_state(start_state) + {}; + + StateType const& state() + { + return _my_state; + } + + template + bool stateTransition(const StateType current_state, LazyCondition condition, const StateType next_state) + { + if(_my_state == current_state && condition.check() ) + { + _my_state = next_state; + return true; + } + return false; + } + private: + StateType _my_state; + }; + + XML_Parser& getParser() + { + return *_parser; + } protected: + void setParser(XML_Parser* parser) + { + _parser = parser; + // grabParser(); ??? + } + XML_Char const* getAttribute(const XML_Char* attr_name, const XML_Char** atts) { while(*atts) @@ -85,12 +211,12 @@ protected: int getCurrentLineNumber() { - return XML_GetCurrentLineNumber(this->_parser); + return XML_GetCurrentLineNumber(*this->_parser); } protected: std::string sCharData; - XML_Parser& _parser; + XML_Parser* _parser; IXMLParser* _caller; }; diff --git a/Utils/XML_SenderNameList.cpp b/Utils/XML_SenderNameList.cpp new file mode 100644 index 00000000..f181ca7d --- /dev/null +++ b/Utils/XML_SenderNameList.cpp @@ -0,0 +1,174 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" + #include "Text.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + SENDER_NAMES_VALUES curSenderNameList; + SENDER_NAMES_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef senderNameListParseData; + +BOOLEAN SenderNameList_TextOnly; + +static void XMLCALL +senderNameListStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + senderNameListParseData * pData = (senderNameListParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "SENDER_LIST") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "NAME") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "uiIndex") == 0 || + strcmp(name, "Name") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; + +} + +static void XMLCALL +senderNameListCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + senderNameListParseData * pData = (senderNameListParseData *)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 +senderNameListEndElementHandle(void *userData, const XML_Char *name) +{ + senderNameListParseData * pData = (senderNameListParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading + { + if(strcmp(name, "SENDER_LIST") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "NAME") == 0) + { + pData->curElement = ELEMENT_LIST; + + wcscpy(pSenderNameList[pData->curSenderNameList.uiIndex], pData->curSenderNameList.Name); + + } + else if(strcmp(name, "uiIndex") == 0) + { + pData->curElement = ELEMENT; + pData->curSenderNameList.uiIndex = (UINT16) atol(pData->szCharData); + } + else if(strcmp(name, "Name") == 0 ) + { + pData->curElement = ELEMENT; + + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curSenderNameList.Name, sizeof(pData->curSenderNameList.Name)/sizeof(pData->curSenderNameList.Name[0]) ); + pData->curSenderNameList.Name[sizeof(pData->curSenderNameList.Name)/sizeof(pData->curSenderNameList.Name[0]) - 1] = '\0'; + } + pData->maxReadDepth--; + } + + pData->currentDepth--; +} + + + + +BOOLEAN ReadInSenderNameList(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + senderNameListParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading SenderNameList.xml" ); + + SenderNameList_TextOnly = localizedVersion; + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( localizedVersion ); + + 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, senderNameListStartElementHandle, senderNameListEndElementHandle); + XML_SetCharacterDataHandler(parser, senderNameListCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + XML_SetUserData(parser, &pData); + + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in SenderNameList.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 ); +} \ No newline at end of file diff --git a/Utils/XML_SenderNameList.h b/Utils/XML_SenderNameList.h new file mode 100644 index 00000000..3cca54e1 --- /dev/null +++ b/Utils/XML_SenderNameList.h @@ -0,0 +1,18 @@ +#ifndef _XML_SENDERNAMELIST_H +#define _XML_SENDERNAMELIST_H + +#include "Types.h" + +#define MAX_SENDER_NAMES_CHARS 128 + +typedef struct +{ + UINT16 uiIndex; + CHAR16 Name[MAX_SENDER_NAMES_CHARS]; + +} SENDER_NAMES_VALUES; + +extern SENDER_NAMES_VALUES zSenderNameList[500]; + + +#endif diff --git a/Utils/XML_auto_parse.h b/Utils/XML_auto_parse.h new file mode 100644 index 00000000..78e4f57c --- /dev/null +++ b/Utils/XML_auto_parse.h @@ -0,0 +1,258 @@ +#ifndef XML_AUTO_PARSE_H +#define XML_AUTO_PARSE_H + +#include +#include +#include "XML_Parser.h" +#include +#include +#include + +#if !defined(TRUE) +# define TRUE 1 +#endif + +namespace xml_auto +{ + class ITransition + { + public: + void Register() { _ref_count++; } + void UnRegister() { if(_ref_count > 0) _ref_count--; } + virtual void Delete() + { + UnRegister(); + if(_ref_count == 0) delete this; + } + virtual void enter(const char* tag_name, IXMLParser::Attributes const& atts) {}; + virtual void leave(const char* tag_name, std::string const& data) {}; + virtual bool handleText() {return false;}; + protected: + ITransition() : _ref_count(0) {}; + ~ITransition() {}; + private: + int _ref_count; + }; + + template + class TTransition : public ITransition + { + public: + typedef typename T::States state_t; + const state_t StartPoint, EndPoint; + T* P_DATA; // parser data + protected: + TTransition(const state_t start, const state_t end, T* p_data = NULL) + : StartPoint(start), EndPoint(end), P_DATA(p_data) + { + Register(); + }; + virtual ~TTransition() + {}; + }; + + template + class TBaseStructure + { + public: + typedef TTransition transition_t; + typedef States state_t; + private: + // map : transition trigger (string) -> pointing at next state + typedef std::map tr_state_t; + + // map : state -> outgoing transitions (of that state) + typedef std::map tr_map_t; + public: + transition_t* getTransition(state_t current_state, std::string const& str) + { + typename tr_map_t::iterator it = _state_tr_map.find(current_state); + if(it != _state_tr_map.end()) + { + typename tr_state_t::iterator trit = it->second.find(str); + if( trit != it->second.end() ) + { + return trit->second; + } + else if( (trit=it->second.find("")) != it->second.end() ) + { + return trit->second; + } + else + { + return NULL; + } + } + return NULL; + } + ~TBaseStructure() + { + typename tr_map_t::iterator it = _state_tr_map.begin(); + for(; it != _state_tr_map.end(); ++it) + { + typename tr_state_t::iterator trit = it->second.begin(); + for(;trit != it->second.end(); trit++) + { + trit->second->Delete(); + } + } + } + protected: + void newTransition(std::string const& tag, transition_t* tr) + { + _state_tr_map[tr->StartPoint][tag] = tr; + _state_tr_map[tr->EndPoint][tag] = tr; + // we use one transition twice -> increment ref counter + tr->Register(); + } + + tr_map_t _state_tr_map; + }; + + template + class TGenericXMLParser : public IXMLParser + { + public: + typedef TBaseStructure struct_t; + TGenericXMLParser(struct_t* base, IXMLParser* caller = NULL) + : IXMLParser("",NULL,caller), m_base(base), m_state(T::STATE_NONE) + { + parser = XML_ParserCreate(NULL); + setParser(&parser); + }; + ~TGenericXMLParser() + { + if(parser) + { + XML_ParserFree(parser); + } + } + virtual void onStartElement(const XML_Char* name, const XML_Char** atts) + { + typename struct_t::transition_t* tr = m_base->getTransition(m_state.state(), name); + if(tr && m_state.stateTransition(tr->StartPoint, LazyTrue(), tr->EndPoint)) + { + m_tr_stack.push(tr); + tr->enter(name, IXMLParser::Attributes(atts)); + } + sCharData = ""; + } + virtual void onEndElement(const XML_Char* name) + { + typename struct_t::transition_t* tr = m_base->getTransition(m_state.state(), name); + if(tr && m_state.stateTransition(tr->EndPoint, LazyTrue(), tr->StartPoint)) + { + SGP_THROW_IFFALSE(tr == m_tr_stack.top(), + _BS(L"Transition associated to tag [") << name << L"] doesn't correspond to saved transition" << _BS::wget); + tr->leave(name, sCharData); + m_tr_stack.pop(); + } + }; + virtual void onTextElement(const XML_Char *str, int len) + { + if(!m_tr_stack.empty()) + { + typename struct_t::transition_t* tr = m_tr_stack.top(); + if(tr && tr->handleText()) + { + sCharData.append(str,len); + } + } + }; + + void parseBuffer(vfs::Byte* buffer, vfs::size_t length) + { + this->grabParser(); + XML_Parser& _parser = this->getParser(); + if(!XML_Parse(_parser, buffer, length, TRUE)) + { + std::wstringstream wss; + wss << L"XML Parser Error : " + << vfs::String::as_utf16(XML_ErrorString(XML_GetErrorCode(_parser))) + << L" in line " + << XML_GetCurrentLineNumber(_parser); + SGP_THROW(wss.str().c_str()); + } + } + + void parseFile(vfs::tReadableFile* pFile) + { + if(!pFile) + { + return; + } + vfs::COpenReadFile rfile(pFile); + + vfs::size_t size = rfile->getSize(); + std::vector buffer(size+1); + + SGP_TRYCATCH_RETHROW( rfile->read(&buffer[0],size), L"" ); + buffer[size] = 0; + + SGP_TRYCATCH_RETHROW( this->parseBuffer(&buffer[0], size), + _BS(L"error in file : ") << pFile->getPath() << _BS::wget); + } + + void parseFile(vfs::Path const& sFile) + { + vfs::tReadableFile* file = getVFS()->getReadFile(sFile); + SGP_THROW_IFFALSE(file, _BS(L"Could not find file : ") << sFile << _BS::wget); + + SGP_TRYCATCH_RETHROW( this->parseFile(file), + _BS(L"error in file : ") << sFile << _BS::wget); + } + + private: + XML_Parser parser; + + typedef IXMLParser::ParserState ParserState_t; + struct_t* m_base; + + typedef std::stack tr_stack_t; + tr_stack_t m_tr_stack; + ParserState_t m_state; + }; +} + +#define PARSER_CLASS_MACRO(class_name, states) \ + class class_name : public states, public xml_auto::TBaseStructure + +#define PURE_TRANSITION(class_name, main_type) \ + class class_name : public xml_auto::TTransition{ \ + public: \ + typedef main_type::States state_t; \ + typedef xml_auto::TTransition super_t; \ + class_name(const state_t start, const state_t end) : super_t(start, end) \ + {} \ + virtual ~class_name() \ + {} \ + }; + +#define DEFINE_TRANSITION(class_name, base_type, handle_text) \ + class class_name : public xml_auto::TTransition{ \ + public: \ + typedef xml_auto::TTransition super_t; \ + typedef base_type::States state_t; \ + class_name(const state_t start, const state_t end, base_type* base_obj) : super_t(start,end,base_obj) {}; \ + virtual ~class_name() {}; \ + virtual bool handleText() {return handle_text;}; \ + +#define DEFINE_TRANSITION_WDATA(class_name, base_type, handle_text, tr_data_type) \ + class class_name : public xml_auto::TTransition{ \ + tr_data_type T_DATA; \ + public: \ + typedef xml_auto::TTransition super_t; \ + typedef base_type::States state_t; \ + class_name(const state_t start, const state_t end, base_type* base_obj) : super_t(start,end,base_obj) {}; \ + virtual ~class_name() {}; \ + virtual bool handleText() {return handle_text;}; \ + +#define FINISH_TRANSITION }; + +#define TRANSITION_ENTER virtual void enter(const char* tag_name, IXMLParser::Attributes const& atts) +#define TRANSITION_LEAVE virtual void leave(const char* tag_name, std::string const& char_data) + +#define TR_HANDLE(from_state, trigger, to_state, handler_class_type) newTransition((trigger), new handler_class_type((from_state),(to_state),this)); +#define TR_PASS(from_state, trigger, to_state) newTransition((trigger), new NOOP((from_state),(to_state))); + +#endif // XML_AUTO_PARSE_H diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 7a526d72..0e6ef24a 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -1,4 +1,5 @@ -#ifdef PRECOMPILEDHEADERS +//#pragma setlocale("CHINESE") +#ifdef PRECOMPILEDHEADERS #include "Utils All.h" #else #include "Language Defines.h" @@ -109,6 +110,25 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +// TODO.Translate +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Page 1/2", //0 + L"Page 2/2", + + L"Page 1/3", + L"Page 2/3", + L"Page 3/3", + + L"Page 1/1", //5 +}; + +// by Jazz: TODO.Translate +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Development Team", @@ -320,6 +340,20 @@ CHAR16 Message[][STRING_LENGTH] = L"无半自动", L"敌人已经没有装备可偷了!", L"敌人手中没有装备!", +// TODO.Translate + L"%s's desert camouflage has worn off.", + L"%s's desert camouflage has washed off.", + + L"%s's wood camouflage has worn off.", + L"%s's wood camouflage has washed off.", + + L"%s's urban camouflage urban has worn off.", + L"%s's urban camouflage urban has washed off.", + + L"%s's snow camouflage snow has worn off.", + L"%s's snow camouflage has washed off.", + + L"You cannot attach %s to this slot.", }; @@ -472,9 +506,12 @@ STR16 pPersonnelAssignmentStrings[] = L"在途中", L"修理", L"锻炼", - L"训练民兵", + L"训练民兵", + L"Training Mobile Militia", // TODO.Translate L"教练", L"学员", + L"Facility Staff", // TODO.Translate + L"Resting at Facility", // TODO.Translate L"死亡", L"无力中", L"战俘", @@ -514,9 +551,12 @@ STR16 pLongAssignmentStrings[] = L"在途中", L"修理", L"练习", - L"训练民兵", + L"训练民兵", + L"Train Mobiles", // TODO.Translate L"训练队友", L"学员", + L"Staff Facility", // TODO.Translate + L"Rest at Facility", // TODO.Translate L"死亡", L"无力中", L"战俘", @@ -760,6 +800,64 @@ STR16 pPersonnelScreenStrings[] = L"受伤次数: ", // number of times merc has been wounded L"技能: ", L"没有技能", + L"Achievements:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elite soldiers: %d\n", + L"Regular soldiers: %d\n", + L"Admin soldiers: %d\n", + L"Hostile groups: %d\n", + L"Creatures: %d\n", + L"Tanks: %d\n", + L"Others: %d\n", + + L"Mercs: %d\n", + L"Militia: %d\n", + L"Others: %d\n", + + L"Shots fired: %d\n", + L"Missiles fired: %d\n", + L"Grenades thrown: %d\n", + L"Knives thrown: %d\n", + L"Blade attacks: %d\n", + L"Hand to hand attacks: %d\n", + L"Successful hits: %d\n", + + L"Locks picked: %d\n", + L"Locks breached: %d\n", + L"Traps removed: %d\n", + L"Explosives detonated: %d\n", + L"Items repaired: %d\n", + L"Items combined: %d\n", + L"Items stolen: %d\n", + L"Militia trained: %d\n", + L"Mercs bandaged: %d\n", + L"Surgeries made: %d\n", + L"Persons met: %d\n", + L"Sectors discovered: %d\n", + L"Ambushes prevented: %d\n", + L"Quests handled: %d\n", + + L"Tactical battles: %d\n", + L"Autoresolve battles: %d\n", + L"Times retreated: %d\n", + L"Ambushes experienced: %d\n", + L"Hardes battle: %d Enemies\n", + + L"Shot: %d\n", + L"Stabbed: %d\n", + L"Punched: %d\n", + L"Blasted: %d\n", + L"Suffered damages in facilities: %d\n", + L"Surgeries undergoed: %d\n", + L"Facility accidents: %d\n", + + L"Character:", + L"Weakening:", }; @@ -782,12 +880,53 @@ STR16 gzMercSkillText[] = L"刀技", L"狙击手", L"伪装", //JA25: modified - L"伪装(城市)", - L"伪装(沙漠)", - L"伪装(雪地)", + // SANDRO - removed this + //L"伪装(城市)", + //L"伪装(沙漠)", + //L"伪装(雪地)", L"专家", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"No Skill", + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + // Minor traits + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + // second names for major skills + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", + L"More...", +}; +////////////////////////////////////////////////////////// + // This is pop up help text for the options that are available to the merc @@ -1094,11 +1233,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"状态: ", - L"重量 (%s): ", + L"重量: ", L"AP Costs", L"射程: ", // Range L"杀伤力: ", // Damage @@ -1117,35 +1256,41 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // Obviously, THIS SHOULD BE DONE IN ALL LANGUAGES... L"附件:", //14 //ham3.6 L"连发/5AP: ", //15 - L"数量: ", //16 + L"Remaining ammo:", //16 // TODO.Translate + + // TODO.Translate + L"Default:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"射程", - L"杀伤", - L"点射/自动惩罚(越低越好)", - L"连发数量/5AP", L"精度", + L"杀伤", + L"射程", + L"Aiming Levels", + L"精瞄修正", + L"平均最佳激光瞄准距离", + L"消焰", + L"噪音(越低越好)", L"可靠性", L"修理难度", + L"精瞄加成所需最小距离", + L"命中修正", + L"", //12 L"举枪AP", L"单发AP", L"点射AP", - L"连发AP", //10 + L"连发AP", L"上弹AP", L"手动上弹AP", - L"消焰", - L"噪音(越低越好)", - L"命中修正", - L"平均最佳激光瞄准距离", - L"精瞄修正", - L"精瞄加成所需最小距离", + L"", //19 L"两角架修正", + L"连发数量/5AP", + L"点射/自动惩罚(越低越好)", //22 L"投掷AP", //20 L"发射AP", L"捅人AP", @@ -1157,35 +1302,38 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"点射惩罚(越低越好)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"射程", - L"杀伤", - L"点射/连发惩罚(越低越好)", - L"连发数量/5AP", L"精度", - L"可靠性", - L"修理难度", - L"举枪所需AP", - L"单发所需AP", - L"点射所需AP", - L"连发所需AP", //10 - L"上弹所需AP", - L"手动上弹所需AP", - L"命中修正", - L"平均最佳激光瞄准距离", + L"杀伤", + L"射程", + L"Aiming Levels", L"精瞄修正", - L"精瞄加成所需最小距离", + L"平均最佳激光瞄准距离", L"消焰", L"噪音(越低越好)", - L"脚架修正", - L"投掷所需AP", //20 - L"发射所需AP", - L"捅人所需AP", + L"可靠性", + L"修理难度", + L"精瞄加成所需最小距离", + L"命中修正", + L"", //12 + L"举枪AP", + L"单发AP", + L"点射AP", + L"连发AP", + L"上弹AP", + L"手动上弹AP", + L"", //19 + L"两角架修正", + L"连发数量/5AP", + L"点射/自动惩罚(越低越好)", //22 + L"投掷AP", //20 + L"发射AP", + L"捅人AP", L"无法单发!", L"无点射模式!", L"无连发模式!", - L"击打所需AP", + L"格斗AP", L"连发惩罚(越低越好)", L"点射惩罚(越低越好)", }; @@ -1302,6 +1450,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1879,6 +2041,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"显示领空 (|A)", L"显示物品 (|I)", L"显示民兵和敌人 (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1912,7 +2075,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc", @@ -1968,7 +2135,7 @@ STR16 pSenderNameList[] = L"A.I.M.", }; - +*/ // next/prev strings STR16 pTraverseStrings[] = @@ -3256,7 +3423,13 @@ STR16 CharacterInfo[] = L"附加信息", //"Additional Info", // Title for the additional info for the merc's bio L"现役成员", //"Active Members", //20 // Title of the page L"可选装备: ", //"Optional Gear:", // Displays the optional gear cost + L"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"所需医疗保证金", //"MEDICAL deposit required", // If the merc required a medical deposit, this is displayed + L"Kit 1", // Text on Starting Gear Selection Button 1 // TODO.Translate + L"Kit 2", // Text on Starting Gear Selection Button 2 + L"Kit 3", // Text on Starting Gear Selection Button 3 + L"Kit 4", // Text on Starting Gear Selection Button 4 + L"Kit 5", // Text on Starting Gear Selection Button 5 }; @@ -3634,8 +3807,11 @@ STR16 zMarksMapScreenText[] = L"现在没有足够的人愿意加入民兵。", L"%s的民兵已经训练满了。", //"%s is full of militia.", L"佣兵有一份限时的合同。", //"Merc has a finite contract.", - L"佣兵的合同没投保", //"Merc's contract is not insured", + L"佣兵的合同没投保", //"Merc's contract is not insured", L"地图概况",//"Map Overview", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3701,22 +3877,25 @@ STR16 zOptionsToggleText[] = L"显示3D光标", //"Show 3D Cursor", L"显示命中机率", //"Show Chance to Hit on cursor", L"榴弹发射器连发时使用枪击光标", //"GL Burst uses Burst cursor", - L"敌人掉落所有物品", //"Enemies Drop all Items", + L"Allow Enemy Taunts", // Changed from "Enemies Drop all Items" - SANDRO L"允许高仰角榴弹发射", //"High angle Grenade launching", - L"限制额外的瞄准", //"Restrict extra Aim Levels", + L"Allow Real Time Sneaking", // Changed from "Restrict extra Aim Levels" - SANDRO L"按空格键选择下一支小队", //"Space selects next Squad", L"显示物品阴影", //"Show Item Shadow", L"用格数显示武器射程", //"Show Weapon Ranges in Tiles", L"单发曳光弹显示曳光", //"Tracer effect for single shot", L"雨声", //"Rain noises", L"允许乌鸦", //"Allow crows", - L"允许士兵工具提示", // Changed from "Random I.M.P personality" - SANDRO + L"允许士兵工具提示", // Show Soldier Tooltips L"自动存盘", //"Auto save", L"沉默的Skyrider", //"Silent Skyrider", L"降低CPU的使用率", //"Low CPU usage", L"Enhanced Description Box", L"强制回合制模式", // add forced turn mode L"属性进度条", //L"Stat Progress Bars", // Show progress towards stat increase //ham3.6 + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) // TODO.Translate L"--作弊模式选项--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"强制 Bobby Ray 送货", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3735,13 +3914,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"如果你想听到人物对话,打开这个选项。", //Mute Confirmation L"打开或关闭人物的口头确认。", - //Subtitles + //Subtitles L"是否显示对话的文字。", //Key to advance speech @@ -3797,22 +3978,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"当打开时,在光标上显示命中机率。", L"开启该选项时,榴弹发射器点射使用点射的准星", - L"当打开时,死亡的敌人掉落所有的物品。", + L"When ON, enemies will occasionally comment certain actions.", // Changed from Enemies Drop All Items - SANDRO L"当打开时,榴弹发射器允许采用较高仰角发射榴弹。(|Q)", - L"当打开时,狙击步枪以外的枪支最多使用4AP去瞄准。", + L"When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"当打开时,按空格键自动切换到下一小队。(|S|p|a|c|e)", L"开启该选项时,会显示物品阴影", L"当打开时,用格数显示武器射程。", L"当打开时,单发曳光弹也显示曳光。", L"当打开时,下雨时能听到雨水音效。", //"When ON, you will hear rain noises when it is raining.", L"当打开时,允许乌鸦出现。", - L"当启用时,把光标定位在敌人身上并且按下 |A|l|t 键会显示一个提示工具窗口。", // - Changed from random IMP personality - SANDRO + L"当启用时,把光标定位在敌人身上并且按下 |A|l|t 键会显示一个提示工具窗口。", L"当打开时,游戏将在玩家回合后自动存盘", L"当打开时,Skyrider将保持沉默。", L"当打开时,游戏将使用更少的CPU资源。", L"当打开时,将出现物品及武器的“增强描述框”(EDB)。", L"当打开时,且在战术画面内存在敌军时,将一直处于回合制模式直至该地区所有敌军被消灭(可以通过快捷键|C|T|R|L+|S|H|I|F|T+|A|L|T+|T来控制打开或关闭强制回合制模式)", L"当打开时,可显示各属性的成长进度。", // L"When ON, shows character progress towards gaining levels.", //ham3.6 + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"When ON, alternate bullet graphics will be shown when you shoot.", // TODO.Translate L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3837,15 +4021,15 @@ STR16 gzGIOScreenText[] = L"现实", L"科幻", L"金版", - L"物品", + L"Available Arsenal", // changed by SANDRO L"大量武器", - L"少量武器", + L"Reduced", // changed by SANDRO L"难度", L"新手", L"老手", L"专家", L"疯子", - L"确定", + L"Start", // TODO.Translate L"取消", L"额外难度", L"可随时存盘", @@ -3856,11 +4040,42 @@ STR16 gzGIOScreenText[] = L"较多", L"很多", L"囧……多", - L"携行系统", - L"旧", - L"新", + L"Inventory / Attachments", // TODO.Translate + L"NOT USED", + L"NOT USED", L"读取联机游戏", L"游戏初始设置(仅在服务器设置时有效)", + // Added by SANDRO + L"Skill Traits", + L"Old", + L"New", + L"Max IMP Characters", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Enemies Drop All Items", + L"Off", + L"On", + L"Number of Terrorists", + L"Random", + L"All", + L"Secret Weapon Caches", + L"Random", + L"All", + L"Progress Speed of Item Choices", + L"Very Slow", + L"Slow", + L"Normal", + L"Fast", + L"Very Fast", + + // TODO.Translate + L"Old / Old", + L"New / Old", + L"New / New", }; STR16 gzMPJScreenText[] = @@ -3883,44 +4098,98 @@ STR16 gzMPJScreenText[] = L"您必须输入正确的服务器端口,范围1~65535。",//L"You must enter a valid Server Port between 1 and 65535.", }; +// TODO.Translate +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { - L"建立主机",//L"HOST GAME", - L"开始",//L"Start", - L"取消",//L"Cancel", - L"服务器名",//L"Server Name", - L"游戏类型",//L"Game Type", - L"死亡模式",//L"Deathmatch", - L"团队死亡模式",//L"Team Deathmatch", - L"合作模式",//L"Co-operative", - L"最大玩家数",//L"Max Players", - L"小队规模",//L"Squad Size", - L"选择佣兵",//L"Merc Selection", - L"随机佣兵",//L"Random Mercs", - L"已被雇佣",//L"Hired by Player", - L"起始平衡",//L"Starting Balance", - L"可以雇佣相同佣兵",//L"Can Hire Same Merc", + L"HOST GAME", + L"Start", + L"Cancel", + L"Server Name", + L"Game Type", + L"Deathmatch", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", + L"Merc Selection", + L"Merc Hiring", + L"Hired by Player", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"开启Bobby Rays网上商店",//L"Allow Bobby Rays", - L"随机选择起始位置",//L"Randomise Starting Edge", - L"必须输入服务器名",//L"You must enter a server name", - L"最大玩家数必须在2-4之间",//L"Max Players must be between 2 and 4", - L"队伍大小必须在1-6之间",//L"Squad size must be between 1 and 6", - L"当日时间",//L"Time of Day", - L"当日时间必须是24小时制 (HH:MM)",//L"Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm", - L"开始资金必须是整数(最小单位为1美元)" ,//L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , - L"伤害系数",//L"Damage Multiplier", - L"伤害系数必须于0-5之间",//L"Damage Multiplier must be a number between 0 and 5", - L"回合计时器",//L"Turn Timer Multiplier", - L"计时器必须设定在0-200之间",//L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", - L"合作模式中允许平民",//L"Enable Civilians in CO-OP", - L"使用新携行模式(NIV)",//L"Use New Inventory (NIV)", - L"强制执行最大AI敌人数量",//L"Enforce Maximum AI Enemies", - L"同步多人模式终端目录",//L"Sync. MP Clients Directory", - L"同步多人模式目录",//L"MP Sync. Directory", - L"你必须进入一个文件传输目录",//L"You must enter a file transfer directory.", - L"(使用 '/' 代替 '\\' 作为目录分隔符)",//L"(Use '/' instead of '\\' for directory delimiters.)", - L"指定的同步目录不存在。",//L"The specified synchronisation directory does not exist.", + L"Bobby Rays", + L"Sector Starting Edge", + L"You must enter a server name", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", + L"Enable Civilians in CO-OP", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", + L"MP Sync. Directory", + L"You must enter a file transfer directory.", + L"(Use '/' instead of '\\' for directory delimiters.)", + L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4098,8 +4367,8 @@ STR16 pMessageStrings[] = L"日志已经更新。", //"History log updated.", L"榴弹发射器点射时使用准星光标(可以扫射)", L"榴弹发射器连发时使用弹道光标(不可以扫射", //"Grenade Bursts use Trajectory Cursor (Spread fire disabled)", - L"启用物品全掉", //"Drop All Enabled", - L"禁用物品全掉", //"Drop All Disabled", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"榴弹发射器以正常仰角发射榴弹", //"Grenade Launchers fire at standard angles", L"榴弹发射器以较高仰角发射榴弹", //L"Grenade Launchers fire at higher angles", // forced turn mode strings @@ -4112,6 +4381,9 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved.//84 L"客户端", //"Client", + + // TODO.Translate + L"You cannot use the Old Inventory and the New Attachment System at the same time.", }; @@ -4476,7 +4748,7 @@ STR16 gzLateLocalizedString[] = L"%s的陶瓷片已经粉碎了!", //"%s's ceramic plates have been smashed!", L"%s多打了%d发子弹!", //"%s fires %d more rounds than intended!", - L"%s多打了%d发子弹!", //"%s fires %d more round than intended!", + L"%s多打了1发子弹!", //"%s fires %d more round than intended!", }; STR16 gzCWStrings[] = @@ -4527,6 +4799,10 @@ STR16 gzTooltipStrings[] = L"无防弹衣", L"无作战裤", L"|护|甲: %s\n", + // Added - SANDRO + L"%s|Skill 1: %s\n", + L"%s|Skill 2: %s\n", + L"%s|Skill 3: %s\n", }; STR16 New113Message[] = @@ -4555,7 +4831,25 @@ STR16 New113Message[] = L"视野中没有敌人", L"即时潜行模式 关闭", L"即时潜行模式 开启", - L"发现敌人!(按|C|t|r|l|+|x进入回合制)", + L"发现敌人!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s was successful on stealing!", + L"%s had not enough action points to steal all selected items.", + L"Do you want to make surgery on %s before bandaging? (You can heal about %i Health.)", + L"Do you want to make surgery on %s? (You can heal about %i Health.)", + L"Do you wish to make necessary surgeries first? (%i patient(s))", + L"Do you wish to make the surgery on this patient first?", + L"Apply first aid automatically with necessary surgeries or without them?", + L"Surgery on %s finished.", + L"%s is hit in the chest and loses a point of maximum health!", + L"%s is hit in the chest and loses %d points of maximum health!", + L"%s has regained one point of lost %s", + L"%s has regained %d points of lost %s", + L"Your scouting skills prevented you to be ambushed by the enemy!", + L"Thanks to your scouting skills you have successfuly avoided a pack of bloodcats!", + L"%s is hit to groin and falls down in pain!", + ////////////////////////////////////////////////////////////////////////////////////// }; STR16 New113HAMMessage[] = @@ -4588,6 +4882,7 @@ STR16 New113HAMMessage[] = L"维持民兵的资金不足!%d名民兵回老家结婚去了。",// L"Insufficient funds to pay all enlisted militia! %d militia have disbanded and returned home.", }; + // WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends // INFO: Do not replace the ?characters. They indicate the (-> Newline) from the edt files STR16 New113MERCMercMailTexts[] = @@ -4602,6 +4897,43 @@ STR16 New113MERCMercMailTexts[] = L"鉴于Biggins发挥有所提高, 他的价格也同时上涨。 ??Speck T. Kline ?", }; +// TODO.Translate +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"FW from AIM Server: Message from Victor Kolesnikov", + L"You want to talk to me? I have time.", + + // Brain + L"FW from AIM Server: Message from Janno Allik", + L"I am back. Waiting for your call.", + + // Scream + L"FW from AIM Server: Message from Lennart Vilde", + L"Sorry, I was out of office, now I am back.", + + // Henning + L"FW from AIM Server: Message from Henning von Branitz", + L"Back from business. You want my help?", + + // Luc + L"FW from AIM Server: Message from Luc Fabre", + L"Give me a call, if you are interested.", + + // Laura + L"FW from AIM Server: Message from Dr. Laura Colin", + L"I am now available.", + + // Grace + L"FW from AIM Server: Message from Graziella Girelli", + L"Got your message. If you still want me, you know what to do.", + + // Rudolf + L"FW from AIM Server: Message from Rudolf Steiger", + L"Rudolf here. Call me back.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the ?characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4610,6 +4942,25 @@ STR16 MissingIMPSkillsDescriptions[] = L"狙击手: 拥有鹰的眼睛和百步穿杨的枪法!?", // Camouflage L"伪装: 跟你的伪装迷彩比起来,树丛看起来倒象是假的!?", + // SANDRO - new strings for new traits added + // Ranger + L"Ranger: You are the one from Texas deserts, aren't you! ± ", + // Gunslinger + L"Gunslinger: With a handgun or two, you can be as lethal as the Billy Kid! ± ", + // Squadleader + L"Squadleader: Natural leader and boss, you are the big shot no kidding! ± ", + // Technician + L"Technician: Fixing stuff, removing traps, planting bombs, that's your bussiness! ± ", + // Doctor + L"Doctor: You can make a quick surgery with pocket-knife and chewing gum anywhere! ± ", + // Athletics + L"Athletics: Your speed and vitality is on top of possibilities! ± ", + // Bodybuilding + L"Bodybuilding: That big muscular figure which cannot be overlooked is you actually! ± ", + // Demolitions + L"Demolitions: You can blow up a whole city just by common home stuff! ± ", + // Scouting + L"Scouting: Nothing can escape your notice! ± ", }; STR16 NewInvMessage[] = @@ -4675,12 +5026,10 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"坐标值: %d", L"服务器独占模式", - L"手动选择服务器优先级: ('1' - 授权 便携电脑/雇佣) ('2' - 启动/载入 级别) ('3' - 解锁 UI) ('4' - 完成设置)", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", + L"手动选择服务器优先级: ('1' - 授权 便携电脑/雇佣) ('2' - 启动/载入 级别) ('3' - 解锁 UI) ('4' - 完成设置)", L"分区=%s, 最大客户端数=%d, 最大佣兵数=%d, 游戏模式=%d, 同一佣兵=%d, 伤害倍数=%f, 时间前进=%d, 秒/Tic=%d, 取消 BobbyRay=%d, 取消 Aim/Merc 装备=%d, 取消士气=%d, 测试=%d", - // 25 - L"测试与欺骗功能键'9'已被激活。", + L"", L"新建连接: 客户端 #%d - '%S'.", L"队: %d.",//not used any more L"'%s' (客户端 %d - '%S') 已被 '%s' (客户端 %d - '%S' 杀死)", @@ -4732,31 +5081,18 @@ STR16 MPClientMessage[] = L"不能连接到服务器,因为你的版本 %S 和服务器端的版本 %S 不同。", L"你击毙了一个敌人。", L"Cannot start the game, because all teams are the same.", // TODO.Translate -}; - -STR16 MPHelp[] = -{ - // 0 - L"欢迎进入铁血联盟2 v1.13 多人游戏。", - L"帮助按 'F1' ", - L"多人控制(在战略画面)", - L"* 第一次建立 ja2_mp.ini *", - L"'1' - 启动服务器", - // 5 - L"'2' - 连接服务器", - L"'3' - 如果服务器解锁笔记本电脑, 设置好客户端准备战斗", - L"'4' - 退出服务器和客户端", - L"'5' - 显示鼠标坐标(在战术画面)", - L"'7' - 对服务器优先级面板弹出对话框", - // 10 - L"'F2' - 显示二级帮助", - L"了解详情请看自述文件", - L"技巧: (如果 ja2_mp.ini 已建立)", - L"* 确认所以的客户端都有独立的客户端号码 *", - L"* 游戏存储不记录bobby rays订单 *", - // 15 - L"* 避免将对立的佣兵放在一起 *", - L"'F1' - 显示基本帮助", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 // TODO.Translate + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; // TODO.Translate @@ -4843,16 +5179,23 @@ STR16 ChineseSpecString7 = L"%s [%d%%]\n%s %1.1f %s"; // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"下一页你将会选择你所创造的佣兵的特长,请留意你最多能够选择两种特长,当你只选择一种特长时,该特长将会升级成为专家特长。除了电子和双手持枪之外,这两种是没有专家级的,请特别留意。", - L"你也可以选择什么特长也不要,作为补偿,你会得到更多的创造点数可以增加你的佣兵的各项能力数值。", + // For old traits + L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected.", + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels.", + // For new major/minor traits + L"Next stage is about choosing your skill traits according to your proffessional specialization as a mercenary. On first page you can select up to two potential major traits, which mostly represent your main role in a team. While on second page is list of possible minor traits, which represent personal feats.", + L"No more then three choices altogeher are possible. Which means if you choose no major traits, you can then choose three minor traits. If you choose both major traits (or one enhanced), you can then choose only one minor trait...", }; - STR16 sgAttributeSelectionText[] = { L"请 按 照 你 对 自 己 的 感 觉 , 调 整 你 的 各 项 能 力 值 。 各 项 能 力 值 的 最 大 值 为", L"IMP能力值和技能概览。", L"奖励点数 :", L"开始等级", + // New strings for new traits + L"On the next page you are going to specify your physical attributes and skills. As 'attributes' are called: health, dexterity, agility, strength and wisdom. Attributes cannot go lower than %d.", + L"The rest are called 'skills' and unlike attributes skills can be set to zero meaning you have absolutely no proficieny in it.", + L"All scores are set to a minimum at the beginning. Note that certain attributes are set to specific values according to skill traits you have selected. You cannot set those attributes lower than that.", }; STR16 pCharacterTraitBeginIMPStrings[] = @@ -4862,7 +5205,7 @@ STR16 pCharacterTraitBeginIMPStrings[] = L"下面来设定你性格上的缺陷,相信自己做一个诚实的孩子吧!每个人至少都有一种缺陷的。真实反映有助于让你的未来雇主更能了解你的潜力,避免给你安排不利的工作环境。", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"平常", L"友善", @@ -4877,6 +5220,24 @@ STR16 gzIMPCharacterTraitText[]= L"I.M.P. 性格特征", }; +STR16 gzIMPCharacterTraitText[]= +{ + L"Normal", + L"Sociable", + L"Loner", + L"Optimist", + L"Assertive", + L"Intellectual", + L"Primitive", + L"Aggressive", + L"Phlegmatic", + L"Dauntless", + L"Pacifist", + L"Malicious", + L"Show-off", + L"I.M.P. Character Traits", +}; + STR16 gzIMPColorChoosingText[] = { L"I.M.P. 颜色及身型", @@ -4884,6 +5245,7 @@ STR16 gzIMPColorChoosingText[] = L"请选择你喜欢的IMP发色、肤色、服装颜色以及体型。", L"请选择你喜欢的IMP发色、肤色、服装颜色。", L"点选这里佣兵将单手持大枪", + L"\n(Caution: you will need a big strength for this.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -5018,4 +5380,498 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 窗口模式需要一个16bpp或更少的颜色深度。", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Suck this!", + L"Touch this!", + L"Come get some!", + L"You're mine!", + L"Die!", + L"You scared, motherfucker?", + L"This will hurt!", + L"Come on you bastard!", + L"Come on! I don't got all day!", + L"Come to daddy!", + L"You'll be six feet under in no time!", + L"Will send ya home in a pinebox, loser!", + L"Hey, wanna play?", + L"You should have stayed home, bitch.", + L"Sucker!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"We have a barbecue here.", + L"I got a present for ya.", + L"Bam!", + L"Smile!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Catch!", + L"Here ya go!", + L"Pop goes the weasel.", + L"This one's for you.", + L"Muhehe.", + L"Catch this, swine!", + L"I like this.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"I'll get your scalp.", + L"Come to papa.", + L"Show me your guts!", + L"I'll rip you to pieces!", + L"Motherfucker!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"We're in some real shit...", + L"They said join the army. Not for this shit!", + L"I have enough.", + L"Oh my God.", + L"They ain't paying us enough for this.", + L"It's just too much for me.", + L"I'll bring some friends.", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"I heard that!", + L"Who's there?", + L"What was that?", + L"Hey! What the...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"They are here!", + L"Now the fun can start.", + L"I hoped this will never happen.", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Ouch!", + L"Ugh!", + L"This.. hurts!", + L"You fuck!", + L"You will regret.. uhh.. this.", + L"What the..!", + L"Now you have.. pissed me off.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //CHINESE diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index c8c25f3c..f2d0e304 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -1,5 +1,13 @@ -#include "Utils All.h" -#include "Language Defines.h" +//#pragma setlocale("DUTCH") +#ifdef PRECOMPILEDHEADERS + #include "Utils All.h" +#else + #include "Language Defines.h" + #if defined( DUTCH ) + #include "text.h" + #include "Fileman.h" + #endif +#endif //suppress : warning LNK4221: no public symbols found; archive member will be inaccessible void this_is_the_DutchText_public_symbol(void){;} @@ -104,6 +112,25 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +// TODO.Translate +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Page 1/2", //0 + L"Page 2/2", + + L"Page 1/3", + L"Page 2/3", + L"Page 3/3", + + L"Page 1/1", //5 +}; + +// by Jazz: TODO.Translate +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Development Team", @@ -308,6 +335,20 @@ CHAR16 Message[][STRING_LENGTH] = L"no semi auto", L"The enemy has no more items to steal!", L"The enemy has no item in its hand!", +// TODO.Translate + L"%s's desert camouflage has worn off.", + L"%s's desert camouflage has washed off.", + + L"%s's wood camouflage has worn off.", + L"%s's wood camouflage has washed off.", + + L"%s's urban camouflage urban has worn off.", + L"%s's urban camouflage urban has washed off.", + + L"%s's snow camouflage snow has worn off.", + L"%s's snow camouflage has washed off.", + + L"You cannot attach %s to this slot.", }; @@ -461,8 +502,11 @@ STR16 pPersonnelAssignmentStrings[] = L"Repareer", // repairing L"Oefenen", // training themselves L"Militie", // training a town to revolt + L"Training Mobile Militia", // TODO.Translate L"Trainer", // training a teammate - L"Student", // being trained by someone else + L"Student", // being trained by someone else + L"Facility Staff", // TODO.Translate + L"Resting at Facility", // TODO.Translate L"Dood", // dead L"Uitgesc.", // abbreviation for incapacitated L"POW", // Prisoner of war - captured @@ -502,9 +546,12 @@ STR16 pLongAssignmentStrings[] = L"Onderweg", // in transit - abbreviated form L"Repareer", // repairing L"Oefenen", // training themselves - L"Militie", // training a town to revolt + L"Militie", // training a town to revolt + L"Train Mobiles", // TODO.Translate L"Trainer", // training a teammate - L"Student", // being trained by someone else + L"Student", // being trained by someone else + L"Staff Facility", // TODO.Translate + L"Rest at Facility", // TODO.Translate L"Dood", // dead L"Uitgesc.", // abbreviation for incapacitated L"POW", // Prisoner of war - captured @@ -748,6 +795,63 @@ STR16 pPersonnelScreenStrings[] = L"Keren Gewond:", // number of times merc has been wounded L"Vaardigheden:", L"Vaardigheden:", + L"Achievements:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elite soldiers: %d\n", + L"Regular soldiers: %d\n", + L"Admin soldiers: %d\n", + L"Hostile groups: %d\n", + L"Creatures: %d\n", + L"Tanks: %d\n", + L"Others: %d\n", + + L"Mercs: %d\n", + L"Militia: %d\n", + L"Others: %d\n", + + L"Shots fired: %d\n", + L"Missiles fired: %d\n", + L"Grenades thrown: %d\n", + L"Knives thrown: %d\n", + L"Blade attacks: %d\n", + L"Hand to hand attacks: %d\n", + L"Successful hits: %d\n", + + L"Locks picked: %d\n", + L"Locks breached: %d\n", + L"Traps removed: %d\n", + L"Explosives detonated: %d\n", + L"Items repaired: %d\n", + L"Items combined: %d\n", + L"Items stolen: %d\n", + L"Militia trained: %d\n", + L"Mercs bandaged: %d\n", + L"Surgeries made: %d\n", + L"Persons met: %d\n", + L"Sectors discovered: %d\n", + L"Ambushes prevented: %d\n", + L"Quests handled: %d\n", + + L"Tactical battles: %d\n", + L"Autoresolve battles: %d\n", + L"Times retreated: %d\n", + L"Ambushes experienced: %d\n", + L"Hardes battle: %d Enemies\n", + + L"Shot: %d\n", + L"Stabbed: %d\n", + L"Punched: %d\n", + L"Blasted: %d\n", + L"Suffered damages in facilities: %d\n", + L"Surgeries undergoed: %d\n", + L"Facility accidents: %d\n", + + L"Character:", + L"Weakening:", }; @@ -770,12 +874,53 @@ STR16 gzMercSkillText[] = L"Mesworp", L"Sniper", L"Camouflaged", - L"Camouflage (Urban)", - L"Camouflage (Desert)", - L"Camouflage (Snow)", + // SANDRO - removed this + //L"Camouflage (Urban)", + //L"Camouflage (Desert)", + //L"Camouflage (Snow)", L"(Expert)", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"No Skill", + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + // Minor traits + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + // second names for major skills + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", + L"More...", +}; +////////////////////////////////////////////////////////// + // This is pop up help text for the options that are available to the merc @@ -1082,11 +1227,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Status:", - L"Gewicht (%s):", + L"Gewicht:", L"AP Costs", L"Afst:", // Range L"Sch:", // Damage @@ -1103,35 +1248,41 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L"Attachments:", //14 // TODO.Translate L"AUTO/5:", //15 - L"Amount:", //16 + L"Remaining ammo:", //16 // TODO.Translate + + // TODO.Translate + L"Default:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (Lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"Flash Suppression", - L"Loudness (Lower is better)", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", + L"", //19 L"Bipod Modifier", + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 L"APs to Throw", L"APs to Launch", L"APs to Stab", @@ -1143,28 +1294,31 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Burst Penalty (Lower is better)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (Lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", - L"Flash Suppression", - L"Loudness (Lower is better)", + L"", //19 L"Bipod Modifier", + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 L"APs to Throw", L"APs to Launch", L"APs to Stab", @@ -1288,6 +1442,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1865,6 +2033,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"Toon Luchtruim (|A)", L"Toon |Items", L"Toon Milities & Vijanden (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1898,7 +2067,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc", @@ -1953,7 +2126,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings @@ -2299,7 +2472,7 @@ STR16 pImpButtonText[] = L"BEGIN", // begin profiling ("BEGIN") L"Persoonlijkheid", // personality section ("Personality") L"Eigenschappen", // personal stats/attributes section ("Attributes") - L"Appearance", // changed from portrait - SANDRO + L"Appearance", // changed from portrait L"Stem %d", // the voice selection ("Voice %d") L"OK", // done profiling ("Done") L"Opnieuw", // start over profiling ("Start Over") @@ -2320,12 +2493,12 @@ STR16 pImpButtonText[] = L"Registratie", // the IMP site registry..when name and gender is selected L"Analyseren", // analyzing your profile results L"OK", - L"Character", // Change from "Voice" - SANDRO + L"Character", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO + // These texts have been also slightly changed L"With your character traits chosen, it is time to select your skills.", L"To complete the process, select your attributes.", L"To commence actual profiling, select portrait, voice and colors.", @@ -3241,7 +3414,13 @@ STR16 CharacterInfo[] = L"Extra Info", // Title for the additional info for the merc's bio L"Actieve Leden", //20 // Title of the page L"Aanv. Uitrusting:", // Displays the optional gear cost + L"gear", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"MEDISCHE aanbetaling nodig", // If the merc required a medical deposit, this is displayed + L"Uitrusting 1", // Text on Starting Gear Selection Button 1 // TODO.Translate + L"Uitrusting 2", // Text on Starting Gear Selection Button 2 + L"Uitrusting 3", // Text on Starting Gear Selection Button 3 + L"Uitrusting 4", // Text on Starting Gear Selection Button 4 + L"Uitrusting 5", // Text on Starting Gear Selection Button 5 }; @@ -3621,6 +3800,9 @@ STR16 zMarksMapScreenText[] = L"Huurling heeft eindig contract.", L"Contract Huurling is niet verzekerd", L"Map Overview", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3686,22 +3868,25 @@ STR16 zOptionsToggleText[] = L"Toon 3D Cursor", L"Show Chance to Hit on cursor", L"GL Burst uses Burst cursor", - L"Enemies Drop all Items", + L"Allow Enemy Taunts", // Changed from "Enemies Drop all Items" - SANDRO L"High angle Grenade launching", - L"Restrict extra Aim Levels", + L"Allow Real Time Sneaking", // Changed from "Restrict extra Aim Levels" - SANDRO L"Space selects next Squad", L"Show Item Shadow", L"Show Weapon Ranges in Tiles", L"Tracer effect for single shot", L"Rain noises", L"Allow crows", - L"Show Soldier Tooltips", // Changed from "Random I.M.P personality" - SANDRO + L"Show Soldier Tooltips", L"Auto save", L"Silent Skyrider", L"Low CPU Usage", L"Enhanced Description Box", L"Forced Turn Mode", // add forced turn mode L"Stat Progress Bars", // Show progress towards stat increase // TODO.Translate + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) // TODO.Translate L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3720,6 +3905,8 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"Schakel deze optie IN als je de karakter-dialogen wil horen.", @@ -3782,22 +3969,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"When ON, the chance to hit is shown on the cursor.", L"When ON, GL burst uses burst cursor.", - L"When ON, dead enemies drop all items.", + L"When ON, enemies will occasionally comment certain actions.", // Changed from Enemies Drop All Items - SANDRO L"When ON, grenade launchers fire grenades at higher angles (|Q).", - L"When ON, aim levels beyond 4 are restricted to rifles and sniper rifles.", + L"When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"When ON, |S|p|a|c|e selects next squad automatically.", L"When ON, item shadows will be shown.", L"When ON, weapon ranges will be shown in tiles.", L"When ON, tracer effect will be shown for single shots.", L"When ON, you will hear rain noises when it is raining.", L"When ON, the crows are present in game.", - L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", // - Changed from random IMP personality - SANDRO + L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", L"When ON, game will be saved after each players turn.", L"When ON, Skyrider will not talk anymore.", L"When ON, game will run with much lower CPU usage.", L"When ON, enhanced descriptions will be shown for items and weapons.", L"When ON and enemy present, Turn Base mode persists untill sector is free (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode L"When ON, shows character progress towards gaining levels.", // TODO.Translate + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"When ON, alternate bullet graphics will be shown when you shoot.", // TODO.Translate L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3830,7 +4020,7 @@ STR16 gzGIOScreenText[] = L"Ervaren", L"Expert", L"INSANE", - L"Ok", + L"Start", // TODO.Translate L"Stop", L"Extra Moeilijk", L"Save Anytime", @@ -3841,11 +4031,42 @@ STR16 gzGIOScreenText[] = L"Great", L"Excellent", L"Awesome", - L"Inventory System", - L"Old", - L"New", + L"Inventory / Attachments", // TODO.Translate + L"NOT USED", + L"NOT USED", L"Load MP Game", L"INITIAL GAME SETTINGS (Only the server settings take effect)", + // Added by SANDRO + L"Skill Traits", + L"Old", + L"New", + L"Max IMP Characters", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Enemies Drop All Items", + L"Off", + L"On", + L"Number of Terrorists", + L"Random", + L"All", + L"Secret Weapon Caches", + L"Random", + L"All", + L"Progress Speed of Item Choices", + L"Very Slow", + L"Slow", + L"Normal", + L"Fast", + L"Very Fast", + + // TODO.Translate + L"Old / Old", + L"New / Old", + L"New / New", }; STR16 gzMPJScreenText[] = @@ -3868,6 +4089,24 @@ STR16 gzMPJScreenText[] = L"You must enter a valid Server Port between 1 and 65535.", }; +// TODO.Translate +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { L"HOST GAME", @@ -3876,36 +4115,72 @@ STR16 gzMPHScreenText[] = L"Server Name", L"Game Type", L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"Max Players", - L"Squad Size", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", L"Merc Selection", - L"Random Mercs", + L"Merc Hiring", L"Hired by Player", - L"Starting Balance", - L"Can Hire Same Merc", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"Allow Bobby Rays", - L"Randomise Starting Edge", + L"Bobby Rays", + L"Sector Starting Edge", L"You must enter a server name", - L"Max Players must be between 2 and 4", - L"Squad size must be between 1 and 6", - L"Time of Day", - L"Time of Day must be a 24 hour time (HH:MM)\n\n eg. 13:30 = 1.30pm", - L"Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000" , - L"Damage Multiplier", - L"Damage Multiplier must be a number between 0 and 5", - L"Turn Timer Multiplier", - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", L"Enable Civilians in CO-OP", - L"Use New Inventory (NIV)", - L"Enforce Maximum AI Enemies", - L"Sync. MP Clients Directory", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", L"MP Sync. Directory", L"You must enter a file transfer directory.", L"(Use '/' instead of '\\' for directory delimiters.)", L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4083,8 +4358,8 @@ STR16 pMessageStrings[] = L"Geschiedenisverslag bijgewerkt.", L"Grenade Bursts use Targeting Cursor (Spread fire enabled)", L"Grenade Bursts use Trajectory Cursor (Spread fire disabled)", - L"Drop All Enabled", - L"Drop All Disabled", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"Granade Launchers fire at standard angles", L"Grenade Launchers fire at higher angles", // forced turn mode strings @@ -4098,6 +4373,8 @@ STR16 pMessageStrings[] = L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved. L"Client", + // TODO.Translate + L"You cannot use the Old Inventory and the New Attachment System at the same time.", }; @@ -4461,7 +4738,7 @@ STR16 gzLateLocalizedString[] = L"%s's armour attachment has been smashed!", L"%s fires %d more rounds than intended!", - L"%s fires %d more round than intended!", + L"%s fires one more round than intended!", }; STR16 gzCWStrings[] = @@ -4512,6 +4789,10 @@ STR16 gzTooltipStrings[] = L"no Vest", L"no Leggings", L"|Armor: %s\n", + // Added - SANDRO + L"%s|Skill 1: %s\n", + L"%s|Skill 2: %s\n", + L"%s|Skill 3: %s\n", }; STR16 New113Message[] = @@ -4540,7 +4821,25 @@ STR16 New113Message[] = L"No enemies in sight", L"Real-time sneaking OFF", L"Real-time sneaking ON", - L"Enemy spotted! (Ctrl + x to enter turn based)", + L"Enemy spotted!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s was successful on stealing!", + L"%s had not enough action points to steal all selected items.", + L"Do you want to make surgery on %s before bandaging? (You can heal about %i Health.)", + L"Do you want to make surgery on %s? (You can heal about %i Health.)", + L"Do you wish to make necessary surgeries first? (%i patient(s))", + L"Do you wish to make the surgery on this patient first?", + L"Apply first aid automatically with necessary surgeries or without them?", + L"Surgery on %s finished.", + L"%s is hit in the chest and loses a point of maximum health!", + L"%s is hit in the chest and loses %d points of maximum health!", + L"%s has regained one point of lost %s", + L"%s has regained %d points of lost %s", + L"Your scouting skills prevented you to be ambushed by the enemy!", + L"Thanks to your scouting skills you have successfuly avoided a pack of bloodcats!", + L"%s is hit to groin and falls down in pain!", + ////////////////////////////////////////////////////////////////////////////////////// }; // TODO.Translate @@ -4589,6 +4888,43 @@ STR16 New113MERCMercMailTexts[] = L"Please take note. Due to the improved performance of Biggens his fees for services rendered have undergone an increase. Speck T. Kline ", }; +// TODO.Translate +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"FW from AIM Server: Message from Victor Kolesnikov", + L"You want to talk to me? I have time.", + + // Brain + L"FW from AIM Server: Message from Janno Allik", + L"I am back. Waiting for your call.", + + // Scream + L"FW from AIM Server: Message from Lennart Vilde", + L"Sorry, I was out of office, now I am back.", + + // Henning + L"FW from AIM Server: Message from Henning von Branitz", + L"Back from business. You want my help?", + + // Luc + L"FW from AIM Server: Message from Luc Fabre", + L"Give me a call, if you are interested.", + + // Laura + L"FW from AIM Server: Message from Dr. Laura Colin", + L"I am now available.", + + // Grace + L"FW from AIM Server: Message from Graziella Girelli", + L"Got your message. If you still want me, you know what to do.", + + // Rudolf + L"FW from AIM Server: Message from Rudolf Steiger", + L"Rudolf here. Call me back.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4597,6 +4933,25 @@ STR16 MissingIMPSkillsDescriptions[] = L"Sniper: De ogen van een havik, u kunnen de vleugels van een vlieg bij honderd werven ontspruiten! ", // Camouflage L"Camouflage: Naast u ringt synthetische zelfs blik! ", + // SANDRO - new strings for new traits added + // Ranger + L"Ranger: You are the one from Texas deserts, aren't you! ", + // Gunslinger + L"Gunslinger: With a handgun or two, you can be as lethal as the Billy Kid! ", + // Squadleader + L"Squadleader: Natural leader and boss, you are the big shot no kidding! ", + // Technician + L"Technician: Fixing stuff, removing traps, planting bombs, that's your bussiness! ", + // Doctor + L"Doctor: You can make a quick surgery with pocket-knife and chewing gum anywhere! ", + // Athletics + L"Athletics: Your speed and vitality is on top of possibilities! ", + // Bodybuilding + L"Bodybuilding: That big muscular figure which cannot be overlooked is you actually! ", + // Demolitions + L"Demolitions: You can blow up a whole city just by common home stuff! ", + // Scouting + L"Scouting: Nothing can escape your notice! ", }; STR16 NewInvMessage[] = @@ -4662,11 +5017,10 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"Grid Number: %d", L"Server only feature", - L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", + L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Timed Turns=%d, Secs/Tic=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", // 25 - L"Testing and cheat function '9' is enabled.", + L"", L"New connection: Client #%d - '%S'.", L"Team: %d.",//not used any more L"'%s' (client %d - '%S') was killed by '%s' (client %d - '%S')", @@ -4718,31 +5072,18 @@ STR16 MPClientMessage[] = L"Cannot connect because your version %S is different from the server version %S.", L"You killed an enemy soldier.", L"Cannot start the game, because all teams are the same.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Welcome to Jagged Alliance 2 v1.13 Multiplayer", - L"Press 'F1' for help", - L"Multiplayer controls (from strategy screen)", - L"* first set up ja2_mp.ini *", - L"'1' - Start server", - // 5 - L"'2' - Connect to server", - L"'3' - If server unlock laptop, set client ready for battle", - L"'4' - Quit server and client", - L"'5' - Display mouse coords (from tactical screen)", - L"'7' - Popup dialog for server override panel", - // 10 - L"'F2' - Display secondary help", - L"See readme_mp.html for further details", - L"Tips: (assuming ja2_mp.ini is set up)", - L"* Make sure all clients have unique CLIENT_NUM *", - L"* Game save doesn't record bobby rays order *", - // 15 - L"* Avoid placing opposed mercs in immediate sight *", - L"'F1' - Display primary help", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 // TODO.Translate + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; STR16 gszMPEdgesText[] = @@ -4819,16 +5160,24 @@ STR16 gzMPChatboxText[] = // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected. To achieve an expert level on a trait, simply choose only that one trait.", - L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels, and if you choose one of them only, you will have only one skill trait.", + // For old traits + L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected.", + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics, Ambidextrous and Camouflage traits cannot be achieved at expert levels.", + // For new major/minor traits + L"Next stage is about choosing your skill traits according to your proffessional specialization as a mercenary. On first page you can select up to two potential major traits, which mostly represent your main role in a team. While on second page is list of possible minor traits, which represent personal feats.", + L"No more then three choices altogeher are possible. Which means if you choose no major traits, you can then choose three minor traits. If you choose both major traits (or one enhanced), you can then choose only one minor trait...", }; STR16 sgAttributeSelectionText[] = { - L"Please adjust your physical attributes as comapred to that of an avarage merc. You cannot raise any score above", + L"Please adjust your physical attributes according to your true abilities. You cannot raise any score above", L"I.M.P. Attributes and skills review.", L"Bonus Pts.:", L"Starting Level", + // New strings for new traits + L"On the next page you are going to specify your physical attributes and skills. As 'attributes' are called: health, dexterity, agility, strength and wisdom. Attributes cannot go lower than %d.", + L"The rest are called 'skills' and unlike attributes skills can be set to zero meaning you have absolutely no proficieny in it.", + L"All scores are set to a minimum at the beginning. Note that certain attributes are set to specific values according to skill traits you have selected. You cannot set those attributes lower than that.", }; STR16 pCharacterTraitBeginIMPStrings[] = @@ -4838,7 +5187,7 @@ STR16 pCharacterTraitBeginIMPStrings[] = L"The second page enlists possible disabilities you might have. If you suffer from any of these disabilities, choose which one (we believe that everyone has only one such disablement). Be honest, as it is important to inform potential employers of your true condition.", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"Normal", L"Friendly", @@ -4850,6 +5199,24 @@ STR16 gzIMPCharacterTraitText[]= L"Big Shot", L"Asshole", L"Coward", + L"I.M.P. Attitudes", +}; + +STR16 gzIMPCharacterTraitText[]= +{ + L"Normal", + L"Sociable", + L"Loner", + L"Optimist", + L"Assertive", + L"Intellectual", + L"Primitive", + L"Aggressive", + L"Phlegmatic", + L"Dauntless", + L"Pacifist", + L"Malicious", + L"Show-off", L"I.M.P. Character Traits", }; @@ -4860,6 +5227,7 @@ STR16 gzIMPColorChoosingText[] = L"Please select the respective colors of your skin, hair and clothing. And select what body type you have.", L"Please select the respective colors of your skin, hair and clothing.", L"Toggle this to use alternative rifle holding.", + L"\n(Caution: you will need a big strength for this.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -4998,4 +5366,498 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 windowed modus vereist een kleurdiepte van 16 bits per pixel.", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Suck this!", + L"Touch this!", + L"Come get some!", + L"You're mine!", + L"Die!", + L"You scared, motherfucker?", + L"This will hurt!", + L"Come on you bastard!", + L"Come on! I don't got all day!", + L"Come to daddy!", + L"You'll be six feet under in no time!", + L"Will send ya home in a pinebox, loser!", + L"Hey, wanna play?", + L"You should have stayed home, bitch.", + L"Sucker!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"We have a barbecue here.", + L"I got a present for ya.", + L"Bam!", + L"Smile!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Catch!", + L"Here ya go!", + L"Pop goes the weasel.", + L"This one's for you.", + L"Muhehe.", + L"Catch this, swine!", + L"I like this.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"I'll get your scalp.", + L"Come to papa.", + L"Show me your guts!", + L"I'll rip you to pieces!", + L"Motherfucker!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"We're in some real shit...", + L"They said join the army. Not for this shit!", + L"I have enough.", + L"Oh my God.", + L"They ain't paying us enough for this.", + L"It's just too much for me.", + L"I'll bring some friends.", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"I heard that!", + L"Who's there?", + L"What was that?", + L"Hey! What the...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"They are here!", + L"Now the fun can start.", + L"I hoped this will never happen.", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Ouch!", + L"Ugh!", + L"This.. hurts!", + L"You fuck!", + L"You will regret.. uhh.. this.", + L"What the..!", + L"Now you have.. pissed me off.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //DUTCH diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index f2295269..832bf178 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -1,3 +1,4 @@ +//#pragma setlocale("ENGLISH") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #else @@ -108,6 +109,23 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. SirTech uses the "@@@" notation. */ +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Page 1/2", //0 + L"Page 2/2", + + L"Page 1/3", + L"Page 2/3", + L"Page 3/3", + + L"Page 1/1", //5 +}; + +// by Jazz: +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; STR16 pCreditsJA2113[] = { @@ -320,6 +338,20 @@ CHAR16 Message[][STRING_LENGTH] = L"no semi auto", L"The enemy has no more items to steal!", L"The enemy has no item in its hand!", + + L"%s's desert camouflage has worn off.", + L"%s's desert camouflage has washed off.", + + L"%s's wood camouflage has worn off.", + L"%s's wood camouflage has washed off.", + + L"%s's urban camouflage urban has worn off.", + L"%s's urban camouflage urban has washed off.", + + L"%s's snow camouflage snow has worn off.", + L"%s's snow camouflage has washed off.", + + L"You cannot attach %s to this slot.", }; @@ -472,9 +504,12 @@ STR16 pPersonnelAssignmentStrings[] = L"In Transit", L"Repair", L"Practice", - L"Training Militia", + L"Training Militia", + L"Training Mobile Militia", // Missing L"Trainer", - L"Student", + L"Student", + L"Facility Staff", // Missing + L"Resting at Facility", // Missing L"Dead", L"Incap.", L"POW", @@ -514,9 +549,12 @@ STR16 pLongAssignmentStrings[] = L"In Transit", L"Repair", L"Practice", - L"Train Militia", + L"Train Militia", + L"Train Mobiles", // Missing L"Train Teammate", - L"Student", + L"Student", + L"Staff Facility", // Missing + L"Rest at Facility", // Missing L"Dead", L"Incap.", L"POW", @@ -760,34 +798,130 @@ STR16 pPersonnelScreenStrings[] = L"Times Wounded:", // number of times merc has been wounded L"Skills:", L"No Skills", + L"Achievements:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elite soldiers: %d\n", + L"Regular soldiers: %d\n", + L"Admin soldiers: %d\n", + L"Hostile groups: %d\n", + L"Creatures: %d\n", + L"Tanks: %d\n", + L"Others: %d\n", + + L"Mercs: %d\n", + L"Militia: %d\n", + L"Others: %d\n", + + L"Shots fired: %d\n", + L"Missiles fired: %d\n", + L"Grenades thrown: %d\n", + L"Knives thrown: %d\n", + L"Blade attacks: %d\n", + L"Hand to hand attacks: %d\n", + L"Successful hits: %d\n", + + L"Locks picked: %d\n", + L"Locks breached: %d\n", + L"Traps removed: %d\n", + L"Explosives detonated: %d\n", + L"Items repaired: %d\n", + L"Items combined: %d\n", + L"Items stolen: %d\n", + L"Militia trained: %d\n", + L"Mercs bandaged: %d\n", + L"Surgeries made: %d\n", + L"Persons met: %d\n", + L"Sectors discovered: %d\n", + L"Ambushes prevented: %d\n", + L"Quests handled: %d\n", + + L"Tactical battles: %d\n", + L"Autoresolve battles: %d\n", + L"Times retreated: %d\n", + L"Ambushes experienced: %d\n", + L"Hardes battle: %d Enemies\n", + + L"Shot: %d\n", + L"Stabbed: %d\n", + L"Punched: %d\n", + L"Blasted: %d\n", + L"Suffered damages in facilities: %d\n", + L"Surgeries undergoed: %d\n", + L"Facility accidents: %d\n", + + L"Character:", + L"Weakening:", }; //These string correspond to enums used in by the SkillTrait enums in SoldierProfileType.h STR16 gzMercSkillText[] = { + // SANDRO - tweaked this L"No Skill", - L"Lock picking", - L"Hand to hand combat", //JA25: modified + L"Lock Picking", + L"Hand to Hand", //JA25: modified L"Electronics", - L"Night operations", //JA25: modified + L"Night Operations", //JA25: modified L"Throwing", L"Teaching", L"Heavy Weapons", L"Auto Weapons", - L"Stealth", + L"Stealthy", L"Ambidextrous", L"Thief", L"Martial Arts", L"Knifing", L"Sniper", L"Camouflage", //JA25: modified - L"Camouflage (Urban)", - L"Camouflage (Desert)", - L"Camouflage (Snow)", + //L"Camouflage (Urban)", + //L"Camouflage (Desert)", + //L"Camouflage (Snow)", L"(Expert)", }; - +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"No Skill", + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + // Minor traits + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + // second names for major skills + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", + L"More...", +}; +////////////////////////////////////////////////////////// // This is pop up help text for the options that are available to the merc @@ -1094,11 +1228,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Status:", - L"Weight (%s):", + L"Weight:", L"AP Costs", L"Rng:", // Range L"Dam:", // Damage @@ -1117,36 +1251,40 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // Obviously, THIS SHOULD BE DONE IN ALL LANGUAGES... L"Attachments:", //14 L"AUTO/5:", //15 - L"Amount:", //16 + L"Remaining ammo:", //16 + L"Default:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", - L"APs to fire Auto", //10 + L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"Flash Suppression", - L"Loudness (lower is better)", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", + L"", //19 L"Bipod Modifier", - L"APs to Throw", //20 + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 + L"APs to Throw", L"APs to Launch", L"APs to Stab", L"No Single Shot!", @@ -1157,29 +1295,32 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Burst Penalty (Lower is better)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", - L"APs to fire Auto", //10 + L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", - L"Flash Suppression", - L"Loudness (Lower is better)", + L"", //19 L"Bipod Modifier", - L"APs to Throw", //20 + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 + L"APs to Throw", L"APs to Launch", L"APs to Stab", L"No Single Shot!", @@ -1302,6 +1443,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1879,6 +2034,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"Show |Airspace", L"Show |Items", L"Show Militia & Enemies (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1912,7 +2068,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc", @@ -1967,7 +2127,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings @@ -2315,7 +2475,7 @@ STR16 pImpButtonText[] = L"BEGIN", // begin profiling L"Skills", // personality section L"Attributes", // personal stats/attributes section - L"Appearance", // changed from portrait - SANDRO + L"Appearance", // changed from portrait L"Voice %d", // the voice selection L"Done", // done profiling L"Start Over", // start over profiling @@ -2336,12 +2496,12 @@ STR16 pImpButtonText[] = L"Registry", // the IMP site registry..when name and gender is selected L"Analyzing", // analyzing your profile results L"OK", - L"Character", // Change from "Voice" - SANDRO + L"Character", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO + // These texts have been also slightly changed L"With your character traits chosen, it is time to select your skills.", L"To complete the process, select your attributes.", L"To commence actual profiling, select portrait, voice and colors.", @@ -3256,7 +3416,13 @@ STR16 CharacterInfo[] = L"Additional Info", // Title for the additional info for the merc's bio L"Active Members", //20 // Title of the page L"Optional Gear:", // Displays the optional gear cost + L"gear", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"MEDICAL deposit required", // If the merc required a medical deposit, this is displayed + L"Kit 1", // Text on Starting Gear Selection Button 1 + L"Kit 2", // Text on Starting Gear Selection Button 2 + L"Kit 3", // Text on Starting Gear Selection Button 3 + L"Kit 4", // Text on Starting Gear Selection Button 4 + L"Kit 5", // Text on Starting Gear Selection Button 5 }; @@ -3634,8 +3800,11 @@ STR16 zMarksMapScreenText[] = L"There aren't enough people willing to be trained right now.", L"%s is full of militia.", L"Merc has a finite contract.", - L"Merc's contract is not insured", + L"Merc's contract is not insured", L"Map Overview", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3701,22 +3870,25 @@ STR16 zOptionsToggleText[] = L"Show 3D Cursor", L"Show Chance to Hit on cursor", L"GL Burst uses Burst cursor", - L"Enemies Drop all Items", + L"Allow Enemy Taunts", // Changed from "Enemies Drop all Items" - SANDRO L"High angle Grenade launching", - L"Restrict extra Aim Levels", + L"Allow Real Time Sneaking", // Changed from "Restrict extra Aim Levels" - SANDRO L"Space selects next Squad", L"Show Item Shadow", L"Show Weapon Ranges in Tiles", L"Tracer effect for single shot", L"Rain noises", L"Allow crows", - L"Show Soldier Tooltips", // Changed from "Random I.M.P personality" - SANDRO + L"Show Soldier Tooltips", L"Auto save", L"Silent Skyrider", L"Low CPU usage", L"Enhanced Description Box", L"Forced Turn Mode", // add forced turn mode L"Stat Progress Bars", // Show progress towards stat increase + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3735,13 +3907,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"Keep this option ON if you want to hear character dialogue.", //Mute Confirmation L"Turns characters' verbal confirmations on or off.", - //Subtitles + //Subtitles L"Controls whether on-screen text is displayed for dialogue.", //Key to advance speech @@ -3797,22 +3971,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"When ON, the chance to hit is shown on the cursor.", L"When ON, GL burst uses burst cursor.", - L"When ON, dead enemies drop all items.", + L"When ON, enemies will occasionally comment certain actions.", // Changed from Enemies Drop All Items - SANDRO L"When ON, grenade launchers fire grenades at higher angles (|Q).", - L"When ON, aim levels beyond 4 are restricted to rifles and sniper rifles.", + L"When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"When ON, |S|p|a|c|e selects next squad automatically.", L"When ON, item shadows will be shown.", L"When ON, weapon ranges will be shown in tiles.", L"When ON, tracer effect will be shown for single shots.", L"When ON, you will hear rain noises when it is raining.", L"When ON, the crows are present in game.", - L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", // - Changed from random IMP personality - SANDRO + L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", L"When ON, game will be saved after each players turn.", L"When ON, Skyrider will not talk anymore.", L"When ON, game will run with much lower CPU usage.", L"When ON, enhanced descriptions will be shown for items and weapons.", L"When ON and enemy present, Turn Base mode persists untill sector is free (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode L"When ON, shows character progress towards gaining levels.", + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"When ON, alternate bullet graphics will be shown when you shoot.", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3837,15 +4014,15 @@ STR16 gzGIOScreenText[] = L"Realistic", L"Sci Fi", L"Platinum", - L"Items", + L"Available Arsenal", // changed by SANDRO L"Tons of Guns", - L"Normal Guns", + L"Reduced", // changed by SANDRO L"Difficulty Level", L"Novice", L"Experienced", L"Expert", L"INSANE", - L"Ok", + L"Start", L"Cancel", L"Extra Difficulty", L"Save Anytime", @@ -3856,11 +4033,41 @@ STR16 gzGIOScreenText[] = L"Great", L"Excellent", L"Awesome", - L"Inventory System", - L"Old", - L"New", + L"Inventory / Attachments", + L"NOT USED", + L"NOT USED", L"Load MP Game", L"INITIAL GAME SETTINGS (Only the server settings take effect)", + // Added by SANDRO + L"Skill Traits", + L"Old", + L"New", + L"Max IMP Characters", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Enemies Drop All Items", + L"Off", + L"On", + L"Number of Terrorists", + L"Random", + L"All", + L"Secret Weapon Caches", + L"Random", + L"All", + L"Progress Speed of Item Choices", + L"Very Slow", + L"Slow", + L"Normal", + L"Fast", + L"Very Fast", + + L"Old / Old", + L"New / Old", + L"New / New", }; STR16 gzMPJScreenText[] = @@ -3880,7 +4087,23 @@ STR16 gzMPJScreenText[] = L"Ping", L"You must enter a player name.", L"You must enter a valid server IP address.\n (eg 84.114.195.239).", - L"You must enter a valid Server Port between 1 and 65535.", + L"You must enter a valid Server Port between 1 and 65535.", +}; + +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", }; STR16 gzMPHScreenText[] = @@ -3891,36 +4114,72 @@ STR16 gzMPHScreenText[] = L"Server Name", L"Game Type", L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"Max Players", - L"Squad Size", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", L"Merc Selection", - L"Random Mercs", + L"Merc Hiring", L"Hired by Player", - L"Starting Balance", - L"Can Hire Same Merc", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"Allow Bobby Rays", - L"Randomise Starting Edge", + L"Bobby Rays", + L"Sector Starting Edge", L"You must enter a server name", - L"Max Players must be between 2 and 4", - L"Squad size must be between 1 and 6", - L"Time of Day", - L"Time of Day must be a 24 hour time (HH:MM)", - L"Starting Cash must be a valid dollar amount (no cents)" , - L"Damage Multiplier", - L"Damage Multiplier must be a number between 0 and 5", - L"Turn Timer Multiplier", - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", L"Enable Civilians in CO-OP", - L"Use New Inventory (NIV)", - L"Enforce Maximum AI Enemies", - L"Sync. MP Clients Directory", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", L"MP Sync. Directory", L"You must enter a file transfer directory.", L"(Use '/' instead of '\\' for directory delimiters.)", - L"The specified synchronisation directory does not exist.", + L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4098,8 +4357,8 @@ STR16 pMessageStrings[] = L"History log updated.", L"Grenade Bursts use Targeting Cursor (Spread fire enabled)", L"Grenade Bursts use Trajectory Cursor (Spread fire disabled)", - L"Drop All Enabled", - L"Drop All Disabled", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"Grenade Launchers fire at standard angles", L"Grenade Launchers fire at higher angles", // forced turn mode strings @@ -4112,6 +4371,7 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved.//84 L"Client", + L"You cannot use the Old Inventory and the New Attachment System at the same time.", }; @@ -4477,7 +4737,7 @@ STR16 gzLateLocalizedString[] = L"%s's armour attachment has been smashed!", L"%s fires %d more rounds than intended!", - L"%s fires %d more round than intended!", + L"%s fires one more round than intended!", }; // HEADROCK HAM 3.5: Added sector name @@ -4529,6 +4789,10 @@ STR16 gzTooltipStrings[] = L"no Vest", L"no Leggings", L"|Armor: %s\n", + // Added - SANDRO + L"%s|Skill 1: %s\n", + L"%s|Skill 2: %s\n", + L"%s|Skill 3: %s\n", }; STR16 New113Message[] = @@ -4557,7 +4821,26 @@ STR16 New113Message[] = L"No enemies in sight", L"Real-time sneaking OFF", L"Real-time sneaking ON", - L"Enemy spotted! (Ctrl + x to enter turn based)", + //L"Enemy spotted! (Ctrl + x to enter turn based)", + L"Enemy spotted!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s was successful at stealing!", // MINTY - Changed "on" to "at": More natural English + L"%s did not have enough action points to steal all selected items.", // MINTY - Changed "had not" to "did not": More natural English + L"Do you want to perform surgery on %s before bandaging? (You can heal about %i Health.)", // MINTY - Changed "make" to "perform": More natural English + L"Do you want to perform surgery on %s? (You can heal about %i Health.)",// MINTY - Changed "make" to "perform": More natural English + L"Do you wish to perform necessary surgeries first? (%i patient(s))",// MINTY - Changed "make" to "perform": More natural English + L"Do you wish to perform the surgery on this patient first?",// MINTY - Changed "make" to "perform": More natural English + L"Apply first aid automatically with necessary surgeries or without them?", + L"Surgery on %s finished.", + L"%s is hit in the chest and loses a point of maximum health!", + L"%s is hit in the chest and loses %d points of maximum health!", + L"%s has regained one point of lost %s", + L"%s has regained %d points of lost %s", + L"Your scouting skills prevented an ambush by the enemy!", // MINTY - Changed "you to be ambushed" to "an ambush": More natural English + L"Thanks to your scouting skills you have successfuly avoided a pack of bloodcats!", + L"%s is hit to groin and falls down in pain!", + ////////////////////////////////////////////////////////////////////////////////////// }; STR16 New113HAMMessage[] = @@ -4606,6 +4889,42 @@ STR16 New113MERCMercMailTexts[] = L"Please take note. Due to the improved performance of Biggens his fees for services rendered have undergone an increase. Speck T. Kline ", }; +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk: Text from Line 58 + L"FW from AIM Server: Message from Victor Kolesnikov", + L"Hello. Monk here. Message received. I'm back if you want to see me. Waiting for your call. ", + + // Brain: Text from Line 60 + L"FW from AIM Server: Message from Janno Allik", + L"Am now ready to consider tasks. There is a time and place for everything. Janno Allik ", + + // Scream: Text from Line 62 + L"FW from AIM Server: Message from Lennart Vilde", + L"Lennart Vilde now available! ", + + // Henning: Text from Line 64 + L"FW from AIM Server: Message from Henning von Branitz", + L"Have received your message, thanks. To discuss employment, contact me at the AIM Website. Till then! Henning von Branitz ", + + // Luc: Text from Line 66 + L"FW from AIM Server: Message from Luc Fabre", + L"Mesage received, merci! Am happy to consider your proposals. You know where to find me. Looking forward to hearing from you ", + + // Laura: Text from Line 68 + L"FW from AIM Server: Message from Dr. Laura Colin", + L"Greetings! Good of you to leave a message It sounds interesting. Visit AIM again I would be happy to hear more. Best regards! Dr. Laura Colin ", + + // Grace: Text from Line 70 + L"FW from AIM Server: Message from Graziella Girelli", + L"You wanted to contact me, but were not successful. A family gathering. I am sure you understand? I've now had enough of family and would be very happy if you would contact me again over the AIM Site. Ciao! ", + + // Rudolf: Text from Line 72 + L"FW from AIM Server: Message from Rudolf Steiger", + L"Do you know how many calls I get every day? Every tosser thinks he can call me. But I'm back, if you have something of interest for me.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4613,7 +4932,27 @@ STR16 MissingIMPSkillsDescriptions[] = // Sniper L"Sniper: Eyes of a hawk, you can shoot the wings from a fly at a hundred yards! ", // Camouflage - L"Camouflage: Besides you even bushes look synthetic! ", + L"Camouflage: Beside you, even bushes look synthetic! ", + // SANDRO - new strings for new traits added + // MINTY - Altered the texts for more natural English, and added a little flavour too + // Ranger + L"Ranger: Those amateurs from Texas have nothing on you! ", + // Gunslinger + L"Gunslinger: With one handgun or two, you can be as lethal as Billy the Kid! ", + // Squadleader + L"Squadleader: A natural leader, your squadmates look to you for inspiration! ", + // Technician + L"Technician: MacGyver's got nothing on you! Mechanical, electronic or explosive, you can fix it! ", + // Doctor + L"Doctor: From grazes to gutshot, to amputations, you can heal them all! ", + // Athletics + L"Athletics: Your speed and vitality are worthy of an Olympian! ", + // Bodybuilding + L"Bodybuilding: Arnie? What a wimp! You could beat him with one arm behind your back! ", + // Demolitions + L"Demolitions: Sowing grenades like seeds, planting bombs, watching the limbs flying.. This is what you live for! ", + // Scouting + L"Scouting: Nothing can escape your notice! ", }; STR16 NewInvMessage[] = @@ -4679,12 +5018,10 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"Grid number: %d", L"Server only feature", - L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", + L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", L"Sector=%s, Max. clients=%d, Max. mercs=%d, Game type=%d, Same merc=%d, Damage multiplier=%f, Timed turns=%d, Secs/Tic=%d, Disable Bobby Ray=%d, Disable Aim/Merc Equipment=%d, Disable Morale=%d, Testing=%d.", - // 25 - L"Testing and cheat function '9' is enabled.", + L"", //not used any more L"New connection: Client #%d - '%S'.", L"Team: %d.",//not used any more L"'%s' (client %d - '%S') was killed by '%s' (client %d - '%S').", @@ -4736,31 +5073,18 @@ STR16 MPClientMessage[] = L"Cannot connect because your version %S is different from the server version %S.", L"You killed an enemy soldier.", L"Cannot start the game, because all teams are the same.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Welcome to Jagged Alliance 2 v1.13 Multiplayer", - L"Press 'F1' for help", - L"Multiplayer controls (from strategy screen)", - L"* first set up ja2_mp.ini *", - L"'1' - Start server", - // 5 - L"'2' - Connect to server", - L"'3' - If server unlock laptop, set client ready for battle", - L"'4' - Quit server and client", - L"'5' - Display mouse coords (from tactical screen)", - L"'7' - Popup dialog for server override panel", - // 10 - L"'F2' - Display secondary help", - L"See readme_mp.html for further details", - L"Tips: (assuming ja2_mp.ini is set up)", - L"* Make sure all clients have unique CLIENT_NUM *", - L"* Game save doesn't record bobby rays order *", - // 15 - L"* Avoid placing opposed mercs in immediate sight *", - L"'F1' - Display primary help", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; STR16 gszMPEdgesText[] = @@ -4837,26 +5161,34 @@ STR16 gzMPChatboxText[] = // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected. To achieve an expert level on a trait, simply choose only that one trait.", - L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels, and if you choose one of them only, you will have only one skill trait.", + // For old traits + L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected.", + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics, Ambidextrous and Camouflage traits cannot be achieved at expert levels.", + // For new major/minor traits + L"Next stage is about choosing your skill traits according to your proffessional specialization as a mercenary. On first page you can select up to two potential major traits, which mostly represent your main role in a team. While on second page is list of possible minor traits, which represent personal feats.", + L"No more then three choices altogeher are possible. Which means if you choose no major traits, you can then choose three minor traits. If you choose both major traits (or one enhanced), you can then choose only one minor trait...", }; STR16 sgAttributeSelectionText[] = { - L"Please adjust your physical attributes as comapred to that of an avarage merc. You cannot raise any score above", + L"Please adjust your physical attributes according to your true abilities. You cannot raise any score above", L"I.M.P. Attributes and skills review.", L"Bonus Pts.:", L"Starting Level", + // New strings for new traits + L"On the next page you are going to specify your physical attributes and skills. As 'attributes' are called: health, dexterity, agility, strength and wisdom. Attributes cannot go lower than %d.", + L"The rest are called 'skills' and unlike attributes skills can be set to zero meaning you have absolutely no proficieny in it.", + L"All scores are set to a minimum at the beginning. Note that certain attributes are set to specific values according to skill traits you have selected. You cannot set those attributes lower than that.", }; STR16 pCharacterTraitBeginIMPStrings[] = { L"I.M.P. Character Analysis", - L"The analysis of your character is the next step on your profile creation. On the first page you will be shown a list of attitudes to choose. We imagine you could identify yourself with more of them, but here you will be able to pick only one. Choose the one which you feel aligned with mostly. ", + L"The analysis of your character is the next step on your profile creation. On the first page you will be shown a list of character traits to choose. We imagine you could identify yourself with more of them, but here you will be able to pick only one. Choose the one which you feel aligned with mostly. ", L"The second page enlists possible disabilities you might have. If you suffer from any of these disabilities, choose which one (we believe that everyone has only one such disablement). Be honest, as it is important to inform potential employers of your true condition.", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"Normal", L"Friendly", @@ -4868,6 +5200,24 @@ STR16 gzIMPCharacterTraitText[]= L"Big Shot", L"Asshole", L"Coward", + L"I.M.P. Attitudes", +}; + +STR16 gzIMPCharacterTraitText[]= +{ + L"Neutral", + L"Sociable", + L"Loner", + L"Optimist", + L"Assertive", + L"Intellectual", + L"Primitive", + L"Aggressive", + L"Phlegmatic", + L"Dauntless", + L"Pacifist", + L"Malicious", + L"Show-off", L"I.M.P. Character Traits", }; @@ -4878,6 +5228,7 @@ STR16 gzIMPColorChoosingText[] = L"Please select the respective colors of your skin, hair and clothing. And select what body type you have.", L"Please select the respective colors of your skin, hair and clothing.", L"Toggle this to use alternative rifle holding.", + L"\n(Caution: you will need a big strength for this.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -5012,4 +5363,499 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 windowed mode requires a color depth of 16bpp or less.", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +// MINTY - Changed some of the following taunts to sound more natural +STR16 sEnemyTauntsFireGun[]= +{ + L"Suck on this!", + L"Say hello to my lil' friend!", // MINTY - "Touch this" just doesn't sound right, so I changed it to a Scarface quote. + L"Come get some!", + L"You're mine!", + L"Die!", + L"You scared, motherfucker?", + L"This will hurt!", + L"Come on you bastard!", + L"Come on! I don't got all day!", + L"Come to daddy!", + L"You'll be six feet under in no time!", + L"Gonna send ya home in a pine box, loser!", + L"Hey, wanna play?", + L"You should have stayed home, bitch!", + L"Sucker!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"Barbecue time!", + L"I got a present for ya!", + L"Bam!", + L"Smile!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Catch!", + L"Here ya go!", + L"Pop goes the weasel.", + L"This one's for you.", + L"Muahaha!", + L"Catch this, swine!", + L"I like this.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"Gonna scalp ya, sucker!", + L"Come to papa.", + L"Show me your guts!", + L"I'll rip you to pieces!", + L"Motherfucker!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"We're in some real shit...", + L"They said join the army. Not for this shit!", + L"I've had enough!", + L"Oh my God!", + L"They ain't paying us enough for this shit..", + L"Mommy!", + L"I'll be back! With friends!", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"I heard that!", + L"Who's there?", + L"What was that?", + L"Hey! What the...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"They're here!", + L"Now the fun can start!", + L"I hoped this would never happen..", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Aaaggh!", + L"Ugh!", + L"This.. hurts!", + L"You fuck!", + L"You will regret.. uhh.. this.", + L"What the..!", + L"Now you have.. pissed me off.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //ENGLISH diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 5d56c6e0..019abf4e 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -1,4 +1,4 @@ -#pragma setlocale("FRENCH") +//#pragma setlocale("FRENCH") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #else @@ -110,6 +110,25 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +// TODO.Translate +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Page 1/2", //0 + L"Page 2/2", + + L"Page 1/3", + L"Page 2/3", + L"Page 3/3", + + L"Page 1/1", //5 +}; + +// by Jazz: TODO.Translate +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Development Team", @@ -321,6 +340,20 @@ CHAR16 Message[][STRING_LENGTH] = L"Pas de coup par coup", L"L'ennemi n'as plus rien voler!", L"L'ennemi n'a rien dans les mains!", +// TODO.Translate + L"%s's desert camouflage has worn off.", + L"%s's desert camouflage has washed off.", + + L"%s's wood camouflage has worn off.", + L"%s's wood camouflage has washed off.", + + L"%s's urban camouflage urban has worn off.", + L"%s's urban camouflage urban has washed off.", + + L"%s's snow camouflage snow has worn off.", + L"%s's snow camouflage has washed off.", + + L"You cannot attach %s to this slot.", }; @@ -470,9 +503,12 @@ STR16 pPersonnelAssignmentStrings[] = L"Transit", L"Rparation", L"Formation", - L"Milice", + L"Milice", + L"Training Mobile Militia", // TODO.Translate L"Entraneur", - L"Elve", + L"Elve", + L"Facility Staff", // TODO.Translate + L"Resting at Facility", // TODO.Translate L"Mort(e)", L"Incap.", L"Captur(e)", @@ -513,8 +549,11 @@ STR16 pLongAssignmentStrings[] = L"Rparation", L"Formation", L"Milice", + L"Train Mobiles", // TODO.Translate L"Entraneur", - L"Elve", + L"Elve", + L"Staff Facility", // TODO.Translate + L"Rest at Facility", // TODO.Translate L"Mort(e)", L"Incap.", L"Captur(e)", @@ -758,6 +797,63 @@ STR16 pPersonnelScreenStrings[] = L"Blessures :", // number of times merc has been wounded L"Spcialits :", L"Aucune spcialit", + L"Achievements:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elite soldiers: %d\n", + L"Regular soldiers: %d\n", + L"Admin soldiers: %d\n", + L"Hostile groups: %d\n", + L"Creatures: %d\n", + L"Tanks: %d\n", + L"Others: %d\n", + + L"Mercs: %d\n", + L"Militia: %d\n", + L"Others: %d\n", + + L"Shots fired: %d\n", + L"Missiles fired: %d\n", + L"Grenades thrown: %d\n", + L"Knives thrown: %d\n", + L"Blade attacks: %d\n", + L"Hand to hand attacks: %d\n", + L"Successful hits: %d\n", + + L"Locks picked: %d\n", + L"Locks breached: %d\n", + L"Traps removed: %d\n", + L"Explosives detonated: %d\n", + L"Items repaired: %d\n", + L"Items combined: %d\n", + L"Items stolen: %d\n", + L"Militia trained: %d\n", + L"Mercs bandaged: %d\n", + L"Surgeries made: %d\n", + L"Persons met: %d\n", + L"Sectors discovered: %d\n", + L"Ambushes prevented: %d\n", + L"Quests handled: %d\n", + + L"Tactical battles: %d\n", + L"Autoresolve battles: %d\n", + L"Times retreated: %d\n", + L"Ambushes experienced: %d\n", + L"Hardes battle: %d Enemies\n", + + L"Shot: %d\n", + L"Stabbed: %d\n", + L"Punched: %d\n", + L"Blasted: %d\n", + L"Suffered damages in facilities: %d\n", + L"Surgeries undergoed: %d\n", + L"Facility accidents: %d\n", + + L"Character:", + L"Weakening:", }; @@ -780,12 +876,54 @@ STR16 gzMercSkillText[] = L"Couteau", L"Tireur isol", L"Camouflage", - L"Camouflage (Urban)", - L"Camouflage (Desert)", - L"Camouflage (Snow)", + // SANDRO - removed this + //L"Camouflage (Urban)", + //L"Camouflage (Desert)", + //L"Camouflage (Snow)", L"(Expert)", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"No Skill", + + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + // Minor traits + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + // second names for major skills + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", + L"More...", +}; +////////////////////////////////////////////////////////// + // This is pop up help text for the options that are available to the merc @@ -1092,11 +1230,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Etat :", - L"Poids (%s):", + L"Poids:", L"P. d'action", L"Por. :", // Range L"Dg. :", // Damage @@ -1113,35 +1251,41 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L"Attachments:", //14 // TODO.Translate L"AUTO/5:", //15 - L"Munitions :", //16 + L"Remaining ammo:", //16 // TODO.Translate + + // TODO.Translate + L"Default:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Porte", - L"Dgats", - L"Pnalit Rafale/Auto (Moins c'est mieux)", - L"Nombre de tirs pour 5 PA", L"Prcision", + L"Dgats", + L"Porte", + L"Aiming Levels", + L"Facteur de vise", + L"Meilleurs porte maser moyenne", + L"Cache-flammes", + L"Intensit sonore (Moins c'est mieux)", L"Fiabilit", L"Facilit d'entretien", + L"Porte mini pour bonus vise", + L"Facteur de toucher", + L"", //12 L"PA pour mettre en joue", L"PA par tir", L"PA par rafale", L"PA pour tir auto.", L"PA pour recharger", L"PA pour recharger manuellement", - L"Cache-flammes", - L"Intensit sonore (Moins c'est mieux)", - L"Facteur de toucher", - L"Meilleurs porte maser moyenne", - L"Facteur de vise", - L"Porte mini pour bonus vise", + L"", //19 L"Facteur de bipied", + L"Nombre de tirs pour 5 PA", + L"Pnalit Rafale/Auto (Moins c'est mieux)", //22 L"PA pour jeter", L"PA pour lancer", L"PA pour poignarder", @@ -1153,28 +1297,31 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Burst Penalty (Lower is better)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Porte", - L"Dgats", - L"Pnalit Rafale/Auto (Moins c'est mieux)", - L"Nombre de tirs pour 5 PA", L"Prcision", + L"Dgats", + L"Porte", + L"Aiming Levels", + L"Facteur de vise", + L"Meilleurs porte maser moyenne", + L"Cache-flammes", + L"Intensit sonore (Moins c'est mieux)", L"Fiabilit", L"Facilit d'entretien", + L"Porte mini pour bonus vise", + L"Facteur de toucher", + L"", //12 L"PA pour mettre en joue", L"PA par tir", L"PA par rafale", L"PA pour tir auto.", L"PA pour recharger", L"PA pour recharger manuellement", - L"Cache-flammes", - L"Intensit sonore (Moins c'est mieux)", - L"Facteur de toucher", - L"Meilleurs porte maser moyenne", - L"Facteur de vise", - L"Porte mini pour bonus vise", + L"", //19 L"Facteur de bipied", + L"Nombre de tirs pour 5 PA", + L"Pnalit Rafale/Auto (Moins c'est mieux)", //22 L"PA pour jeter", L"PA pour lancer", L"PA pour poignarder", @@ -1298,6 +1445,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1875,6 +2036,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"Espace arien (|A)", L"Objets (|I)", L"Milice & Ennemis (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1908,7 +2070,12 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; + +/* { L"Enrico", L"Psych Pro Inc", @@ -1963,7 +2130,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings @@ -2311,7 +2478,7 @@ STR16 pImpButtonText[] = L"COMMENCER", // begin profiling L"Personnalit", // personality section L"Caractristiques", // personal stats/attributes section - L"Appearance", // changed from portrait - SANDRO + L"Appearance", // changed from portrait L"Voix %d", // the voice selection L"OK", // done profiling L"Recommencer", // start over profiling @@ -2332,12 +2499,12 @@ STR16 pImpButtonText[] = L"Registre", // the IMP site registry..when name and gender is selected L"Analyse", // analyzing your profile results L"OK", - L"Character", // Change from "Voice" - SANDRO + L"Character", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO + // These texts have been also slightly changed L"With your character traits chosen, it is time to select your skills.", L"To complete the process, select your attributes.", L"To commence actual profiling, select portrait, voice and colors.", @@ -3252,7 +3419,13 @@ STR16 CharacterInfo[] = L"Info. complmentaires", // Title for the additional info for the merc's bio L"Membres actifs", //20 // Title of the page L"Matriel optionnel :", // Displays the optional gear cost + L"gear", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"Dpt Mdical", // If the merc required a medical deposit, this is displayed + L"Kit 1", // Text on Starting Gear Selection Button 1 // TODO.Translate + L"Kit 2", // Text on Starting Gear Selection Button 2 + L"Kit 3", // Text on Starting Gear Selection Button 3 + L"Kit 4", // Text on Starting Gear Selection Button 4 + L"Kit 5", // Text on Starting Gear Selection Button 5 }; @@ -3632,6 +3805,9 @@ STR16 zMarksMapScreenText[] = L"Le mercenaire a un contrat dtermin.", L"Ce mercenaire n'est pas assur.", L"Ecran carte", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3697,22 +3873,25 @@ STR16 zOptionsToggleText[] = L"Curseur Tot", L"Afficher Chance de toucher", L"Curseur raf. pour raf. LanceG.", - L"Tout materiel lch", + L"Allow Enemy Taunts", // Changed from "Enemies Drop all Items" - SANDRO L"Lancemt Grenades grand angle", - L"Restreindre niv. sup. de vise", + L"Allow Real Time Sneaking", // Changed from "Restrict extra Aim Levels" - SANDRO L"Espace pour escouade suivante", L"Ombres objets", L"Afficher porte armes en cases", L"Balle Traante pour tir simple", L"Son de pluie", L"Afficher corbeaux", - L"Show Soldier Tooltips", // Changed from "Random I.M.P personality" - SANDRO + L"Show Soldier Tooltips", L"Sauvegarde auto", L"Silence Skyrider !", L"Faible consommation processeur", L"EDB (mod rajoutant info utiles)", L"Mode tour par tour forc", // add forced turn mode L"Stat Progress Bars", // Show progress towards stat increase // TODO.Translate + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) // TODO.Translate L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3731,13 +3910,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"Activez cette option pour entendre vos mercenaires lorsqu'ils parlent.", //Mute Confirmation L"Active/dsactive les confirmations des mercenaires.", - //Subtitles + //Subtitles L"Affichage des sous-titres l'cran.", //Key to advance speech @@ -3793,22 +3974,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"Si activ, affiche une barre de probabilits de succs sur le curseur.", L"Si activ, les rafales de lance grenades ont un curseur de rafale.", - L"Si activ, les ennemis lchent tout le materiel qu'ils portaient.", + L"When ON, enemies will occasionally comment certain actions.", // Changed from Enemies Drop All Items - SANDRO L"Si activ, les grenades lances grenades ont un grand angle (|Q).", - L"Si activ, les niveaux de vise apres 4 cliks sont rservs aux fusils ou sniper.", + L"When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"Si activ, |S|p|a|c|e selectionne l'escouade suivante.", L"Si activ, les ombres d'objets sont affiches.", L"Si activ, la porte des armes est affiche en nombres de cases.", L"Si activ, les effets de traantes sont affichs pour les tir simples.", L"Si activ, le son de pluie est audible quand il pleut.", L"Si activ, les corbeaux sont prsents dans le jeu.", - L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", // - Changed from random IMP personality - SANDRO + L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", L"Si activ, le jeu est sauvegard chaque nouveau tour joueur.", L"Si activ, les confirmations insistantes de Skyrider cessent.", L"Si activ, le jeu restreint l'utilisation du processeur.", L"Si activ, l'EDB sera affich pour les armes et objets.", L"Si cette option est active et que des ennemis sont prsents, \nle mode tour par tour est actif tant qu'il reste \ndes ennemis dans le secteur (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode L"When ON, shows character progress towards gaining levels.", // TODO.Translate + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"When ON, alternate bullet graphics will be shown when you shoot.", // TODO.Translate L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3841,7 +4025,7 @@ STR16 gzGIOScreenText[] = L"Expriment", L"Expert", L"INCROYABLE", - L"Ok", + L"Start", // TODO.Translate L"Annuler", L"En combat", L"Sauv. volont", @@ -3852,11 +4036,42 @@ STR16 gzGIOScreenText[] = L"Meilleure", L"Excellente", L"Superbe", - L"Inventaire", - L"Original", - L"Nouveau", + L"Inventory / Attachments", // TODO.Translate + L"NOT USED", + L"NOT USED", L"Charge jeu multi", L"CONFIGURATION DU JEU (Les paramtres serveur seulement prennent effet)", + // Added by SANDRO + L"Skill Traits", + L"Old", + L"New", + L"Max IMP Characters", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Enemies Drop All Items", + L"Off", + L"On", + L"Number of Terrorists", + L"Random", + L"All", + L"Secret Weapon Caches", + L"Random", + L"All", + L"Progress Speed of Item Choices", + L"Very Slow", + L"Slow", + L"Normal", + L"Fast", + L"Very Fast", + + // TODO.Translate + L"Old / Old", + L"New / Old", + L"New / New", }; STR16 gzMPJScreenText[] = @@ -3879,6 +4094,24 @@ STR16 gzMPJScreenText[] = L"You must enter a valid Server Port between 1 and 65535.", }; +// TODO.Translate +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { L"HOST GAME", @@ -3887,36 +4120,72 @@ STR16 gzMPHScreenText[] = L"Server Name", L"Game Type", L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"Max Players", - L"Squad Size", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", L"Merc Selection", - L"Random Mercs", + L"Merc Hiring", L"Hired by Player", - L"Starting Balance", - L"Can Hire Same Merc", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"Allow Bobby Rays", - L"Randomise Starting Edge", + L"Bobby Rays", + L"Sector Starting Edge", L"You must enter a server name", - L"Max Players must be between 2 and 4", - L"Squad size must be between 1 and 6", - L"Time of Day", - L"Time of Day must be a 24 hour time (HH:MM)", - L"Starting Cash must be a valid dollar amount (no cents)" , - L"Damage Multiplier", - L"Damage Multiplier must be a number between 0 and 5", - L"Turn Timer Multiplier", - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", L"Enable Civilians in CO-OP", - L"Use New Inventory (NIV)", - L"Enforce Maximum AI Enemies", - L"Sync. MP Clients Directory", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", L"MP Sync. Directory", L"You must enter a file transfer directory.", L"(Use '/' instead of '\\' for directory delimiters.)", L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4094,8 +4363,8 @@ STR16 pMessageStrings[] = L"Historique mis jour.", L"Curseur de vise pour raf.Gre. (Dispersion active)", L"Curseur de trajectoire raf.gre. (Dispersion desact.)", - L"Lcher tout activ", - L"Lcher tout dsactiv", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"Angles standards pour lance-grenades", L"Lance-grenades grands angles", // forced turn mode strings @@ -4108,6 +4377,9 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved. L"Client", + + // TODO.Translate + L"You cannot use the Old Inventory and the New Attachment System at the same time.", }; @@ -4416,7 +4688,7 @@ STR16 gzLateLocalizedString[] = L"%s a rpar pour %s : %s",//inverted order !!! Red has repaired the MP5 of Scope //36 - L"Chat Sauvage", + L"Chat", // Max. 9 Characters. Should be "bloodcat". //37-38 "Name trips and falls" L"%s trbuche et tombe", @@ -4471,7 +4743,7 @@ STR16 gzLateLocalizedString[] = L"%s: attachement de protection dtruit !", L"%s tire %d fois de plus que prvu !", - L"%s tire %d fois de plus que prvu !", + L"%s tire 1 fois de plus que prvu !", }; STR16 gzCWStrings[] = @@ -4522,6 +4794,10 @@ STR16 gzTooltipStrings[] = L"no Vest", L"no Leggings", L"|Armor: %s\n", + // Added - SANDRO + L"%s|Skill 1: %s\n", + L"%s|Skill 2: %s\n", + L"%s|Skill 3: %s\n", }; STR16 New113Message[] = @@ -4550,7 +4826,25 @@ STR16 New113Message[] = L"No enemies in sight", L"Real-time sneaking OFF", L"Real-time sneaking ON", - L"Enemy spotted! (Ctrl + x to enter turn based)", + L"Enemy spotted!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s was successful on stealing!", + L"%s had not enough action points to steal all selected items.", + L"Do you want to make surgery on %s before bandaging? (You can heal about %i Health.)", + L"Do you want to make surgery on %s? (You can heal about %i Health.)", + L"Do you wish to make necessary surgeries first? (%i patient(s))", + L"Do you wish to make the surgery on this patient first?", + L"Apply first aid automatically with necessary surgeries or without them?", + L"Surgery on %s finished.", + L"%s is hit in the chest and loses a point of maximum health!", + L"%s is hit in the chest and loses %d points of maximum health!", + L"%s has regained one point of lost %s", + L"%s has regained %d points of lost %s", + L"Your scouting skills prevented you to be ambushed by the enemy!", + L"Thanks to your scouting skills you have successfuly avoided a pack of bloodcats!", + L"%s is hit to groin and falls down in pain!", + ////////////////////////////////////////////////////////////////////////////////////// }; // TODO.Translate @@ -4599,6 +4893,42 @@ STR16 New113MERCMercMailTexts[] = L"Prenez note. De par des performances accrues Biggens voit le prix de ses services augments. Speck T. Kline ", }; +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"TR du serveur AIM: Message de Victor Kolesnikov", + L"Salut. Ici Monk. Message reu. Je suis disponible si vous voulez me voir. Jattends votre appel. ", + + // Brain + L"TR du serveur AIM: Message de Janno Allik", + L"Je suis prt conciderer votre offre. Il y a un temps et un lieu pour tout. Janno Allik ", + + // Scream + L"TR du serveur AIM: Message de Lennart Vilde", + L"Lennart Vilde est maintenant disponible! ", + + // Henning + L"TR du serveur AIM: Message de Henning von Branitz", + L"Jai reu votre message, merci. Pour parler dembauche, contactez-moi sur le site web de lAIM. Henning von Branitz ", + + // Luc + L"TR du serveur AIM: Message de Luc Fabre", + L"Message reu, merci! Je suis heureux de considrer votre proposition. Vous savez o me trouver. Au plaisir de vous entendre.", + + // Laura + L"TR du serveur AIM: Message de Dr. Laura Colin", + L"Salutations! Merci pour votre message, il semble intressant. Visiter lAIM nouveau, je serais ravie den entendre plus. Cordialement! Dr. Laura Colin ", + + // Grace + L"TR du serveur AIM: Message de Graziella Girelli", + L"Vous vouliez me contacter, mais vous navez pas russi. Une runion de famille. Je suis sr que vous comprenez? Jen ai maintenant assez de la famille et serait trs heureuse si vous voulez me contacter de nouveau sur le site AIM. Ciao! ", + + // Rudolf + L"TR du serveur AIM: Message de Rudolf Steiger", + L"Vous savez combien jai dappel par jour ? Tous les branleurs pensent pouvoir mappeler. Mais je suis de retour, si vous avez quelque chose dintressant pour moi.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4607,6 +4937,25 @@ STR16 MissingIMPSkillsDescriptions[] = L"Tireur isol : Des yeux de faucon, vous pouvez tirer les ailes d'une mouche cent mtres! ", // Camouflage L"Camouflage : Sans compter que derrire vous mme les buissons semblent synthtiques! ", + // SANDRO - new strings for new traits added + // Ranger + L"Ranger: You are the one from Texas deserts, aren't you! ", + // Gunslinger + L"Gunslinger: With a handgun or two, you can be as lethal as the Billy Kid! ", + // Squadleader + L"Squadleader: Natural leader and boss, you are the big shot no kidding! ", + // Technician + L"Technician: Fixing stuff, removing traps, planting bombs, that's your bussiness! ", + // Doctor + L"Doctor: You can make a quick surgery with pocket-knife and chewing gum anywhere! ", + // Athletics + L"Athletics: Your speed and vitality is on top of possibilities! ", + // Bodybuilding + L"Bodybuilding: That big muscular figure which cannot be overlooked is you actually! ", + // Demolitions + L"Demolitions: You can blow up a whole city just by common home stuff! ", + // Scouting + L"Scouting: Nothing can escape your notice! ", }; STR16 NewInvMessage[] = @@ -4672,12 +5021,10 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"Grid Number: %d", L"Server only feature", - L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", + L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Timed Turns=%d, Secs/Tic=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", - // 25 - L"Testing and cheat function '9' is enabled.", + L"", L"New connection: Client #%d - '%S'.", L"Team: %d.",//not used any more L"'%s' (client %d - '%S') was killed by '%s' (client %d - '%S')", @@ -4729,31 +5076,18 @@ STR16 MPClientMessage[] = L"Cannot connect because your version %S is different from the server version %S.", L"You killed an enemy soldier.", L"Cannot start the game, because all teams are the same.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Welcome to JAGGED ALLIANCE 2 v1.13 Multiplayer", - L"Press 'F1' for help", - L"Multiplayer controls (from strategy screen)", - L"* first set up ja2_mp.ini *", - L"'1' - Start server", - // 5 - L"'2' - Connect to server", - L"'3' - If server unlock laptop, set client ready for battle", - L"'4' - Quit server and client", - L"'5' - Display mouse coords (from tactical screen)", - L"'7' - Popup dialog for server override panel", - // 10 - L"'F2' - Display secondary help", - L"See readme_mp.html for further details", - L"Tips: (assuming ja2_mp.ini is set up)", - L"* Make sure all clients have unique CLIENT_NUM *", - L"* Game save doesn't record bobby rays order *", - // 15 - L"* Avoid placing opposed mercs in immediate sight *", - L"'F1' - Display primary help", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 // TODO.Translate + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; STR16 gszMPEdgesText[] = @@ -4830,16 +5164,24 @@ STR16 gzMPChatboxText[] = // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected. To achieve an expert level on a trait, simply choose only that one trait.", - L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels, and if you choose one of them only, you will have only one skill trait.", + // For old traits + L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected.", + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics, Ambidextrous and Camouflage traits cannot be achieved at expert levels.", + // For new major/minor traits + L"Next stage is about choosing your skill traits according to your proffessional specialization as a mercenary. On first page you can select up to two potential major traits, which mostly represent your main role in a team. While on second page is list of possible minor traits, which represent personal feats.", + L"No more then three choices altogeher are possible. Which means if you choose no major traits, you can then choose three minor traits. If you choose both major traits (or one enhanced), you can then choose only one minor trait...", }; STR16 sgAttributeSelectionText[] = { - L"Please adjust your physical attributes as comapred to that of an avarage merc. You cannot raise any score above", + L"Please adjust your physical attributes according to your true abilities. You cannot raise any score above", L"I.M.P. Attributes and skills review.", L"Bonus Pts.:", L"Starting Level", + // New strings for new traits + L"On the next page you are going to specify your physical attributes and skills. As 'attributes' are called: health, dexterity, agility, strength and wisdom. Attributes cannot go lower than %d.", + L"The rest are called 'skills' and unlike attributes skills can be set to zero meaning you have absolutely no proficieny in it.", + L"All scores are set to a minimum at the beginning. Note that certain attributes are set to specific values according to skill traits you have selected. You cannot set those attributes lower than that.", }; STR16 pCharacterTraitBeginIMPStrings[] = @@ -4849,7 +5191,7 @@ STR16 pCharacterTraitBeginIMPStrings[] = L"The second page enlists possible disabilities you might have. If you suffer from any of these disabilities, choose which one (we believe that everyone has only one such disablement). Be honest, as it is important to inform potential employers of your true condition.", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"Normal", L"Friendly", @@ -4861,6 +5203,24 @@ STR16 gzIMPCharacterTraitText[]= L"Big Shot", L"Asshole", L"Coward", + L"I.M.P. Attitudes", +}; + +STR16 gzIMPCharacterTraitText[]= +{ + L"Normal", + L"Sociable", + L"Loner", + L"Optimist", + L"Assertive", + L"Intellectual", + L"Primitive", + L"Aggressive", + L"Phlegmatic", + L"Dauntless", + L"Pacifist", + L"Malicious", + L"Show-off", L"I.M.P. Character Traits", }; @@ -4871,6 +5231,7 @@ STR16 gzIMPColorChoosingText[] = L"Please select the respective colors of your skin, hair and clothing. And select what body type you have.", L"Please select the respective colors of your skin, hair and clothing.", L"Toggle this to use alternative rifle holding.", + L"\n(Caution: you will need a big strength for this.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -5008,4 +5369,498 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 mode fentr exige une profondeur de couleur de 16 bit ou moins.", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Suck this!", + L"Touch this!", + L"Come get some!", + L"You're mine!", + L"Die!", + L"You scared, motherfucker?", + L"This will hurt!", + L"Come on you bastard!", + L"Come on! I don't got all day!", + L"Come to daddy!", + L"You'll be six feet under in no time!", + L"Will send ya home in a pinebox, loser!", + L"Hey, wanna play?", + L"You should have stayed home, bitch.", + L"Sucker!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"We have a barbecue here.", + L"I got a present for ya.", + L"Bam!", + L"Smile!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Catch!", + L"Here ya go!", + L"Pop goes the weasel.", + L"This one's for you.", + L"Muhehe.", + L"Catch this, swine!", + L"I like this.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"I'll get your scalp.", + L"Come to papa.", + L"Show me your guts!", + L"I'll rip you to pieces!", + L"Motherfucker!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"We're in some real shit...", + L"They said join the army. Not for this shit!", + L"I have enough.", + L"Oh my God.", + L"They ain't paying us enough for this.", + L"It's just too much for me.", + L"I'll bring some friends.", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"I heard that!", + L"Who's there?", + L"What was that?", + L"Hey! What the...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"They are here!", + L"Now the fun can start.", + L"I hoped this will never happen.", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Ouch!", + L"Ugh!", + L"This.. hurts!", + L"You fuck!", + L"You will regret.. uhh.. this.", + L"What the..!", + L"Now you have.. pissed me off.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //FRENCH diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 158c597e..6c13872c 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -1,4 +1,4 @@ -#pragma setlocale("GERMAN") +//#pragma setlocale("GERMAN") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #else @@ -110,6 +110,47 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +/* +LOOTF - Foot note. I've rewritten a whole lot of stuff and only marked specific lines and blocks. + That's where I'm either + + - not sure about the character limit (might not be mentioned but causes trouble when displaying texts?) + - not sure about the meaning + - not sure if people will like it (this concerns German speakers) + - not as creative as to find a perfect replacement + +I have also changed stuff people might have found okay, which only troubled me. +This includes + "Zurckziehen". Klingt einfach nicht. Hrt sich an wie sich zur Nachtruhe begeben. +"Zurckgezogen" ist ein Waldschrat. Gendert auf "ausgewichen". +Ich hoffe nur, dass nicht irgendjemand dumm rumschwtzt wegen Kugeln ausweichen oder so. + +Anything else is a-ok and can be filtered out by comparing this cpp with the old version. +I have also added tabs and removed some where I thought it was appropriate (format-wise). +My comments are marked using LOOTF. +Comments for SANDRO are marked using LOOTF - SANDRO. +Remove any LOOTF comment that has been checked, except maybe for "alt." (alternative) stuff or stuff of that sort. + +07/2010 LootFragg +*/ +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Seite 1/2", //0 + L"Seite 2/2", + + L"Seite 1/3", + L"Seite 2/3", + L"Seite 3/3", + + L"Seite 1/1", //5 +}; + +// by Jazz +CHAR16 zGrod[][500] = +{ + L"Roboter", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Entwicklungsteam", @@ -118,7 +159,7 @@ STR16 pCreditsJA2113[] = L"@};(Verschiedene weiter Mods!)", L"@T,C144,R134,{;Gegenstnde", L"@T,C144,R134,{;Weitere Mitwirkende", - L"@};(Alle weiteren Community Mitglieder die Ideen und Feedback eingebracht haben!)", + L"@};(Alle weiteren Community-Mitglieder die Ideen und Feedback eingebracht haben!)", }; CHAR16 ItemNames[MAXITEMS][80] = @@ -266,7 +307,7 @@ CHAR16 Message[][STRING_LENGTH] = // The first %s is a merc name and the second %s is an item name - L"Zweite Waffe hat keine Ammo!", + L"Zweite Waffe hat keine Munition!", L"%s hat %s gestohlen.", // The %s is a merc name @@ -278,17 +319,17 @@ CHAR16 Message[][STRING_LENGTH] = // Both %s's are item names - L"Sie knnen %s mit %s nicht zusammenfgen", + L"Sie knnen %s mit %s nicht kombinieren", L"Keine", - L"Ammo entfernen", + L"Waffen entladen", // = Removing ammo from weapons on the ground on pressing Shift + F if set in options. L"Modifikationen", //You cannot use "item(s)" and your "other item" at the same time. - //Ex: You cannot use sun goggles and you gas mask at the same time. + //Ex: You cannot use sun goggles and your gas mask at the same time. L"Sie knnen %s nicht zusammen mit %s benutzen.", // - L"Der Gegenstand in Ihrem Cursor kann mit anderen Gegenstnden verbunden werden, indem Sie ihn in einem der vier Slots platzieren", + L"Der Gegenstand in Ihrem Cursor kann mit anderen Gegenstnden verbunden werden, indem Sie ihn in einem der vier Slots platzieren.", L"Der Gegenstand in Ihrem Cursor kann mit anderen Gegenstnden verbunden werden, indem Sie ihn in einem der vier Attachment-Slots platzieren. (Aber in diesem Fall sind die Gegenstnde nicht kompatibel.)", L"Es sind noch Feinde im Sektor!", L"Geben Sie %s %s", @@ -297,7 +338,7 @@ CHAR16 Message[][STRING_LENGTH] = L"Die Modifikation ist permanent. Weitermachen?", L"%s fhlt sich frischer!", L"%s ist auf Murmeln ausgerutscht!", - L"%s konnte %s aus der Hand des Feindes nicht stehlen!", + L"%s konnte %s nicht aus der Hand des Feindes stehlen!", L"%s hat %s repariert", L"Unterbrechung fr ", L"Ergeben?", @@ -313,6 +354,19 @@ CHAR16 Message[][STRING_LENGTH] = L"kein Einzelschuss", L"Der Feind besitzt keine Gegenstnde mehr zum Stehlen!", L"Der Feind hat keinen Gegenstand in seiner Hand!", + + L"%s's Wstentarnung ist nicht mehr effektiv.", + L"%s's Wstentarnung wurde heruntergewaschen.", + + L"%s's Waldtarnung ist nicht mehr effektiv.", + L"%s's Waldtarnung wurde heruntergewaschen.", + + L"%s's Stadttarnung ist nicht mehr effektiv.", + L"%s's Stadttarnung wurde heruntergewaschen.", + + L"%s's Schneetarnung ist nicht mehr effektiv.", + L"%s's Schneetarnung wurde heruntergewaschen.", + L"Sie knnen %s nicht an diesem Slot anbringen.", }; CHAR16 pTownNames[MAX_TOWNS][MAX_TOWN_NAME_LENGHT] = @@ -382,7 +436,7 @@ STR16 pAssignmentStrings[] = L"Betrieb", // operating a strategic facility L"Pause", // Resting at a facility L"Tot", // dead - L"Unfhig", // abbreviation for incapacitated + L"Koma", // abbreviation for incapacitated //LOOTF - "Unfhig" klingt schlimm. Gendert auf Koma. Vorschlge? L"Gefangen", // Prisoner of war - captured L"Hospital", // patient in a hospital L"Leer", //Vehicle is empty @@ -453,16 +507,19 @@ STR16 pPersonnelAssignmentStrings[] = L"Patient", L"Fahrzeug", L"Transit", - L"Repar.", + L"Reparieren", L"ben", - L"Miliz", + L"Miliz", + L"Trainiere Mobile Miliz", L"Trainer", - L"Rekrut", + L"Rekrut", + L"Betriebspersonal", + L"Betriebspause", L"Tot", - L"Unfhig", + L"Koma", //LOOTF - s.o. L"Gefangen", L"Hospital", - L"Leer", // Vehicle is empty + L"Leer", // Vehicle is empty }; // refer to above for comments @@ -493,11 +550,14 @@ STR16 pLongAssignmentStrings[] = L"Patient", L"Fahrzeug", L"Transit", - L"Repar.", + L"Reparieren", L"ben", L"Miliz", + L"Trainiere Mobile", L"Trainer", - L"Rekrut", + L"Rekrut", + L"Betriebspersonal", + L"Betriebspause", L"Tot", L"Unfhig", L"Gefangen", @@ -566,7 +626,7 @@ STR16 pUpperLeftMapScreenStrings[] = L"Vertrag", // the contract info about the merc L"Gesundh.", // the health level of the current merc L"Moral", // the morale of the current merc - L"Zust.", // the condition of the current vehicle + L"Zustand", // the condition of the current vehicle L"Tank", // the fuel level of the current vehicle }; @@ -582,7 +642,7 @@ STR16 pGuardMenuStrings[] = { L"Schussrate:", // the allowable rate of fire for a merc who is guarding L" Aggressiv feuern", // the merc can be aggressive in their choice of fire rates - L" Ammo sparen", // conserve ammo + L" Munition sparen", // conserve ammo L" Nur bei Bedarf feuern", // fire only when the merc needs to L"Andere Optionen:", // other options available to merc L" Rckzug mglich", // merc can retreat @@ -597,7 +657,7 @@ STR16 pOtherGuardMenuStrings[] = { L"Schussrate:", L" *Aggressiv feuern*", - L" *Ammo sparen*", + L" *Munition sparen*", L" *Nur bei Bedarf feuern*", L"Andere Optionen:", L" *Rckzug mglich*", @@ -622,31 +682,31 @@ STR16 pAssignMenuStrings[] = //lal STR16 pMilitiaControlMenuStrings[] = { - L"Angreifen", // set militia to aggresive - L"Position halten", // set militia to stationary - L"Rckzug", // retreat militia - L"An meine Position", // retreat militia - L"Auf den Boden", // retreat militia + L"Angreifen", // set militia to aggresive + L"Position halten", // set militia to stationary + L"Rckzug", // retreat militia + L"An meine Position", // retreat militia + L"Auf den Boden", // retreat militia L"In Deckung gehen", L"Alle: Angreifen", L"Alle: Position halten", L"Alle: Rckzug", L"Alle: An meine Position", - L"Alle: Alle verteilen", + L"Alle: Ausschwrmen", L"Alle: Auf den Boden", L"Alle: In Deckung gehen", //L"All: Find items", - L"Abbrechen", // cancel this menu + L"Abbrechen", // cancel this menu }; //STR16 pTalkToAllMenuStrings[] = //{ -// L"Attack", // set militia to aggresive -// L"Hold Position", // set militia to stationary -// L"Retreat", // retreat militia -// L"Come to me", // retreat militia -// L"Get down", // retreat militia -// L"Cancel", // cancel this menu +// L"Attack", // set militia to aggresive +// L"Hold Position", // set militia to stationary +// L"Retreat", // retreat militia +// L"Come to me", // retreat militia +// L"Get down", // retreat militia +// L"Cancel", // cancel this menu //}; STR16 pRemoveMercStrings[] ={ @@ -710,31 +770,101 @@ STR16 pPersonnelTitle[] = STR16 pPersonnelScreenStrings[] = { - L"Gesundheit: ", // health of merc - L"Beweglichkeit: ", - L"Geschicklichkeit: ", - L"Kraft: ", - L"Fhrungsqualitt: ", - L"Weisheit: ", - L"Erf. Stufe: ", // experience level - L"Treffsicherheit: ", - L"Technik: ", - L"Sprengstoffe: ", - L"Medizin: ", - L"Med. Versorgung: ", // amount of medical deposit put down on the merc - L"Laufzeit: ", // time remaining on current contract - L"Gettet: ", // number of kills by merc - L"Mithilfe: ", // number of assists on kills by merc - L"Tgl. Kosten:", // daily cost of merc - L"Gesamtkosten:", // total cost of merc - L"Vertrag:", // cost of current contract - L"Diensttage:", // total service rendered by merc - L"Schulden:", // amount left on MERC merc to be paid - L"Prozentzahl Treffer:", // percentage of shots that hit target - L"Einstze:", // number of battles fought - L"Verwundungen:", // number of times merc has been wounded - L"Fhigkeiten:", - L"Keine Fhigkeiten:", + L"Gesundheit: ", // Stat: Health of merc + L"Beweglichkeit: ", // Stat: Agility + L"Geschicklichkeit: ", // Stat: Dexterity + L"Kraft: ", // Stat: Strength + L"Fhrungsqualitt: ", // Stat: Leadership + L"Weisheit: ", // Stat: Wisdom + L"Erfahrungsstufe: ", // Stat: Experience level + L"Treffsicherheit: ", // Stat: Marksmanship + L"Technik: ", // Stat: Mechanical + L"Sprengstoffe: ", // Stat: Explosives + L"Medizin: ", // Stat: Medical + L"Med. Vorsorge: ", // amount of medical deposit put down on the merc + L"Laufzeit: ", // time remaining on current contract + L"Gettet: ", // number of kills by merc + L"Mithilfe: ", // number of assists on kills by merc + L"Tgl. Kosten:", // daily cost of merc + L"Gesamtkosten:", // total cost of merc + L"Vertrag:", // cost of current contract + L"Diensttage:", // total service rendered by merc + L"Schulden:", // amount left on MERC merc to be paid + L"Trefferquote:", // percentage of shots that hit target + L"Einstze:", // number of battles fought + L"Verwundungen:", // number of times merc has been wounded + L"Fhigkeiten:", // Traits + L"Keine Fhigkeiten:", // No traits + L"Aktivitten:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + // GETTET + // 0 + L"Elite Soldaten: %d\n", + L"Regulre Soldaten: %d\n", + L"Admin Soldaten: %d\n", + L"Feindliche Gruppen: %d\n", + L"Monster: %d\n", + L"Panzer: %d\n", + L"Andere: %d\n", + + // MITHILFE + // 7 + L"Sldner: %d\n", + L"Miliz: %d\n", + L"Andere: %d\n", + + // TREFFERQUOTE + // 10 + L"Schsse gefeuert: %d\n", + L"Raketen gefeuert: %d\n", + L"Granaten geworfen: %d\n", + L"Messer geworfen: %d\n", + L"Klinge attakiert: %d\n", + L"Nahkampf attakiert: %d\n", + L"Gelandete Treffer: %d\n", + + // AKTIVITTEN + // 17 + L"Schlsser geknackt: %d\n", + L"Schlsser gebrochen: %d\n", + L"Fallen entschrft: %d\n", + L"Sprenstoffe entzndet: %d\n", + L"Gegenstnde repariert: %d\n", + L"Gegenstnde kombiniert: %d\n", + L"Gegenstnde gestohlen: %d\n", + L"Miliz trainiert: %d\n", + L"Soldaten verbunden: %d\n", + L"Operation gemacht: %d\n", + L"Personen bekanntgemacht: %d\n", + L"Sektoren erkundet: %d\n", + L"Hinterhalte vermieden: %d\n", + L"Auftrge erledigt: %d\n", + + // EINSTZE + // 31 + L"Taktische Kmpfe: %d\n", + L"Automatische Kmpfe: %d\n", + L"Fluchtversuche: %d\n", + L"Erfolgreiche Hinterhalte: %d\n", + L"Schwerster Kampf: %d Feinde\n", + + // VERWUNDUNGEN + // 36 + L"Angeschossen: %d\n", + L"Angestochen: %d\n", + L"Geschlagen: %d\n", + L"Explosionsverletzungen: %d\n", + L"Schaden erlitten in Anlagen: %d\n", + L"Operationen ertragen: %d\n", + L"Unflle in Anlagen: %d\n", + + // 43 + L"Charakter:", + L"Schwchen:", }; @@ -763,6 +893,50 @@ STR16 gzMercSkillText[] = L"(Experte)", }; +////////////////////////////////////////////////////////// +// SANDRO - added this + +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"Keine Fertigkeit", + + L"MG-Schtze", + L"Grenadier", + L"Przisionsschtze", + L"Pfadfinder", + L"Pistolenschtze", + L"Faustkmpfer", + L"Gruppenfhrer", + L"Mechaniker", + L"Sanitter", + + // Minor traits + L"Beidhnder", + L"Messerkmpfer", + L"Messerwerfer", + L"Nachtmensch", + L"Schleicher", + L"Lufer", + L"Kraftsportler", + L"Sprengmeister", + L"Ausbilder", + L"Aufklrer", + + // second names for major skills + L"MG-Veteran", + L"Artillerist", + L"Scharfschtze", + L"Jger", + L"Revolverheld", + L"Kampfsportler", + L"Zugfhrer", + L"Ingenieur", + L"Arzt", + + L"Mehr...", +}; + // This is pop up help text for the options that are available to the merc STR16 pTacticalPopupButtonStrings[] = { @@ -770,8 +944,8 @@ STR16 pTacticalPopupButtonStrings[] = L"Kauern/Kauernd bewegen (|C)", L"Stehen/|Rennen", L"Hinlegen/Kriechen (|P)", - L"Schauen (|L)", - L"Action", + L"B|licken", + L"Aktion", L"Reden", L"Untersuchen (|C|t|r|l)", @@ -783,7 +957,7 @@ STR16 pTacticalPopupButtonStrings[] = L"Falle entschrfen", L"Abschlieen", L"Aufschlieen", - L"Sprengstoff an Tr benutzen", + L"Schloss aufsprengen", L"Brecheisen benutzen", L"Rckgngig (|E|s|c)", L"Schlieen", @@ -804,7 +978,7 @@ STR16 pContractExtendStrings[] = { L"1 Tag", L"1 Woche", - L"2 Wochen", // + L"2 Wochen", }; // On the map screen, there are four columns. This text is popup help text that identifies the individual columns. @@ -915,59 +1089,59 @@ STR16 gpStrategicString[] = L"", //Unused L"%s wurden entdeckt in Sektor %c%d und ein weiterer Trupp wird gleich ankommen.", //STR_DETECTED_SINGULAR L"%s wurden entdeckt in Sektor %c%d und weitere Trupps werden gleich ankommen.", //STR_DETECTED_PLURAL - L"Gleichzeitige Ankunft koordinieren?", //STR_COORDINATE + L"Gleichzeitige Ankunft koordinieren?", //STR_COORDINATE //Dialog strings for enemies. - L"Feind bietet die Chance zum Aufgeben an.", //STR_ENEMY_SURRENDER_OFFER - L"Feind hat restliche bewusstlose Sldner gefangen genommen.", //STR_ENEMY_CAPTURED + L"Feind bietet die Chance zum Aufgeben an.", //STR_ENEMY_SURRENDER_OFFER + L"Feind hat restliche bewusstlose Sldner gefangen genommen.", //STR_ENEMY_CAPTURED //The text that goes on the autoresolve buttons - L"Rckzug", //The retreat button //STR_AR_RETREAT_BUTTON - L"Fertig", //The done button //STR_AR_DONE_BUTTON + L"Rckzug", //The retreat button //STR_AR_RETREAT_BUTTON + L"Fertig", //The done button //STR_AR_DONE_BUTTON //The headers are for the autoresolve type (MUST BE UPPERCASE) - L"VERTEIDIGUNG", //STR_AR_DEFEND_HEADER - L"ANGRIFF", //STR_AR_ATTACK_HEADER - L"BEGEGNUNG", //STR_AR_ENCOUNTER_HEADER - L"Sektor", //The Sector A9 part of the header //STR_AR_SECTOR_HEADER + L"VERTEIDIGUNG", //STR_AR_DEFEND_HEADER + L"ANGRIFF", //STR_AR_ATTACK_HEADER + L"BEGEGNUNG", //STR_AR_ENCOUNTER_HEADER + L"Sektor", //The Sector A9 part of the header //STR_AR_SECTOR_HEADER //The battle ending conditions - L"SIEG!", //STR_AR_OVER_VICTORY - L"NIEDERLAGE!", //STR_AR_OVER_DEFEAT - L"AUFGEGEBEN!", //STR_AR_OVER_SURRENDERED - L"GEFANGENGENOMMEN!", //STR_AR_OVER_CAPTURED - L"ZURCKGEZOGEN!", //STR_AR_OVER_RETREATED + L"SIEG!", //STR_AR_OVER_VICTORY + L"NIEDERLAGE!", //STR_AR_OVER_DEFEAT + L"AUFGEGEBEN!", //STR_AR_OVER_SURRENDERED + L"GEFANGENGENOMMEN!", //STR_AR_OVER_CAPTURED + L"AUSGEWICHEN!", //STR_AR_OVER_RETREATED //These are the labels for the different types of enemies we fight in autoresolve. - L"Miliz", //STR_AR_MILITIA_NAME, - L"Elite", //STR_AR_ELITE_NAME, - L"Trupp", //STR_AR_TROOP_NAME, - L"Verwal", //STR_AR_ADMINISTRATOR_NAME, - L"Monster", //STR_AR_CREATURE_NAME, + L"Miliz", //STR_AR_MILITIA_NAME, + L"Elite", //STR_AR_ELITE_NAME, + L"Soldat", //STR_AR_TROOP_NAME, + L"Admin.", //STR_AR_ADMINISTRATOR_NAME, + L"Monster", //STR_AR_CREATURE_NAME, //Label for the length of time the battle took - L"Zeit verstrichen", //STR_AR_TIME_ELAPSED, + L"Zeit verstrichen", //STR_AR_TIME_ELAPSED, //Labels for status of merc if retreating. (UPPERCASE) - L"HAT SICH ZURCKGEZOGEN", //STR_AR_MERC_RETREATED, - L"ZIEHT SICH ZURCK", //STR_AR_MERC_RETREATING, - L"RCKZUG", //STR_AR_MERC_RETREAT, + L"IST AUSGEWICHEN", //STR_AR_MERC_RETREATED, + L"WEICHT AUS", //STR_AR_MERC_RETREATING, + L"RCKZUG", //STR_AR_MERC_RETREAT, //PRE BATTLE INTERFACE STRINGS //Goes on the three buttons in the prebattle interface. The Auto resolve button represents //a system that automatically resolves the combat for the player without having to do anything. //These strings must be short (two lines -- 6-8 chars per line) - L"PC Kampf", //STR_PB_AUTORESOLVE_BTN, - L"Gehe zu Sektor", //STR_PB_GOTOSECTOR_BTN, - L"Rckzug", //STR_PB_RETREATMERCS_BTN, + L"PC-Kampf", //STR_PB_AUTORESOLVE_BTN, + L"Gehe zu Sektor", //STR_PB_GOTOSECTOR_BTN, + L"Rckzug", //STR_PB_RETREATMERCS_BTN, //The different headers(titles) for the prebattle interface. L"FEINDBEGEGNUNG", @@ -988,10 +1162,10 @@ STR16 gpStrategicString[] = L"Monster", L"Bloodcats", L"Sektor", - L"Keine", //If there are no uninvolved mercs in this fight. + L"Keine", //If there are no uninvolved mercs in this fight. L"n.a.", //Acronym of Not Applicable - L"T", //One letter abbreviation of day - L"h", //One letter abbreviation of hour + L"T", //One letter abbreviation of day + L"h", //One letter abbreviation of hour //TACTICAL PLACEMENT USER INTERFACE STRINGS //The four buttons @@ -1063,11 +1237,11 @@ STR16 sKeyDescriptionStrings[2]= }; //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Status:", - L"Gew. (%s):", //weight + L"Gew.:", //weight L"AP Kosten", L"Reichw.:", // Range L"Schaden:", @@ -1084,35 +1258,40 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L"Zubehr:", //14 // Attachments L"AUTO/5:", //15 - L"Menge:", //16 + L"Verf. Munition:", //16 + + L"Standard:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Reichweite", - L"Schaden", - L"Burst/Auto Strafe (Niedriger ist besser)", - L"Autofeuer Schsse fr 5 AP", L"Genauigkeit", + L"Schaden", + L"Reichweite", + L"Zielgenauigkeit", + L"Zielen-Modifikator", + L"Durchschn. beste Laser-Reichweite", + L"Mndungsfeuerdmpfung", + L"Lautstrke (Niedriger ist besser)", L"Zuverlssigkeit", L"Reparaturleichtigkeit", + L"Min. Reichweite fr Zielen-Bonus", + L"Treffer-Modifikator", + L"", //12 L"APs zum Anlegen", L"APs fr Einzelschuss", L"APs fr Feuersto", L"APs fr Autofeuer", L"APs zum Nachladen", L"APs zum manuellen Nachladen", - L"Mndungsfeuerdmpfung", - L"Lautstrke (Niedriger ist besser)", - L"Treffer Modifikator", - L"Durchschn. beste Laser Reichweite", - L"Zielen Modifikator", - L"Min. Reichweite fr Zielen Bonus", - L"Zweibein Modifikator", + L"", //19 + L"Zweibein-Modifikator", + L"Autofeuer: Schsse je 5 AP", + L"Burst/Auto-Streuung (Niedriger ist besser)", //22 L"APs zum Werfen", L"APs zum Abschieen", L"APs zum Stechen", @@ -1120,32 +1299,35 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Kein Feuersto!", L"Kein Autofeuer!", L"APs zum Schlagen", - L"Autofeuer Strafe (Niedriger ist besser)", - L"Feuersto Strafe (Niedriger ist besser)", + L"Autofeuer-Streuung (Niedriger ist besser)", + L"Feuersto-Streuung (Niedriger ist besser)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Reichweite", - L"Schaden", - L"Feuersto/Autofeuer Strafe (Niedriger ist besser)", - L"Autofeuer Schsse fr 5 AP", L"Genauigkeit", + L"Schaden", + L"Reichweite", + L"Zielgenauigkeit", + L"Zielen-Modifikator", + L"Durchschn. beste Laser-Reichweite", + L"Mndungsfeuerdmpfung", + L"Lautstrke (Niedriger ist besser)", L"Zuverlssigkeit", L"Reparaturleichtigkeit", + L"Min. Reichweite fr Zielen-Bonus", + L"Treffer-Modifikator", + L"", //12 L"APs zum Anlegen", L"APs fr Einzelschuss", L"APs fr Feuersto", L"APs fr Autofeuer", L"APs zum Nachladen", L"APs zum manuellen Nachladen", - L"Treffer Modifikator", - L"Durchschn. beste Laser Reichweite", - L"Zielen Modifikator", - L"Min. Reichweite fr Zielen Bonus", - L"Mndungsfeuerdmpfung", - L"Lautstrke (Niedriger ist besser)", - L"Zweibein Modifikator", + L"", //19 + L"Zweibein-Modifikator", + L"Autofeuer: Schsse je 5 AP", + L"Burst/Auto-Streuung (Niedriger ist besser)", //22 L"APs zum Werfen", L"APs zum Abschieen", L"APs zum Stechen", @@ -1153,27 +1335,27 @@ STR16 gzWeaponStatsFasthelpTactical[ 29 ] = L"Kein Feuersto!", L"Kein Autofeuer!", L"APs zum Schlagen", - L"Autofeuer Strafe (Niedriger ist besser)", - L"Feuersto Strafe (Niedriger ist besser)", + L"Autofeuer-Streuung (Niedriger ist besser)", + L"Feuersto-Streuung (Niedriger ist besser)", }; STR16 gzAmmoStatsFasthelp[ 20 ] = { L"Rstungsdurchschlag (Niedriger ist besser)", - L"Projektilsturz (Hher ist besser)", - L"Voraufprall Explosion (Hher ist besser)", - L"Leuchtspur Effekt", + L"Schaden im Ziel (Hher ist besser)", + L"Nahbereichs-Explosion (Hher ist besser)", + L"Leuchtspur-Effekt", L"Panzerbrechend", L"Schlossbrecher", L"Ignoriert Rstung", L"Surehaltig", - L"Reichweite MOdifikator", - L"Schaden Modifikator", - L"Treffer Modifikator", - L"Autofeuer Strafe Modifikator (Hher ist besser)", - L"Feuersto Strafe Modifikator (Hher ist besser)", - L"Zuverlssigkeits Modifikator", - L"Lautstrke Modifikator (Niedriger ist besser)", + L"Reichweiten-Modifikator", + L"Schaden-Modifikator", + L"Treffer-Modifikator", + L"Dauerfeuer-Streuungs-Modifikator (Hher ist besser)", + L"Feuersto-Streuungs-Modifikator (Hher ist besser)", + L"Zuverlssigkeits-Modifikator", + L"Schalldmpfung (Niedriger ist besser)", L"", L"", L"", @@ -1184,22 +1366,22 @@ STR16 gzAmmoStatsFasthelp[ 20 ] = STR16 gzArmorStatsFasthelp[ 20 ] = { L"Schutz", - L"Deckung (Hher ist besser)", - L"Abschwchungsgrad (Niedriger ist besser) ", - L"AP Modifikator", - L"Treffer Modifikator", - L"Waldgebiet Tarnung", - L"Stadt Tarnung", - L"Wste Tarnung", - L"Schnee Tarnung", - L"Anschleichen Modifikator", - L"Sichtweite Modifikator", - L"Tagsichtweite Modifikator", - L"Nachtsichtweite Modifikator", - L"Grelles Licht Modifikator", - L"Hhle Sichtweite Modifikator", - L"Tunnelsicht Modifikator", - L"Geruschreichweite Modifikator", + L"Bedeckung (Hher ist besser)", + L"Abnutzungsfaktor (Niedriger ist besser) ", + L"AP-Modifikator", + L"Treffer-Modifikator", + L"Waldtarnung", + L"Stadt-Tarnung", + L"Wstentarnung", + L"Schneetarnung", + L"Anschleichen-Modifikator", + L"Sichtweiten-Modifikator", + L"Tagsichtweiten-Modifikator", + L"Nachtsichtweiten-Modifikator", + L"Grelles-Licht-Modifikator", + L"Hhlen-Sicht-Modifikator", + L"Tunnelblick-Modifikator", + L"Hrweiten-Modifikator", L"", L"", L"", @@ -1210,11 +1392,11 @@ STR16 gzExplosiveStatsFasthelp[ 20 ] = L"Schaden", L"Betubungsschaden", L"Detonationsgerusch (Niedriger ist besser)", - L"Verflchtigung!!! (Niedriger ist besser)", + L"Flchtigkeit!!! (Niedriger ist besser)", L"Detonationsbereich", - L"Startauswirkungsbereich", - L"Endauswirkungsbereich", - L"Auswirkungsdauer", + L"Startausdehnung des Wirkbereichs", + L"Endausdehnung des wirkbereichs", + L"Wirkungsdauer", L"", L"", L"", @@ -1231,51 +1413,65 @@ STR16 gzExplosiveStatsFasthelp[ 20 ] = STR16 gzMiscItemStatsFasthelp[ 34 ] = { - L"Gegenstandsgre Modifikator (Niedriger ist besser)", - L"Zuverlssigkeits Modifikator", - L"Lautstrke Modifikator (Niedriger ist besser)", - L"Verbirgt Mndungsfeuer", - L"Zweibein Modifikator", - L"Reichweite Modifikator", - L"Treffer Modifikator", - L"Beste Laser Reichweite", - L"Zielen Bonus Modifikator", - L"Feuerstogre Modifikator", - L"Feuersto Strafe Modifikator", - L"Autofeuer Strafe Modifikator", - L"AP Modifikator", - L"AP fr Feuersto Modifikator (Niedriger ist besser)", - L"AP fr Autofeuer Modifikator (Niedriger ist besser)", - L"AP fr Anlegen Modifikator", - L"AP fr Nachladen Mofifikator", - L"Magazingre Modifikator", - L"AP fr Angriff Modifikator", - L"Schaden Modifikator", - L"Nahkampf Modifikator", - L"Waldgebiet Tarnung", - L"Stadt Tarnung", - L"Wsten Tarnung", - L"Schnee Tarnung", - L"Anschleichen Modifikator", - L"Geruschreichweite Modifikator", - L"Sichtweite Modifikator", - L"Tagsichtweite Modifikator", - L"Nachtsichtweite Modifikator", - L"Grelles Licht Modifikator", - L"Hhlensichtweite Modifikator", - L"Tunnelsicht Modifikator (Niedriger ist besser)", + L"Gegenstandsgren-Modifikator (Niedriger ist besser)", + L"Zuverlssigkeits-Modifikator", + L"Schalldmpfung (Niedriger ist besser)", + L"Mndungsfeuerdmpfung", + L"Zweibein-Modifikator", + L"Reichweiten-Modifikator", + L"Treffer-Modifikator", + L"Beste Laser-Reichweite", + L"Zielen-Bonus-Modifikator", + L"Schusszahlmodifikator Feuersto", //LOOTF - gendert von "Feuerstogren-Modifikator" + L"Feuerstostreuungs-Modifikator", + L"Dauerfeuerstreuungs-Modifikator", + L"AP-Modifikator", + L"AP-Modifikator Feuersto (Niedriger ist besser)", //LOOTF - gendert von "AP fr Feuersto Modifikator.." + L"AP-Modifikator Dauerfeuer (Niedriger ist besser)", //LOOTF - gendert von "AP fr Autofeuer Modifikator.." + L"AP-Modifikator Waffenvorhalt", //LOOTF - gendert von "AP fr Anlegen Modifikator" + L"AP-Modifikator Nachladen", //LOOTF - gendert von "AP fr Nachladen Mofifikator" + L"Magazingren-Modifikator", + L"AP-Modifikator fr Angriff", //LOOTF - gendert von "AP fr Angriff Modifikator" + L"Schaden-Modifikator", + L"Nahkampf-Modifikator", + L"Waldtarnung", + L"Stadt-Tarnung", + L"Wstentarnung", + L"Schneetarnung", + L"Anschleichen-Modifikator", + L"Hrweiten-Modifikator", + L"Sichtweiten-Modifikator", + L"Tagsichtweiten-Modifikator", + L"Nachtsichtweiten-Modifikator", + L"Grelles-Licht-Modifikator", + L"Hhlensicht-Modifikator", + L"Tunnelblick-Modifikator (Niedriger ist besser)", L"Minimale Reichweite fr Zielbonus", }; // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFEKTEM", + L"EXZELLENTEM", + L"GUTEM", + L"NORMALEM", + L"NICHT GUTEM", + L"SCHLECHTEM", + L"SCHRECKLICHEM", + L" Zustand." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = { L"Betrag", L"Verbleibend:", //this is the overall balance L"Betrag", - L"Abteilen:", // the amount he wants to separate from the overall balance to get two piles of money + L"Abheben:", // the amount he wants to separate from the overall balance to get two piles of money L"Konto", L"Saldo", L"Betrag", @@ -1286,12 +1482,12 @@ CHAR16 gMoneyStatsDesc[][ 13 ] = //only, but represent the precentage of points remaining. CHAR16 zHealthStr[][13] = //used to be 10 { - L"STIRBT", // >= 0 + L"STIRBT", // >= 0 L"KRITISCH", // >= 15 L"SCHLECHT", // >= 30 L"VERWUNDET", // >= 45 - L"GESUND", // >= 60 - L"STARK", // >= 75 + L"GESUND", // >= 60 + L"STARK", // >= 75 L"SEHR GUT", // >= 90 }; @@ -1301,8 +1497,8 @@ STR16 gzMoneyAmounts[6] = L"$100", L"$10", L"OK", - L"Abteilen", - L"Abheben", + L"Abheben", // Money from pile + L"Abheben", // Money from account }; // short words meaning "Advantages" for "Pros" and "Disadvantages" for "Cons." @@ -1319,7 +1515,7 @@ CHAR16 gzConsLabel[10] = //Conversation options a player has when encountering an NPC CHAR16 zTalkMenuStrings[6][ SMALL_STRING_LENGTH ] = { - L"Wie bitte?", //meaning "Repeat yourself" + L"Wie bitte?", //meaning "Repeat yourself" L"Freundlich", //approach in a friendly L"Direkt", //approach directly - let's get down to business L"Drohen", //approach threateningly - talk now, or I'll blow your face off @@ -1344,8 +1540,8 @@ CHAR16 zDialogActions[1][ SMALL_STRING_LENGTH ] = STR16 pVehicleStrings[] = { L"Eldorado", - L"Hummer", // a hummer jeep/truck -- military vehicle - L"Ice Cream Truck", + L"Hummer", // a hummer jeep/truck -- military vehicle + L"Eiscreme-Wagen", L"Jeep", L"Panzer", L"Helikopter", @@ -1358,14 +1554,14 @@ STR16 pShortVehicleStrings[] = L"Truck", L"Jeep", L"Tank", - L"Heli", // the helicopter + L"Heli", // the helicopter }; STR16 zVehicleName[] = { L"Eldorado", L"Hummer", //a military jeep. This is a brand name. - L"Truck", // Ice cream truck + L"Truck", // Ice cream truck L"Jeep", L"Panzer", L"Heli", //an abbreviation for Helicopter @@ -1417,8 +1613,8 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] = L"%s hat den vollen Betrag erhalten.", L"%s bekommt noch %d.", L"Detonationsfrequenz auswhlen:", //in this case, frequency refers to a radio signal - L"Wie viele Zge bis zur Explosion:", //how much time, in turns, until the bomb blows - L"Ferngesteuerte Zndung einstellen:",//in this case, frequency refers to a radio signal + L"Wie viele Zge bis zur Explosion:", //how much time, in turns, until the bomb blows + L"Ferngesteuerte Zndung einstellen:", //in this case, frequency refers to a radio signal L"Falle entschrfen?", L"Blaue Flagge wegnehmen?", L"Blaue Flagge hier aufstellen?", @@ -1427,8 +1623,8 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] = // In the next string, %s is a name. Stance refers to way they are standing. L"Wollen Sie %s wirklich angreifen?", - L"Fahrzeuge knnen ihre Position nicht ndern.", - L"Der Roboter kann seine Position nicht ndern.", + L"Fahrzeuge knnen ihre Haltung nicht ndern.", + L"Der Roboter kann seine Haltung nicht ndern.", // In the next 3 strings, %s is a name @@ -1471,37 +1667,37 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] = // These messages are displayed during play to alert the player to a particular situation - L"KLEMMT", //weapon is jammed. - L"Roboter braucht %s Kaliber Ammo.", //Robot is out of ammo - L"Dorthin werfen? Unmglich.", //Merc can't throw to the destination he selected + L"KLEMMT", //weapon is jammed. + L"Roboter braucht Munition vom Kaliber %s.", //Robot is out of ammo + L"Dorthin werfen? Unmglich.", //Merc can't throw to the destination he selected // These are different buttons that the player can turn on and off. - L"Stealth Mode (|Z)", + L"Schleichen (|Z)", L"Kartenbildschir|m", L"Spielzug been|den", L"Sprechen", L"Stumm", L"Aufrichten (|P|g|U|p)", - L"Cursor Level (|T|a|b)", - L"Klettern / Springen", + L"Ebene wechseln (|T|a|b)", + L"Klettern / Springen (|J)", L"Ducken (|P|g|D|n)", L"Untersuchen (|C|t|r|l)", L"Voriger Sldner", L"Nchster Sldner (|S|p|a|c|e)", L"|Optionen", - L"Feuersto (|B)", + L"Feuermodus (|B)", L"B|lickrichtung", L"Gesundheit: %d/%d\nEnergie: %d/%d\nMoral: %s", L"Was?", //this means "what?" - L"Forts.", //an abbrieviation for "Continued" - L"Stumm aus fr %s.", - L"Stumm fr %s.", // + L"Weiter", //an abbrieviation for "Continued" (displayed on merc portrait) + L"Schleichen aus fr %s.", + L"Schleichen an fr %s.", L"Fahrer", L"Fahrzeug verlassen", L"Trupp wechseln", L"Fahren", - L"n.a.", //this is an acronym for "Not Applicable." + L"n.a.", //this is an acronym for "Not Applicable." L"Benutzen ( Faustkampf )", L"Benutzen ( Feuerwaffe )", L"Benutzen ( Hieb-/Stichwaffe )", @@ -1550,8 +1746,8 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] = L"Weg blockiert", L"Geld einzahlen/abheben", //Help text over the $ button on the Single Merc Panel L"Niemand braucht Erste Hilfe.", - L"Klemmt.", //Short form of JAMMED, for small inv slots - L"Kann da nicht hin.", // used ( now ) for when we click on a cliff + L"Klemmt.", //Short form of JAMMED, for small inv slots + L"Kann da nicht hin.", // used ( now ) for when we click on a cliff L"Weg ist blockiert. Mit dieser Person den Platz tauschen?", L"Person will sich nicht bewegen", // In the following message, '%s' would be replaced with a quantity of money (e.g. $200) @@ -1571,8 +1767,8 @@ CHAR16 TacticalStr[][ MED_STRING_LENGTH ] = L"Schloss zerstrt", L"Noch jemand an der Tr.", L"Gesundh.: %d/%d\nTank: %d/%d", - L"%s kann %s nicht sehen.", // Cannot see person trying to talk to - L"Attachment removed", + L"%s kann %s nicht sehen.", // Cannot see person trying to talk to + L"Anbringung entfernt", L"Sie knnen kein weiteres Fahrzeug mehr verwenden, da Sie bereits 2 haben", }; @@ -1625,8 +1821,8 @@ STR16 pRepairStrings[] = { L"Gegenstnde", // tell merc to repair items in inventory L"Raketensttzpunkt", // tell merc to repair SAM site - SAM is an acronym for Surface to Air Missile - L"Abbruch", // cancel this menu - L"Roboter", // repair the robot + L"Abbruch", // cancel this menu + L"Roboter", // repair the robot }; // NOTE: combine prestatbuildstring with statgain to get a line like the example below. @@ -1647,29 +1843,29 @@ STR16 sStatGainStrings[] = L"Beweglichkeit", L"Geschicklichkeit", L"Weisheit.", - L"an Medizin.", - L"an Sprengstoff.", - L"an Technik.", + L"an Medizinkenntnis.", + L"an Sprengstoffkenntnis.", + L"an Technikfhigkeit.", L"an Treffsicherheit.", L"Erfahrungsstufe(n).", - L"Kraft.", - L"Fhrungsqualitt.", + L"an Kraft.", + L"an Fhrungsqualitt.", }; STR16 pHelicopterEtaStrings[] = { L"Gesamt: ", // total distance for helicopter to travel - L" Sicher: ", // Number of safe sectors - L" Unsicher:", // Number of unsafe sectors - L"Gesamtkosten: ",// total cost of trip by helicopter - L"Ank.: ", // ETA is an acronym for "estimated time of arrival" + L" Sicher: ", // Number of safe sectors + L" Unsicher:", // Number of unsafe sectors + L"Gesamtkosten: ", // total cost of trip by helicopter + L"Ank.: ", // ETA is an acronym for "estimated time of arrival" // warning that the sector the helicopter is going to use for refueling is under enemy control L"Helikopter hat fast keinen Sprit mehr und muss im feindlichen Gebiet landen.", L"Passagiere: ", L"Skyrider oder Absprungsort auswhlen?", L"Skyrider", - L"Absprung", //make sure length doesn't exceed 8 characters (used to be "Absprungsort") + L"Absprung", //make sure length doesn't exceed 8 characters (used to be "Absprungsort") }; STR16 sMapLevelString[] = @@ -1700,12 +1896,12 @@ STR16 gsTimeStrings[] = STR16 sFacilitiesStrings[] = { L"Keine", - L"Hospital", - L"Fabrik", // Factory + L"Krankenhaus", + L"Fabrik", // Factory L"Gefngnis", L"Militr", L"Flughafen", - L"Schiestand", // a field for soldiers to practise their shooting skills + L"Schieanlage", // a field for soldiers to practise their shooting skills }; // text for inventory pop up button @@ -1720,9 +1916,9 @@ STR16 pwTownInfoStrings[] = { L"Gre", // 0 // size of the town in sectors L"", // blank line, required - L"unter Kontrolle", // how much of town is controlled + L"unter Kontrolle", // how much of town is controlled L"Keine", // none of this town - L"Mine", // mine associated with this town + L"Mine", // mine associated with this town L"Loyalitt", // 5 // the loyalty level of this town L"Trainiert", // the forces in the town trained by the player L"", @@ -1730,7 +1926,7 @@ STR16 pwTownInfoStrings[] = L"Level", // the training level of civilians in this town L"Zivilistentraining", // 10 // state of civilian training in town L"Miliz", // the state of the trained civilians in the town - L"Mobile. M. Training", // HEADROCK HAM 3.6: The stat of Mobile militia training in town + L"Mobile M. Training", // HEADROCK HAM 3.6: The stat of Mobile militia training in town }; // Mine strings @@ -1779,7 +1975,7 @@ STR16 pMapInventoryErrorString[] = STR16 pMapInventoryStrings[] = { - L"Ort", // sector these items are in + L"Ort", // sector these items are in L"Zahl der Gegenstnde", // total number of items in sector }; @@ -1795,7 +1991,7 @@ STR16 pMapScreenFastHelpTextList[] = L"Test-Text", L"Test-Text", L"Test-Text", - L"In diesem Bildschirm knnen Sie nicht viel machen, bevor Sie in Arulco ankommen. Wenn Sie Ihr Team zusammengestellt haben, klicken Sie auf den Zeitraffer-Button unten links. Dadurch vergeht die Zeit schneller, bis Ihr Team in Arulco ankommt.", + L"In diesem Bildschirm knnen Sie nicht viel machen, bevor Sie in Arulco ankommen. Wenn Sie Ihr Team zusammengestellt haben, klicken Sie auf den Zeitraffer-Button unten rechts. Dadurch vergeht die Zeit schneller, bis Ihr Team in Arulco ankommt.", }; // movement menu text @@ -1803,7 +1999,7 @@ STR16 pMovementMenuStrings[] = { L"Sldner in Sektor bewegen", // title for movement box L"Route planen", // done with movement menu, start plotting movement - L"Abbruch", // cancel this menu + L"Abbruch", // cancel this menu L"Andere", // title for group of mercs not on squads nor in vehicles }; @@ -1811,9 +2007,9 @@ STR16 pUpdateMercStrings[] = { L"Ups:", // an error has occured L"Vertrag ist abgelaufen:", // this pop up came up due to a merc contract ending - L"Auftrag wurde ausgefhrt:", // this pop up....due to more than one merc finishing assignments + L"Auftrag wurde ausgefhrt:", // this pop up....due to more than one merc finishing assignments L"Diese Sldner arbeiten wieder:", // this pop up ....due to more than one merc waking up and returing to work - L"Diese Sldner schlafen:", // this pop up ....due to more than one merc being tired and going to sleep + L"Diese Sldner schlafen:", // this pop up ....due to more than one merc being tired and going to sleep L"Vertrag bald abgelaufen:", //this pop up came up due to a merc contract ending }; @@ -1825,7 +2021,8 @@ STR16 pMapScreenBorderButtonHelpText[] = L"|Teams & Feinde zeigen", L"Luftr|aum zeigen", L"Gegenstnde zeigen (|I)", - L"Miliz & Feinde zeigen (|Z)", + L"Mili|z & Feinde zeigen", + L"Zeige Mobile Miliz Begrenzungen", // HEADROCK HAM 4: Mobile Restrictions Button }; STR16 pMapScreenBottomFastHelp[] = @@ -1835,7 +2032,7 @@ STR16 pMapScreenBottomFastHelp[] = L"|Optionen", L"Zeitraffer (|+)", // time compress more L"Zeitraffer (|-)", // time compress less - L"Vorige Nachricht (|U|p)\nSeite zurck (|P|g|U|p)", // previous message in scrollable list + L"Vorige Nachricht (|U|p)\nSeite zurck (|P|g|U|p)", // previous message in scrollable list L"Nchste Nachricht (|D|o|w|n)\nNchste Seite (|P|g|D|n)", // next message in the scrollable list L"Zeit Start/Stop (|S|p|a|c|e)", // start/stop time compression }; @@ -1856,7 +2053,11 @@ STR16 pDayStrings[] = }; // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc.", @@ -1911,7 +2112,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings STR16 pTraverseStrings[] = @@ -1993,9 +2194,9 @@ STR16 pTransactionText[] = L"B.S.E.-Profilanalyse", // IMP is the acronym for International Mercenary Profiling L"Versicherung fr %s abgeschlossen", L"Versicherung fr %s verringert", - L"Versicherung fr %s verlngert", // johnny contract extended + L"Versicherung fr %s verlngert", // johnny contract extended L"Versicherung fr %s gekndigt", - L"Versicherungsanspruch fr %s", // insurance claim for merc + L"Versicherungsanspruch fr %s", // insurance claim for merc L"1 Tag", // merc's contract extended for a day L"1 Woche", // merc's contract extended for a week L"2 Wochen", // ... for 2 weeks @@ -2005,14 +2206,14 @@ STR16 pTransactionText[] = L"Volle Rckzahlung fr %s", L"Teilw. Rckzahlung fr %s", L"Keine Rckzahlung fr %s", - L"Zahlung an %s", // %s is the name of the npc being paid + L"Zahlung an %s", // %s is the name of the npc being paid L"berweisen an %s", // transfer funds to a merc - L"berweisen von %s", // transfer funds from a merc - L"Miliz in %s ausbilden", // initial cost to equip a town's militia + L"berweisen von %s", // transfer funds from a merc + L"Miliz in %s ausbilden", // initial cost to equip a town's militia L"Gegenstnde von %s gekauft.", //is used for the Shop keeper interface. The dealers name will be appended to the end of the string. L"%s hat Geld angelegt.", - L"Betriebskosten", // HEADROCK HAM 3.6 - L"Unterhaltskosten fr Miliz", // HEADROCK HAM 3.6 + L"Betriebskosten", // HEADROCK HAM 3.6 + L"Unterhaltskosten fr Miliz", // HEADROCK HAM 3.6 }; STR16 pTransactionAlternateText[] = @@ -2026,12 +2227,12 @@ STR16 pTransactionAlternateText[] = // helicopter pilot payment STR16 pSkyriderText[] = { - L"Skyrider wurden $%d gezahlt", // skyrider was paid an amount of money + L"Skyrider wurden $%d gezahlt", // skyrider was paid an amount of money L"Skyrider bekommt noch $%d", // skyrider is still owed an amount of money - L"Skyrider hat aufgetankt", // skyrider has finished refueling + L"Skyrider hat aufgetankt", // skyrider has finished refueling L"",//unused L"",//unused - L"Skyrider ist bereit fr weiteren Flug.", // Skyrider was grounded but has been freed + L"Skyrider ist bereit fr weiteren Flug.", // Skyrider was grounded but has been freed L"Skyrider hat keine Passagiere. Wenn Sie Sldner in den Sektor transportieren wollen, weisen Sie sie einem Fahrzeug/Helikopter zu.", }; @@ -2065,8 +2266,8 @@ STR16 pMapScreenStatusStrings[] = STR16 pMapScreenPrevNextCharButtonHelpText[] = { - L"Voriger Sldner (|L|e|f|t)", // previous merc in the list - L"Nchster Sldner (|R|i|g|h|t)", // next merc in the list + L"Voriger Sldner (|L|e|f|t)", // previous merc in the list + L"Nchster Sldner (|R|i|g|h|t)", // next merc in the list }; STR16 pEtaString[] = @@ -2077,7 +2278,7 @@ STR16 pEtaString[] = STR16 pTrashItemText[] = { L"Sie werden das Ding nie wiedersehen. Trotzdem wegwerfen?", // do you want to continue and lose the item forever - L"Dieser Gegenstand sieht SEHR wichtig aus. Sie sie GANZ SICHER, dass Sie ihn wegwerfen wollen?", // does the user REALLY want to trash this item + L"Dieser Gegenstand sieht SEHR wichtig aus. Sind Sie GANZ SICHER, dass Sie ihn wegwerfen wollen?", // does the user REALLY want to trash this item }; STR16 pMapErrorString[] = @@ -2089,7 +2290,7 @@ STR16 pMapErrorString[] = L"Marschbefehl? Wir sind in einem feindlichen Sektor!", L"Wenn Sldner reisen sollen, mssen sie einem Trupp oder Fahrzeug zugewiesen werden.", L"Sie haben noch keine Teammitglieder.", // you have no members, can't do anything - L"Sldner kann nicht gehorchen.", // merc can't comply with your order + L"Sldner kann Befehl nicht ausfhren.", // merc can't comply with your order //6-10 L"braucht eine Eskorte. Platzieren Sie ihn in einem Trupp mit Eskorte.", // merc can't move unescorted .. for a male L"braucht eine Eskorte. Platzieren Sie sie in einem Trupp mit Eskorte.", // for a female @@ -2129,8 +2330,8 @@ STR16 pMapErrorString[] = //36-40 L"%s kann nicht zu %s wechseln, weil der sich bewegt", L"%s kann so nicht einsteigen", - L"%s kann sich nicht %s anschlieen", - L"Sie knnen den Zeitraffer erst mit neuen Sldner benutzen!", + L"%s kann sich %s nicht anschlieen", + L"Sie knnen den Zeitraffer erst mit neuen Sldnern benutzen!", L"Dieses Fahrzeug kann nur auf Straen fahren!", //41-45 L"Reisenden Sldnern knnen Sie keine Auftrge erteilen.", @@ -2139,7 +2340,7 @@ STR16 pMapErrorString[] = L"Keiner kann das Fahrzeug steuern.", L"Ein oder mehrere Sldner dieses Trupps knnen sich jetzt nicht bewegen.", //46-50 - L"Ein oder mehrere Sldner des ANDEREN Trupps kann sich gerade nicht bewegen.", + L"Ein oder mehrere Sldner des ANDEREN Trupps knnen sich gerade nicht bewegen.", L"Fahrzeug zu stark beschdigt!", L"Nur zwei Sldner pro Sektor knnen Milizen trainieren.", L"Roboter muss von jemandem bedient werden. Beide im selben Trupp platzieren.", @@ -2159,8 +2360,8 @@ STR16 pMapPlotStrings[] = // help text used when moving the merc arrival sector STR16 pBullseyeStrings[] = { - L"Klicken Sie auf den Sektor, in dem die Sldner statt dessen ankommen sollen.", - L"OK. Sldner werden in %s abgesetzt", + L"Klicken Sie auf den Sektor, in dem die Sldner stattdessen ankommen sollen.", + L"OK. Sldner werden in %s abgesetzt.", L"Sldner knnen nicht dorthin fliegen. Luftraum nicht gesichert!", L"Abbruch. Ankunftssektor unverndert,", L"Luftraum ber %s ist nicht mehr sicher! Ankunftssektor jetzt in %s.", @@ -2198,9 +2399,9 @@ STR16 pMercContractOverStrings[] = { L"s Vertrag war abgelaufen, und er ist nach Hause gegangen.", // merc's contract is over and has departed L"s Vertrag war abgelaufen, und sie ist nach Hause gegangen.", // merc's contract is over and has departed - L"s Vertrag wurde gekndigt, und er ist weggegangen.", // merc's contract has been terminated - L"s Vertrag wurde gekndigt, und sie ist weggegangen.", // merc's contract has been terminated - L"Sie schulden M.E.R.C. zu viel, also ist %s gegangen.", // Your M.E.R.C. account is invalid so merc left + L"s Vertrag wurde gekndigt, und er ist weggegangen.", // merc's contract has been terminated + L"s Vertrag wurde gekndigt, und sie ist weggegangen.", // merc's contract has been terminated + L"Sie schulden M.E.R.C. zu viel, also ist %s gegangen.", // Your M.E.R.C. account is invalid so merc left }; // Text used on IMP Web Pages @@ -2213,24 +2414,24 @@ STR16 pImpPopUpStrings[] = L"Option zur Zeit nicht gltig.", L"Um eine genaue Evaluierung durchzufhren, mssen Sie mindestens noch ein Teammitglied aufnehmen knnen.", L"Evaluierung bereits durchgefhrt.", - L"Fehler beim Laden des B.S.E. Charakters.", - L"Sie haben bereits die maximale Anzahl an B.S.E. Charakteren.", - L"Sie haben bereits drei B.S.E. Charaktere mit dem gleichen Geschlecht.", - L"Sie knnen sich den B.S.E. Charakter nicht leisten.", - L"Der neue B.S.E. Charakter ist nun in ihrem Team.", + L"Fehler beim Laden des B.S.E.-Charakters.", + L"Sie haben bereits die maximale Anzahl an B.S.E.-Charakteren.", + L"Sie haben bereits drei B.S.E.-Charaktere mit dem gleichen Geschlecht.", + L"Sie knnen sich den B.S.E.-Charakter nicht leisten.", + L"Der neue B.S.E.-Charakter ist nun in ihrem Team.", }; // button labels used on the IMP site STR16 pImpButtonText[] = { - L"Wir ber uns", // about the IMP site + L"Wir ber uns", // about the IMP site L"BEGINNEN", // begin profiling L"Persnlichkeiten", // personality section L"Eigenschaften", // personal stats/attributes section - L"Aussehen", // changed from portrait - SANDRO + L"Aussehen", // changed from portrait L"Stimme %d", // the voice selection L"Fertig", // done profiling - L"Von vorne anfangen", // start over profiling + L"Von vorne anfangen", // start over profiling L"Ja, die Antwort passt!", L"Ja", L"Nein", @@ -2248,15 +2449,15 @@ STR16 pImpButtonText[] = L"Registrieren", // the IMP site registry..when name and gender is selected L"Analyse wird durchgefhrt", // analyzing your profile results L"OK", - L"Charakter", // Change from "Voice" - SANDRO + L"Charakter", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO - L"Nach Festlegung Ihres Charakters, knnen Sie Ihre Fertigkeit(en) auswhlen.", - L"Um die Evaluation erfolgreich abzuschlieen, bestimmen Sie Ihre Eigenschaften.", - L"Um Ihr Profil zu erstellen, whlen Sie ein(e) Portrait, Stimme aus und definieren Erscheinung und ueres.", + // These texts have been also slightly changed + L"Nach Festlegung Ihres Charakters knnen Sie Ihre Fertigkeit(en) auswhlen.", + L"Um die Evaluierung erfolgreich abzuschlieen, bestimmen Sie Ihre Eigenschaften.", + L"Um Ihr Profil zu erstellen, whlen Sie ein Portrait und eine Stimme aus und definieren Ihre uere Erscheinung.", L"Jetzt, da Sie Ihr Aussehen bestimmt haben, fahren wir mit der Charakter-Analyse fort.", }; @@ -2301,26 +2502,26 @@ STR16 pHistoryStrings[] = { L"", // leave this line blank //1-5 - L"%s von A.I.M. angeheuert.", // merc was hired from the aim site - L"%s von M.E.R.C. angeheuert.", // merc was hired from the aim site - L"%s ist tot.", // merc was killed - L"Rechnung an M.E.R.C. bezahlt", // paid outstanding bills at MERC + L"%s von A.I.M. angeheuert.", // merc was hired from the aim site + L"%s von M.E.R.C. angeheuert.", // merc was hired from the aim site + L"%s ist tot.", // merc was killed + L"Rechnung an M.E.R.C. bezahlt", // paid outstanding bills at MERC L"Enrico Chivaldoris Auftrag akzeptiert", //6-10 L"B.S.E.-Profil erstellt", - L"Versicherung abgeschlossen fr %s.", // insurance contract purchased - L"Versicherung gekndigt fr %s.", // insurance contract canceled - L"Versicherung ausgezahlt fr %s.", // insurance claim payout for merc - L"%ss Vertrag um 1 Tag verlngert.", // Extented "mercs name"'s for a day + L"Versicherung abgeschlossen fr %s.", // insurance contract purchased + L"Versicherung gekndigt fr %s.", // insurance contract canceled + L"Versicherung ausgezahlt fr %s.", // insurance claim payout for merc + L"%ss Vertrag um 1 Tag verlngert.", // Extented "mercs name"'s for a day //11-15 - L"%ss Vertrag um 1 Woche verlngert.", // Extented "mercs name"'s for a week - L"%ss Vertrag um 2 Wochen verlngert.", // Extented "mercs name"'s 2 weeks - L"%s entlassen.", // "merc's name" was dismissed. - L"%s geht.", // "merc's name" quit. - L"Quest begonnen.", // a particular quest started + L"%ss Vertrag um 1 Woche verlngert.", // Extented "mercs name"'s for a week + L"%ss Vertrag um 2 Wochen verlngert.", // Extented "mercs name"'s 2 weeks + L"%s entlassen.", // "merc's name" was dismissed. + L"%s geht.", // "merc's name" quit. + L"Quest begonnen.", // a particular quest started //16-20 L"Quest gelst.", - L"Mit Vorarbeiter in %s geredet", // talked to head miner of town + L"Mit Vorarbeiter in %s geredet", // talked to head miner of town L"%s befreit", L"Cheat benutzt", L"Essen ist morgen in Omerta", @@ -2379,24 +2580,24 @@ STR16 pHistoryStrings[] = L"Kontrolle ber Sektor verloren", L"Sektor verteidigt", //66-70 - L"Schlacht verloren", //ENEMY_ENCOUNTER_CODE - L"Tdlicher Hinterhalt", //ENEMY_AMBUSH_CODE + L"Schlacht verloren", //ENEMY_ENCOUNTER_CODE + L"Tdlicher Hinterhalt", //ENEMY_AMBUSH_CODE L"Hinterhalt ausgehoben", - L"Angriff fehlgeschlagen", //ENTERING_ENEMY_SECTOR_CODE + L"Angriff fehlgeschlagen", //ENTERING_ENEMY_SECTOR_CODE L"Angriff erfolgreich", //71-75 - L"Monster angegriffen", //CREATURE_ATTACK_CODE - L"Von Bloodcats gettet", //BLOODCAT_AMBUSH_CODE + L"Monster angegriffen", //CREATURE_ATTACK_CODE + L"Von Bloodcats gettet", //BLOODCAT_AMBUSH_CODE L"Bloodcats gettet", L"%s wurde gettet", L"Carmen den Kopf eines Terroristen gegeben", - L"Slay ist gegangen", //Slay is a merc and has left the team - L"%s gekillt", //History log for when a merc kills an NPC or PC + L"Slay ist gegangen", //Slay is a merc and has left the team + L"%s gettet", //History log for when a merc kills an NPC or PC }; STR16 pHistoryLocations[] = { - L"n.a.", // N/A is an acronym for Not Applicable + L"n.a.", // N/A is an acronym for Not Applicable }; // icon text strings that appear on the laptop @@ -2409,7 +2610,7 @@ STR16 pLaptopIcons[] = L"Logbuch", L"Dateien", L"Schlieen", - L"sir-FER 4.0", // our play on the company name (Sirtech) and web surFER + L"sir-FER 4.0", // our play on the company name (Sirtech) and web surFER }; // bookmarks for different websites @@ -2420,7 +2621,7 @@ STR16 pBookMarkStrings[] = L"Bobby Rays", L"B.S.E.", L"M.E.R.C.", - L"Bestattungsinst.", + L"Bestatter", L"Florist", L"Versicherung", L"Abbruch", @@ -2442,26 +2643,26 @@ STR16 pDownloadString[] = { STR16 gsAtmSideButtonText[] = { L"OK", - L"Nehmen", // take money from merc - L"Geben", // give money to merc - L"Rckgngig", // cancel transaction - L"Lschen", // clear amount being displayed on the screen + L"Nehmen", // take money from merc + L"Geben", // give money to merc + L"Rckgngig", // cancel transaction + L"Lschen", // clear amount being displayed on the screen }; STR16 gsAtmStartButtonText[] = { L"berw $", // transfer money to merc -- short form - L"Statistik", // view stats of the merc - L"Inventar", // view the inventory of the merc + L"Statistik", // view stats of the merc + L"Inventar", // view the inventory of the merc L"Anstellung", }; STR16 sATMText[] = { - L"Geld berw.?", // transfer funds to merc? - L"Ok?", // are we certain? - L"Betrag eingeben", // enter the amount you want to transfer to merc - L"Art auswhlen", // select the type of transfer to merc + L"Geld berw.?", // transfer funds to merc? + L"Ok?", // are we certain? + L"Betrag eingeben", // enter the amount you want to transfer to merc + L"Art auswhlen", // select the type of transfer to merc L"Nicht genug Geld", // not enough money to transfer to merc L"Betrag muss durch $10 teilbar sein", // transfer amount must be a multiple of $10 }; @@ -2480,7 +2681,7 @@ STR16 pErrorStrings[] = STR16 pPersonnelString[] = { - L"Sldner:", // mercs we have + L"Sldner:", // mercs we have }; STR16 pWebTitle[ ] = @@ -2508,7 +2709,7 @@ STR16 pWebPagesTitles[] = L"Bobby Rays - Waffen", L"Bobby Rays - Munition", L"Bobby Rays - Rstungen", - L"Bobby Rays - Sonst.", //misc is an abbreviation for miscellaneous + L"Bobby Rays - Sonstige", //misc is an abbreviation for miscellaneous L"Bobby Rays - Gebraucht", L"Bobby Rays - Versandauftrag", L"B.S.E.", @@ -2552,7 +2753,7 @@ STR16 pPersonnelDepartedStateStrings[] = L"Sonstiges", L"Heirat", L"Vertrag zu Ende", - L"Quit", + L"Aufgehrt", //LOOTF - Englisch "quit", welcher Kontext? = Slay Ruttwen? }; // personnel strings appearing in the Personnel Manager on the laptop @@ -2571,7 +2772,7 @@ STR16 pPersonelTeamStrings[] = STR16 pPersonnelCurrentTeamStatsStrings[] = { L"Schlechteste", - L"Durchschn.", + L"Durchsch.", L"Beste", }; @@ -2658,7 +2859,7 @@ STR16 pUpdatePanelButtons[] = CHAR16 LargeTacticalStr[][ LARGE_STRING_LENGTH ] = { L"Sie sind in diesem Sektor geschlagen worden!", - L"Der Feind hat kein Erbarmen mit den Seelen Ihrer Teammitglieder und verschlingt jeden einzelnen.", + L"Der Feind hat kein Erbarmen mit den Seelen Ihrer Teammitglieder und verschlingt jeden einzelnen.", //LOOTF - Auch im Englischen Kannibalismus. Was zum Henker? L"Ihre bewusstlosen Teammitglieder wurden gefangen genommen!", L"Ihre Teammitglieder wurden vom Feind gefangen genommen.", }; @@ -2686,22 +2887,22 @@ STR16 MercAccountText[] = { // Text on the buttons on the bottom of the screen L"Befugnis ert.", - L"Home", + L"Startseite", L"Konto #:", L"Sldner", L"Tage", - L"Rate", //5 + L"Tagessatz", //5 //LOOTF - "Rate" gendert auf "Tagessatz", ndern wenn Probleme, alt. "Sold" L"Belasten", L"Gesamt:", L"Zahlung von %s wirklich genehmigen?", //the %s is a string that contains the dollar amount ( ex. "$150" ) }; // Merc Account Page buttons -STR16 MercAccountPageText[] = +STR16 MercAccountPageText[] = { // Text on the buttons on the bottom of the screen L"Zurck", - L"Weiter", + L"Weiter", }; //For use at the M.E.R.C. web site. Text relating a MERC mercenary @@ -2723,13 +2924,13 @@ STR16 MercInfo[] = L"Anheuern", L"Weiter", L"Zusatzinfo", - L"Home", + L"Startseite", L"Angestellt", L"Sold:", L"Pro Tag", L"Verstorben", - L"Sie versuchen, zu viele Sldner anzuheuern. Sie haben die Maximalgre erreicht.", + L"Sie versuchen, zu viele Sldner anzuheuern. Sie haben die Maximalanzahl erreicht.", L"nicht da", }; @@ -2857,53 +3058,53 @@ STR16 sFloristCards[] = // Text for Bobby Ray's Mail Order Site STR16 BobbyROrderFormText[] = { - L"Bestellformular", //Title of the page + L"Bestellformular", //Title of the page L"St.", // The number of items ordered - L"Gew. (%s)", // The weight of the item + L"Gew. (%s)", // The weight of the item L"Artikel", // The name of the item L"Preis", // the item's weight - L"Summe", //5 // The total price of all of items of the same type - L"Zwischensumme", // The sub total of all the item totals added - L"Versandkosten (vgl. Bestimmungsort)", // S&H is an acronym for Shipping and Handling - L"Endbetrag", // The grand total of all item totals + the shipping and handling - L"Bestimmungsort", - L"Liefergeschwindigkeit", //10 // See below - L"$ (pro %s)", // The cost to ship the items - L"bernacht Express", // Gets deliverd the next day + L"Summe", //5 // The total price of all of items of the same type + L"Zwischensumme", // The sub total of all the item totals added + L"Versandkosten (vgl. Bestimmungsort)", // S&H is an acronym for Shipping and Handling + L"Endbetrag", // The grand total of all item totals + the shipping and handling + L"Bestimmungsort", + L"Liefergeschwindigkeit", //10 // See below + L"$ (pro %s)", // The cost to ship the items + L"bernacht-Express", // Gets deliverd the next day L"2 Arbeitstage", // Gets delivered in 2 days L"Standard-Service", // Gets delivered in 3 days - L"Lschen",//15 // Clears the order page - L"Bestellen", // Accept the order + L"Lschen", //15 // Clears the order page + L"Bestellen", // Accept the order L"Zurck", // text on the button that returns to the previous page L"Home", // Text on the button that returns to the home page L"* Gebrauchter Gegenstand", // Disclaimer stating that the item is used - L"Sie haben nicht genug Geld.", //20 // A popup message that to warn of not enough money + L"Sie haben nicht genug Geld.", //20 // A popup message that to warn of not enough money L"", // Gets displayed when there is no valid city selected L"Wollen Sie Ihre Bestellung wirklich nach %s schicken?", // A popup that asks if the city selected is the correct one L"Packungsgewicht**", // Displays the weight of the package - L"** Mindestgewicht", // Disclaimer states that there is a minimum weight for the package + L"** Mindestgewicht", // Disclaimer states that there is a minimum weight for the package L"Lieferungen", }; STR16 BobbyRFilter[] = { // Guns - L"Schw. W.", - L"Pistole", - L"MP", - L"SMG", - L"Gewehr", - L"SSG", + L"Schwere W.", + L"Pistolen", + L"MPs", + L"SMGs", + L"Gewehre", + L"SSGs", L"Sturmgew.", - L"MG", + L"MGs", L"Schrotfl.", // Ammo L"Pistole", - L"M. Pistole", + L"M.-Pistole", L"SMG", L"Gewehr", - L"SS Gewehr", + L"SS-Gewehr", L"Sturmgew.", L"MG", L"Schrotfl.", @@ -2911,7 +3112,7 @@ STR16 BobbyRFilter[] = // Used L"Feuerwfn.", L"Rstungen", - L"LBE Ausr.", + L"Trageausr.", L"Sonstiges", // Armour @@ -2928,8 +3129,8 @@ STR16 BobbyRFilter[] = L"Bomben", L"Verbandsk.", L"Taschen", - L"Gesicht G.", - L"LBE Ausr.", + L"Kopfausr.", + L"Trageausr.", L"Sonstiges", }; @@ -2949,30 +3150,30 @@ STR16 BobbyRText[] = L"Gebraucht", //7 L"Vor", L"BESTELLEN", - L"Home", //10 + L"Startseite", //10 //The following 2 lines are used on the Ammunition page. //They are used for help text to display how many items the player's merc has //that can use this type of ammo - L"Ihr Team hat",//11 - L"Waffe(n), die dieses Kaliber benutzen", //12 + L"Ihr Team hat", //11 + L"Waffe(n), die diese Munition verschieen", //12 //The following lines provide information on the items L"Gewicht:", // Weight of all the items of the same type L"Kal:", // the caliber of the gun L"Mag:", // number of rounds of ammo the Magazine can hold - L"Reichw.:", // The range of the gun - L"Schaden:", // Damage of the weapon - L"Freq.:", // Weapon's Rate Of Fire, acroymn ROF + L"Reichw.:", // The range of the gun + L"Schaden:", // Damage of the weapon + L"Kadenz:", // Weapon's Rate Of Fire, acroymn ROF L"Preis:", // Cost of the item L"Vorrtig:", // The number of items still in the store's inventory - L"Bestellt:", // The number of items on order + L"Bestellt:", // The number of items on order L"Beschdigt", // If the item is damaged L"Gew.:", // the Weight of the item L"Summe:", // The total cost of all items on order - L"* %% funktionstchtig", // if the item is damaged, displays the percent function of the item + L"* %% funktionstchtig", // if the item is damaged, displays the percent function of the item //Popup that tells the player that they can only order 10 items at a time L"Mist! Mit diesem Formular knnen Sie nur 10 Sachen bestellen. Wenn Sie mehr wollen (was wir sehr hoffen), fllen Sie bitte noch ein Formular aus.", @@ -2992,7 +3193,7 @@ STR16 BobbyRaysFrontText[] = { //Details on the web site - L"Dies ist die heieste Site fr Waffen und militrische Ausrstung aller Art", + L"Dies ist die heieste Seite fr Waffen und militrische Ausrstung aller Art", L"Welchen Sprengstoff Sie auch immer brauchen - wir haben ihn.", L"SECOND HAND", @@ -3069,7 +3270,7 @@ STR16 CharacterInfo[] = { // The various attributes of the merc - L"Gesundh.", + L"Gesundheit", L"Beweglichkeit", L"Geschicklichkeit", L"Kraft", @@ -3097,9 +3298,15 @@ STR16 CharacterInfo[] = L"Kontakt", L"Weiter", L"Zusatzinfo", // Title for the additional info for the merc's bio - L"Aktive Mitglieder", //20 // Title of the page - L"Zustzl. Ausrst:", // Displays the optional gear cost + L"Aktive Mitglieder", //20 // Title of the page + L"Zustzl. Ausrst:", // Displays the optional gear cost + L"Ausr.", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"VERSICHERUNG erforderlich", // If the merc required a medical deposit, this is displayed + L"Kit 1", // Text on Starting Gear Selection Button 1 + L"Kit 2", // Text on Starting Gear Selection Button 2 + L"Kit 3", // Text on Starting Gear Selection Button 3 + L"Kit 4", // Text on Starting Gear Selection Button 4 + L"Kit 5", // Text on Starting Gear Selection Button 5 }; //Aim Member.c @@ -3127,14 +3334,14 @@ STR16 VideoConfercingText[] = L"ANHEUERN", // go to menu in which you can hire the merc L"AUFLEGEN", // stops talking with the merc L"OK", - L"NACHRICHT", // if the merc is not there, you can leave a message + L"NACHRICHT", // if the merc is not there, you can leave a message //Text on the top of the video conference popup L"Videokonferenz mit", L"Verbinde. . .", - L"versichert", // Displays if you are hiring the merc with the medical deposit + L"versichert", // Displays if you are hiring the merc with the medical deposit }; @@ -3176,7 +3383,7 @@ STR16 AimHistoryText[] = // Text on the buttons at the bottom of the page L"Zurck", - L"Home", + L"Startseite", L"Veteranen", L"Weiter", }; @@ -3262,14 +3469,14 @@ STR16 AimBottomMenuText[] = STR16 SKI_Text[] = { L"WAREN VORRTIG", //Header for the merchandise available - L"SEITE", //The current store inventory page being displayed - L"KOSTEN", //The total cost of the the items in the Dealer inventory area + L"SEITE", //The current store inventory page being displayed + L"KOSTEN", //The total cost of the the items in the Dealer inventory area L"WERT", //The total value of items player wishes to sell - L"SCHTZUNG", //Button text for dealer to evaluate items the player wants to sell - L"TRANSAKTION", //Button text which completes the deal. Makes the transaction. - L"FERTIG", //Text for the button which will leave the shopkeeper interface. + L"SCHTZUNG", //Button text for dealer to evaluate items the player wants to sell + L"TRANSAKTION", //Button text which completes the deal. Makes the transaction. + L"FERTIG", //Text for the button which will leave the shopkeeper interface. L"KOSTEN", //The amount the dealer will charge to repair the merc's goods - L"1 STUNDE", // SINGULAR! The text underneath the inventory slot when an item is given to the dealer to be repaired + L"1 STUNDE", // SINGULAR! The text underneath the inventory slot when an item is given to the dealer to be repaired L"%d STUNDEN", // PLURAL! The text underneath the inventory slot when an item is given to the dealer to be repaired L"REPARIERT", // Text appearing over an item that has just been repaired by a NPC repairman dealer L"Es ist kein Platz mehr, um Sachen anzubieten.", //Message box that tells the user there is no more room to put there stuff @@ -3314,7 +3521,7 @@ STR16 gzSkiAtmText[] = STR16 SkiMessageBoxText[] = { L"Mchten Sie %s von Ihrem Konto abbuchen, um die Differenz zu begleichen?", - L"Nicht genug Geld. Ihnen fehlen %s", + L"Nicht genug Geld. Ihnen fehlen %s.", L"Mchten Sie %s von Ihrem Konto abbuchen, um die Kosten zu decken?", L"Hndler bitten, mit der berweisung zu beginnen.", L"Hndler bitten, Gegenstnde zu reparieren", @@ -3328,7 +3535,7 @@ STR16 zOptionsText[] = //button Text L"Spiel sichern", L"Spiel laden", - L"Spielende", + L"Beenden", L"Nchste", L"Vorherige", L"Fertig", @@ -3357,7 +3564,7 @@ STR16 zSaveLoadText[] = L"Der gespeicherte Spielstand unterscheidet sich vom aktuellen Spielstand. Es kann wahrscheinlich nichts passieren. Weiter?", - L"Die gespeicherten Spielstnde sind evtl. beschdigt Wollen Sie sie alle lschen?", + L"Die gespeicherten Spielstnde sind evtl. beschdigt. Wollen Sie sie alle lschen?", //Translators, the next two strings are for the same thing. The first one is for beta version releases and the second one @@ -3369,6 +3576,7 @@ STR16 zSaveLoadText[] = L"Versuche, lteren Spielstand zu laden. Laden und automatisch aktualisieren?", #endif + //Translators, the next two strings are for the same thing. The first one is for beta version releases and the second one //is used for the final version. Please don't modify the "#ifdef JA2BETAVERSION" or the "#else" or the "#endif" as they are //used by the compiler and will cause program errors if modified/removed. It's okay to translate the strings though. @@ -3377,6 +3585,7 @@ STR16 zSaveLoadText[] = #else L"Versuche, lteren Spielstand zu laden. Laden und automatisch aktualisieren?", #endif + L"Gespeichertes Spiel in Slot #%d wirklich berschreiben?", L"Wollen Sie das Spiel aus Slot # speichern?", @@ -3394,7 +3603,7 @@ STR16 zSaveLoadText[] = L"Real-Stil", L"SciFi-Stil", L"Schwierigkeit", - L"Platinum Mode", //Placeholder English + L"Platinum Mode", //Placeholder English L"Bobby Ray's", L"Normale Auswahl", L"Groe Auswahl", @@ -3402,7 +3611,7 @@ STR16 zSaveLoadText[] = L"Fantastische Auswahl", L"Neues Inventar funktioniert nicht in 640x480 Auflsung. Whlen Sie eine andere Auflsung und versuchen Sie es erneut.", - L"Neues Inventar funktioniert nicht mit dem ausgewhlten 'Data' Ordner.", + L"Neues Inventar funktioniert nicht mit dem ausgewhlten 'Data' Ordner.", }; //MapScreen @@ -3439,13 +3648,16 @@ STR16 zMarksMapScreenText[] = L"Es sind nicht genug Leute zum Training bereit.", L"%s ist voller Milizen.", L"Sldner hat begrenzten Vertrag.", - L"Vertrag des Sldners ist nicht versichert", + L"Vertrag des Sldners beinhaltet keine Versicherung.", L"Kartenbersicht", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"Sie haben derzeit keine Mobile Miliz. Rekrutieren Sie einige Milizen und kehren Sie zurck zu dieser Ansicht.", + L"Diese Ansicht zeigt Ihnen, wo Ihre Mobile Miliz ins feindliche Gebiet vorrcken kann. GRAU = Mobile Miliz verweigern hier vorzurcken. ROT = Mobile Miliz kann hier vorrcken, aber Sie haben den Befehl nicht gegeben. GELB = Mobile Miliz kann in den Sektor vorrcken, aber nicht verlassen. GRN = Mobile Miliz kann sich hier frei bewegen. Rechtsklick auf einen GRNEN / GELBEN Bereich um das Verhalten der Miliz zu ndern.", }; STR16 pLandMarkInSectorString[] = { - L"Trupp %d hat in Sektor %s jemanden bemerkt", + L"Trupp %d hat in Sektor %s jemanden bemerkt.", }; // confirm the player wants to pay X dollars to build a militia force in town @@ -3457,7 +3669,7 @@ STR16 pMilitiaConfirmStrings[] = L"Miliz in %s (%s %d) weitertrainieren?", // continue training this town? L"Preis $", // the cost in dollars to train militia L"( J/N )", // abbreviated yes/no - L"Miliz auf der Raketenbasis im Sektor %s (%s %d) weitertrainieren?", // continue trainign militia in SAM site sector + L"Miliz auf dem Raketensttzpunkt im Sektor %s (%s %d) weitertrainieren?", // continue trainign militia in SAM site sector L"Milizen in %d Sektoren zu trainieren kostet $ %d. %s", // cost to train sveral sectors at once L"Sie knnen sich keine $%d fr die Miliz hier leisten.", L"%s bentigt eine Loyalitt von %d Prozent, um mit dem Milizen-Training fortzufahren.", @@ -3480,6 +3692,67 @@ STR16 gzCopyrightText[] = L"Copyright (C) 1999 Sir-tech Canada Ltd. Alle Rechte vorbehalten.", // }; +/* // WANNE: not used yet, because the texts are too long! +//option Text +STR16 zOptionsToggleText[] = +{ + L"Sound: Sprache", + L"Sound: Stumme Besttigungen", + L"Info: Untertitel", + L"Spiel: Dialoge Pause", + L"Grafik: Rauch animieren", + L"Grafik: Blut zeigen", + L"Input: Meinen Cursor nicht bewegen!", + L"Input: Alte Auswahlmethode", + L"Grafik: Weg vorzeichnen", + L"Spiel: Fehlschsse anzeigen", + L"Spiel: Besttigung bei Echtzeit", + L"Info: Schlaf-/Wachmeldung anzeigen", + L"Info: Metrisches System benutzen", + L"Grafik: Boden beleuchten", + L"Input: Cursor autom. auf Sldner", + L"Input: Cursor autom. auf Tren", + L"Grafik: Gegenstnde leuchten", + L"Grafik: Baumkronen zeigen", + L"Grafik: Drahtgitter zeigen", + L"Grafik: 3D Cursor zeigen", + L"Spiel: Trefferchance anzeigen", + L"Spiel: GL Burst mit Burst Cursor", + L"Info: Gegner-Spott aktiveren", // Changed from "Enemies Drop all Items" - SANDRO + L"Spiel: Hohe Granatwerferflugbahn", + L"Spiel: Echtzeit-Schleichen aktivieren", // Changed from "Restrict extra Aim Levels" - SANDRO + L"Input: Nchste Gruppe selektieren", + L"Grafik: Gegenstnde mit Schatten", + L"Info: Waffenreichweite in Felder", + L"Grafik: Leuchtspur fr Einzelschsse", + L"Sound: Regengerusche", + L"Spiel: Krhen erlauben", + L"Info: Tooltips ber Gegner", + L"Spiel: Automatisch speichern", + L"Sound: Stummer Skyrider", + L"Grafik: Niedrige CPU Belastung", + L"Info: Erw. Gegenstandsinfo (EDB)", + L"Spiel: Erzwungener Runden-Modus", // add forced turn mode + L"Info: Status Trainingsfortschritt", // Show progress towards stat increase + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternatives Kartenfarbschema", // Change color scheme of Strategic Map + L"Alternative Projektilgrafik", // Show alternate bullet graphics (tracers) + L"--Cheat Mode Optionen--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, + L"Erzwinge Bobby Ray Lieferungen", // force all pending Bobby Ray shipments + L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END + L"--DEBUG OPTIONEN--", // an example options screen options header (pure text) + L"ALLE Einstellungen zurcksetzen", // failsafe show/hide option to reset all options + L"Wollen Sie wirklich zurcksetzen?", // a do once and reset self option (button like effect) + L"DEBUG Options in other builds", // allow debugging in release or mapeditor + L"DEBUG Render Option group", // an example option that will show/hide other options + L"Render Mouse Regions", // an example of a DEBUG build option + L"-----------------", // an example options screen options divider (pure text) + + // this is THE LAST option that exists (debug the options screen, doesnt do anything, except exist) + L"THE_LAST_OPTION", +}; +*/ + //option Text STR16 zOptionsToggleText[] = { @@ -3488,8 +3761,8 @@ STR16 zOptionsToggleText[] = L"Untertitel", L"Dialoge Pause", L"Rauch animieren", - L"Sichtbare Verletzungen", - L"Cursor nicht bewegen!", + L"Blut zeigen", + L"Meinen Cursor nicht bewegen!", L"Alte Auswahlmethode", L"Weg vorzeichnen", L"Fehlschsse anzeigen", @@ -3505,29 +3778,30 @@ STR16 zOptionsToggleText[] = L"3D Cursor zeigen", L"Trefferchance anzeigen", L"GL Burst mit Burst Cursor", - L"Gegner lassen alles fallen", - L"Granatwerferflugbahn erhhen", - L"Extra Zielgenauigkeit", + L"Gegner-Spott aktiveren", // Changed from "Enemies Drop all Items" - SANDRO + L"Hohe Granatwerferflugbahn", + L"Echtzeit-Schleichen aktivieren", // Changed from "Restrict extra Aim Levels" - SANDRO L"Nchste Gruppe selektieren", L"Gegenstnde mit Schatten", L"Waffenreichweite in Felder", - L"Tracereffekte fr Einzelschsse", + L"Leuchtspur fr Einzelschsse", L"Regengerusche", L"Krhen erlauben", - L"Tooltips ber Gegner", // Changed from "Random I.M.P personality" - SANDRO + L"Tooltips ber Gegner", L"Automatisch speichern", L"Stummer Skyrider", L"Niedrige CPU Belastung", L"Erw. Gegenstandsinfo (EDB)", L"Erzwungener Runden-Modus", // add forced turn mode L"Status Trainingsfortschritt", // Show progress towards stat increase + L"Alternative Projektilgrafik", // Show alternate bullet graphics (tracers) L"--Cheat Mode Optionen--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, - L"Erzwinge Bobby Ray Lieferungen", // force all pending Bobby Ray shipments + L"Erzwinge BR Lieferungen", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END L"--DEBUG OPTIONEN--", // an example options screen options header (pure text) L"ALLE Einstellungen rcksetzen", // failsafe show/hide option to reset all options - L"Wollen Sie wirklich rcksetzen?", // a do once and reset self option (button like effect) - L"Debug Options in other builds", // allow debugging in release or mapeditor + L"Wollen Sie wirklich rcksetzen?", // a do once and reset self option (button like effect) + L"DEBUG Options in other builds", // allow debugging in release or mapeditor L"DEBUG Render Option group", // an example option that will show/hide other options L"Render Mouse Regions", // an example of a DEBUG build option L"-----------------", // an example options screen options divider (pure text) @@ -3539,17 +3813,19 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech - L"Mit dieser Option hren Sie die Dialoge.", + L"Wenn diese Funktion aktiviert ist, werden in Dialogen Stimmen wiedergegeben. Anderenfalls wird nur der Text angezeigt.", //Mute Confirmation - L"Schaltet die gesprochenen Besttigungen an oder aus.", + L"Schalten Sie mit dieser Funktion die gesprochenen Besttigungen (wie \"Okay\" oder \"Bin dran\") aus, wenn sie stren.", //Subtitles - L"Schaltet Untertitel fr Dialoge ein oder aus.", + L"Wenn diese Funktion aktiviert ist, wird in Dialogen der entsprechende Text angezeigt.", //Key to advance speech - L"Wenn Untertitel AN sind, hat man durch diese Option Zeit, Dialoge von NPCs zu lesen.", + L"Schalten Sie diese Funktion AN, wenn Sie Dialoge von NPCs ganz in Ruhe lesen wollen. Untertitel mssen dazu AN sein.", //Toggle smoke animation L"Schalten Sie diese Option ab, wenn animierter Rauch Ihre Bildwiederholrate verlangsamt.", @@ -3558,65 +3834,68 @@ STR16 zOptionsScreenHelpText[] = L"Diese Option abschalten, wenn Sie kein Blut sehen knnen.", //Never move my mouse - L"Wenn Sie diese Option abstellen, wird der Mauszeiger nicht mehr von den Popup-Fenstern verdeckt.", + L"Schalten Sie diese Option ab, wenn Sie nicht mchten, dass Ihr Mauszeiger automatisch auf Pop-Up-Fenster springt.", //Old selection method L"Mit dieser Option funktioniert die Auswahl der Sldner so wie in frheren JAGGED ALLIANCE-Spielen (also genau andersherum als jetzt).", //Show movement path - L"Diese Funktion ANschalten, um die geplanten Wege der Sldner in Echtzeit anzuzeigen\n(oder abgeschaltet lassen und bei gewnschter Anzeige die |S|H|I|F|T-Taste drcken).", + L"Diese Funktion ANschalten, um die geplanten Wege der Sldner zum Cursor anzuzeigen\n(oder abgeschaltet lassen und bei gewnschter Anzeige die |S|H|I|F|T-Taste drcken).", //show misses - L"Mit dieser Option zeigt Ihnen das Spiel, wo Ihre Kugeln hinfliegen, wenn Sie \"nicht treffen\".", + L"Wenn diese Funktion aktiviert ist, folgt die Spielkamera im Rundenmodus der Geschossflugbahn bis zu ihrem Ende. Ausschalten um das Spiel zu beschleunigen.", //Real Time Confirmation - L"Durch diese Option wird vor der Rckkehr in den Echtzeit-Modus ein zustzlicher \"Sicherheits\"-Klick verlangt.", + L"Wenn diese Funktion aktiviert ist, wird fr jede Aktion im Echtzeit-Modus ein zustzlicher \"Sicherheits\"-Klick verlangt um versehentliche Befehle zu vermeiden.", //Sleep/Wake notification - L"Wenn ANgeschaltet werden Sie informiert, wann Ihre Sldner, die sich im \"Dienst\" befinden schlafen oder die Arbeit wieder aufnehmen.", + L"Schalten Sie diese Option aus, wenn Sie kein Popup erhalten wollen, sobald zu einem Dienst eingeteilte Sldner schlafen gehen oder die Arbeit wieder aufnehmen.", //Use the metric system - L"Mit dieser Option wird im Spiel das metrische System verwendet.", + L"Mit dieser Option wird im Spiel das metrische anstelle des imperialen Masystems verwendet (z.B. Meter und Kilogramm).", //Merc Lighted movement - L"Diese Funktion ANschalten, wenn der Sldner beim Gehen den Boden beleuchten soll. AUSgeschaltet erhht sich die Bildwiederholrate.", + L"Diese Funktion beleuchtet fr den Spieler die Umgebung des Sldners - auch beim Bewegen. AUSgeschaltet erhht sich die Bildwiederholrate.", //Smart cursor - L"Wenn diese Funktion aktiviert ist, werden Sldner automatisch hervorgehoben, sobald der Cursor in ihrer Nhe ist.", + L"Wenn diese Funktion aktiviert ist, springt der Cursor immer automatisch auf Sldner in seiner direkten Nhe.", //snap cursor to the door - L"Wenn diese Funktion aktiviert ist, springt der Cursor automatisch auf eine Tr, sobald eine in der Nhe ist.", + L"Wenn diese Funktion aktiviert ist, springt der Cursor automatisch auf Tren in direkter Nhe des Mauszeigers.", //glow items - L"ANgeschaltet, bekommen Gegenstnde einen pulsierenden Rahmen (|I).", + L"Wenn diese Funktion aktiviert ist, haben Gegenstnde am Boden zur besseren Sichtbarkeit einen pulsierenden Rahmen (|I).", //toggle tree tops - L"ANgeschaltet, werden die Baumkronen gezeigt (|T).", + L"Mit der Deaktivierung dieser Funktion lassen sich Baumkronen ausblenden um bessere Sicht auf das Geschehen zu ermglichen (|T).", //toggle wireframe - L"ANgeschaltet, werden Drahtgitter fr verborgene Wnde gezeigt (|W).", + L"Wenn diese Funktion aktiviert ist, werden Drahtgitter verborgener Wnde gezeigt um z.B. perspektivisch verdeckte Fenster zu erkennen (|W).", - L"ANgeschaltet, wird der Bewegungs-Cursor in 3D angezeigt (|Home).", + L"Wenn diese Funktion aktiviert ist, wird der Bewegungs-Cursor in 3D angezeigt (|Home).", // Options for 1.13 L"Wenn diese Funktion aktiviert ist, wird die Trefferwahrscheinlichkeit am Cursor angezeigt.", - L"Wenn diese Funktion aktiviert ist, wird fr einen GL Burst der Burst Cursor angezeigt.", - L"Wenn diese Funktion aktiviert ist, lassen tote Gegner alle Gegenstnde am Boden zurck.", - L"Wenn diese Funktion aktiviert ist, knnen Granatwerfer Granaten in hherem Winkel abfeuern (|Q).", - L"Wenn diese Funktion aktiviert ist, kann die Zielgenauigkeit von Gewehren und Scharfschtzengewehren ber 4 gesteigert werden.", - L"Wenn diese Funktion aktiviert ist, selektiert |S|p|a|c|e automatisch die nchste Gruppe.", - L"Wenn diese Funktion aktiviert ist, wird der Schatten von Gegenstnden angezeigt.", - L"Wenn diese Funktion aktiviert ist, werden Waffenreichweiten in Feldern angezeigt.", - L"Wenn diese Funktion aktiviert ist, wird Tracereffekt auch fr Einzelschsse angezeigt.", + L"Mit dieser Funktion lsst sich der Zielcursor fr Granatwerfer-Feuerste umschalten. Der Burst-Cursor (wenn AN) ermglicht den Beschuss einer greren Flche.", + L"Wenn diese Funktion aktiviert ist, beschimpfen Gegner den Spieler oder kommentieren ihre Situation mittels kleiner Pop-Ups.", // Changed from Enemies Drop All Items - SANDRO + L"Wenn diese Funktion aktiviert ist, knnen Granatwerfer Granaten in hherem Winkel abfeuern und so ihre volle Reichweite ausnutzen (|Q).", + L"Wenn diese Funktion aktiviert ist, schaltet das Spiel fr unbemerkt schleichende Sldner nicht automatisch in den Rundenmodus sobald Gegner in Sicht geraten, auer Sie drcken |S|t|r|g+|X.", // Changed from Restrict Extra Aim Levels - SANDRO + L"Wenn diese Funktion aktiviert ist, selektiert |S|p|a|c|e automatisch die nchste Gruppe statt den nchsten Sldner der Gruppe.", + L"Wenn diese Funktion aktiviert ist, werfen Gegenstnde einen Schatten.", + L"Wenn diese Funktion aktiviert ist, werden Waffenreichweiten in Feldern angezeigt statt in z.B. Metern.", + L"Wenn diese Funktion aktiviert ist, wird auch fr Einzelschsse mit Leuchtspurmunition der grafische Effekt dazu angezeigt.", L"Wenn diese Funktion aktiviert ist, werden Regengerusche hrbar, sobald es regnet.", - L"Wenn diese Funktion aktiviert ist, sind Krhen im Spiel vorhanden.", - L"Wenn diese Funktion aktiviert ist, erscheint ein Tooltip Fenster ber dem Gegner, bei gleichzeitigem Drcken von |A|l|t und Halten des Cursors ber dem Feind.", // - Changed from random IMP personality - SANDRO - L"Wenn diese Funktion aktiviert ist, wird nach jeder Runde automatisch gespeichert.", - L"Wenn diese Funktion aktiviert ist, wird Skyrider nichts mehr sprechen.", - L"Wenn diese Funktion aktiviert ist, wird das Spiel mit viel geringerer CPU Belastung laufen.", - L"Wenn diese Funktion aktiviert ist, werden erweiterte Beschreibungen zu den Waffen und Gegenstnden angezeigt.", + L"Wenn diese Funktion aktiviert ist, sind Krhen im Spiel vorhanden und hacken lautstark an manchen Leichen herum, haben aber sonst keine groen Auswirkungen auf das Spiel.", + L"Wenn diese Funktion aktiviert ist, werden mit Druck auf |A|l|t Informationen ber den Gegner eingeblendet, der unter dem Mauszeiger steht. Hinweis: Wenn nicht anders eingestellt, muss dieser in guter Sichtweite eigener Truppen sein.", + L"Wenn diese Funktion aktiviert ist, wird nach jeder Runde automatisch in einen speziellen Autosave-Spielstand gespeichert.", + L"Wenn diese Funktion aktiviert ist, wird Skyrider nichts mehr sagen. Verwenden Sie diese Option, wenn er Ihnen auf die Nsse geht.", + L"Aktivieren Sie diese Funktion, wenn Ihr Rechner steinalt ist und anderenfalls Probleme auftreten wrden.", + L"Wenn diese Funktion aktiviert ist, werden erweiterte Beschreibungen und Werte zu den Waffen und Gegenstnden angezeigt.", L"Wenn diese Funktion aktiviert ist und noch Gegner im Sektor sind, bleibt das Spiel im Runden-Modus, bis alle Feinde tot sind (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", - L"Wenn diese Funktion aktiviert ist, wird der Trainingsfortschritt fr die Sldner angezeigt.", + L"Wenn diese Funktion aktiviert ist, werden die Sldnerwerte visuell mit ihrem Trainingsfortschritt unterlegt.", + L"|H|A|M |4 |D|e|b|u|g: Wenn diese Funktion aktiviert ist, wird der Abstand den jede die Kugel vom Zielmittelpunkt abweicht, unter Bercksichtigung aller CTH-Faktoren, ausgegeben.", + L"Wenn diese Funktion aktiviert ist, wird die Strategische Karte entsprechend Ihres Erkundungsfortschrittes unterschiedlich eingefrbt.", + L"Wenn diese Funktion aktiviert ist, werden geschossene Projektile visuell mit Tracereffekten dargestellt.", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3641,29 +3920,58 @@ STR16 gzGIOScreenText[] = L"SciFi", L"Platinum", //Placeholder English L"Waffen", - L"Zustzliche Waffen", + L"Zus. Waffen", L"Normal", L"Schwierigkeitsgrad", L"Einsteiger", L"Profi", L"Alter Hase", L"WAHNSINNIG", - L"Ok", + L"Starten", L"Abbrechen", - L"Extraschwer", - L"Immer speichern mglich", - L"Ironman", + L"Extraschwer (Speichern erlauben)", + L"Jederzeit", + L"Nicht im Kampf", L"Option nicht verfgbar", L"Bobby Ray's Auswahl", L"Normal", L"Gro", L"Ausgezeichnet", L"Fantastisch", - L"Inventar System", - L"Alt", - L"Neu", + L"Inventar / Attachments", + L"NOT USED", // Alt (Original) + L"NOT USED", // Neu - mit Trageausr. L"Lade MP Spiel", L"GRUNDEINSTELLUNGEN (Nur Servereinstellungen werden verwendet)", + // Added by SANDRO + L"Fertigkeiten", + L"Alte", + L"Neue", + L"Max. BSE-Charaktere", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Tote Gegner lassen alles fallen", + L"Aus", + L"An", + L"Anzahl der Terroristen", + L"Zufllig", + L"Alle vorhanden", + L"Geheime Waffenlager", + L"Zufllig", + L"Alle vorhanden", + L"Fortschritt Waffenwahl", + L"Sehr langsam", + L"Langsam", + L"Normal", + L"Schnell", + L"Sehr schnell", + L"Alt / Alt", + L"Neu / Alt", + L"Neu / Neu", }; STR16 gzMPJScreenText[] = @@ -3673,17 +3981,33 @@ STR16 gzMPJScreenText[] = L"Erffnen", L"Abbrechen", L"Aktualisieren", - L"Spieler Name", - L"Server IP", + L"Spielername", + L"Server-IP", L"Port", - L"Server Name", + L"Servername", L"# Spieler", L"Version", L"Spieltyp", L"Ping", - L"Sie mssen einen Spieler Name eingeben.", - L"Sie mssen eine gltie Server IP Adresse eingeben.\n (Bsp: 84.114.195.239).", - L"Sie mssen eine gltige Server Portnummer zwischen 1 und 65535 eingeben.", + L"Sie mssen einen Spielernamen eingeben.", + L"Sie mssen eine gltie Server-IP-Adresse eingeben.\n (Bsp: 84.114.195.239).", + L"Sie mssen eine gltige Server-Portnummer zwischen 1 und 65535 eingeben.", +}; + +STR16 gzMPJHelpText[] = +{ + L"Besuchen Sie http://webchat.quakenet.org/?channels=ja2-multiplayer um sich mit anderen Spielern zu treffen.", + + L"ERFFNEN", + L"Geben Sie '127.0.0.1' fr die IP Adresse ein. Die Port Nummer sollte grer als 60000 sein.", + L"Vergewissern Sie sich, dass das Port (UDP, TCP) auf dem Router weitergeleitet wird. Siehe: http://portforward.com", + L"Sie mssen Ihre externe IP (http://www.whatismyip.com) und die Port Nummmer an die anderen Spieler schicken (via IRC, ICQ, etc.).", + L"Klicken Sie auf 'Erffnen', um ein neues Spiel zu erffnen.", + + L"TEILNEHMEN", + L"Der Host muss Ihnen die externe IP Adresse und die Port Nummer schicken (via IRC, ICQ, etc.).", + L"Geben Sie die externe IP und die Port Nummer des Hosts ein.", + L"Klicken Sie auf 'Teilnehmen', um an einem bereits erffneten Spiel teilzunehmen.", }; STR16 gzMPHScreenText[] = @@ -3691,60 +4015,96 @@ STR16 gzMPHScreenText[] = L"ERFFNE SPIEL", L"Starten", L"Abbrechen", - L"Server Name", + L"Servername", L"Spieltyp", L"Deathmatch", - L"Team Deathmatch", - L"CO-OP", - L"Max. Spieler", - L"Teamgre", + L"Team-Deathmatch", + L"Kooperativ (CO-OP)", + L"Maximale Spieler", + L"Maximale Sldner", L"Sldnerauswahl", - L"Zufllige Sldner anheuern", + L"Sldnerrekrutierung", L"Sldner selbst whlen", L"Startkapital", - L"Kann gleiche Sldner anheuern", - L"Zeige angeheuerten Sldner", - L"Bobby Ray erlauben", - L"Zufllige Startzone", - L"Sie mssen einen Server Namen eingeben.", - L"Max. Spieleranzahl muss zwischen 2 und 4 sein.", - L"Teamgre muss zwischen 1 und 6 sein.", + L"Gleiche Sldner erlaubt", + L"Angeheuerte Sldner anzeigen", + L"Bobby Ray", + L"Sektor Startzone", + L"Sie mssen einen Servernamen eingeben.", + L"", + L"", L"Tageszeit", - L"Tageszeit muss eine 24h Zeit (SS:MM) sein.", - L"Startkapital muss ein gltiger Dollerwert (keine Cents) sein." , - L"Schaden Multiplikator", - L"Schaden Multiplikator muss zwischen 0 and 5 sein.", - L"Zeit Multiplikator", - L"Zeit Multiplikator muss zwischen 0 (keine Zeitbegrenzung) and 200 (max. Zeitbegrenzung) sein.", + L"", + L"" , + L"Waffenschaden", + L"", + L"Rundenzeitbegrenzung", + L"", L"Erlaube Zivilisten in CO-OP", - L"Verwende neues Inventar (NIV)", - L"Erzwinge maximale AI Gegner", - L"Synk. MP Client Verzeichnisse", - L"MP Synk. Verzeichnis", - L"Sie mssen ein gltiges MP Synchronsiationsverzeichnis eingeben.", + L"", + L"Maximale KI-Gegner in CO-OP", + L"Synchronisiere Verzeichnisse", + L"Synchronisationsverzeichnis", + L"Sie mssen ein gltiges MP-Synchronisationsverzeichnis eingeben.", L"(Benutzen Sie '/' anstelle von '\\' als Verzeichnistrennzeichen.)", - L"Das angegebene MP Synk. Verzeichnis existiert nicht.", + L"Das angegebene MP-Synch.-Verzeichnis existiert nicht.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Ja", + L"Nein", + // Starting Time + L"Morgen", + L"Nachmittag", + L"Nacht", + // Starting Cash + L"Wenig", + L"Mittel", + L"Viel", + L"Unendlich", + // Time Turns + L"Niemals", + L"Langsam", + L"Mittel", + L"Schnell", + // Weapon Damage + L"Sehr gering", + L"Gering", + L"Normal", + // Merc Hire + L"Zufllig", + L"Normal", + // Sector Edge + L"Zufllig", + L"Whlbar", + // Bobby Ray / Hire same merc + L"Verbieten", + L"Erlauben", }; STR16 pDeliveryLocationStrings[] = { L"Austin", //Austin, Texas, USA L"Bagdad", //Baghdad, Iraq (Suddam Hussein's home) - L"Drassen", //The main place in JA2 that you can receive items. The other towns are dummy names... - L"Hong Kong", //Hong Kong, Hong Kong + L"Drassen", //The main place in JA2 that you can receive items. The other towns except Meduna are dummy names... + L"Hong Kong", //Hong Kong, Hong Kong L"Beirut", //Beirut, Lebanon (Middle East) L"London", //London, England - L"Los Angeles", //Los Angeles, California, USA (SW corner of USA) + L"Los Angeles", //Los Angeles, California, USA (SW corner of USA) L"Meduna", //Meduna -- the other airport in JA2 that you can receive items. - L"Metavira", //The island of Metavira was the fictional location used by JA1 - L"Miami", //Miami, Florida, USA (SE corner of USA) + L"Metavira", //The island of Metavira was the fictional location used by JA1 + L"Miami", //Miami, Florida, USA (SE corner of USA) L"Moskau", //Moscow, USSR - L"New York", //New York, New York, USA + L"New York", //New York, New York, USA L"Ottawa", //Ottawa, Ontario, Canada -- where JA2 was made! - L"Paris", //Paris, France - L"Tripolis", //Tripoli, Libya (eastern Mediterranean) - L"Tokio", //Tokyo, Japan - L"Vancouver", //Vancouver, British Columbia, Canada (west coast near US border) + L"Paris", //Paris, France + L"Tripolis", //Tripoli, Libya (eastern Mediterranean) + L"Tokio", //Tokyo, Japan + L"Vancouver", //Vancouver, British Columbia, Canada (west coast near US border) }; STR16 pSkillAtZeroWarning[] = @@ -3804,41 +4164,41 @@ STR16 pMessageStrings[] = L"ABBRECHEN", L"ZURCK", L"LGEN", - L"Keine Beschreibung", //Save slots that don't have a description. + L"Keine Beschreibung", //Save slots that don't have a description. L"Spiel gespeichert", L"Spiel gespeichert", - L"QuickSave", //10 The name of the quicksave file (filename, text reference) - L"Spielstand", //The name of the normal savegame file, such as SaveGame01, SaveGame02, etc. - L"sav", //The 3 character dos extension (represents sav) - L"..\\Spielstnde", //The name of the directory where games are saved. + L"QuickSave", //10 //The name of the quicksave file (filename, text reference) + L"Spielstand", //The name of the normal savegame file, such as SaveGame01, SaveGame02, etc. + L"sav", //The 3 character dos extension (represents sav) + L"..\\Spielstnde", //The name of the directory where games are saved. L"Tag", L"Sldner", - L"Leerer Slot", //An empty save game slot + L"Leerer Slot", //An empty save game slot L"Demo", //Demo of JA2 L"Debug", //State of development of a project (JA2) that is a debug build L"Verffentlichung", //Release build for JA2 - L"KpM", //20 Abbreviation for Rounds per minute -- the potential # of bullets fired in a minute. + L"RpM", //20 //Abbreviation for Rounds per minute -- the potential # of bullets fired in a minute. //LOOTF - KpM macht Augenkrebs, KpM gibt es einfach nicht. L"min", //Abbreviation for minute. - L"m", //One character abbreviation for meter (metric distance measurement unit). - L"Kgln", //Abbreviation for rounds (# of bullets) + L"m", //One character abbreviation for meter (metric distance measurement unit). + L"Kgln", //Abbreviation for rounds (# of bullets) //LOOTF - character limit? Kugeln = kacke, will ndern! L"kg", //Abbreviation for kilogram (metric weight measurement unit) L"Pfd", //Abbreviation for pounds (Imperial weight measurement unit) L"Home", //Home as in homepage on the internet. L"US$", //Abbreviation for US Dollars - L"n.a.", //Lowercase acronym for not applicable. - L"Inzwischen", //Meanwhile - L"%s ist angekommen im Sektor %s%s", //30 Name/Squad has arrived in sector A9. Order must not change without notifying SirTech + L"n.a.", //Lowercase acronym for not applicable. + L"Inzwischen", //Meanwhile + L"%s ist im Sektor %s%s angekommen", //30 //Name/Squad has arrived in sector A9. Order must not change without notifying SirTech L"Version", L"Leerer Quick-Save-Slot", - L"Dieser Slot ist nur fr Quick-Saves aus den Map Screens und dem Taktik-Bildschirm. Speichern mit ALT+S", + L"Dieser Slot ist fr Quick-Saves aus dem Karten- oder Taktik-Bildschirm reserviert. Speichern mit ALT+S.", L"offen", L"zu", L"Ihr Festplattenspeicher ist knapp. Sie haben lediglich %sMB frei und Jagged Alliance 2 v1.13 bentigt %sMB.", L"%s von AIM angeheuert", - L"%s hat %s gefangen.", //'Merc name' has caught 'item' -- let SirTech know if name comes after item. + L"%s hat %s gefangen.", //'Merc name' has caught 'item' -- let SirTech know if name comes after item. - L"%s hat die Droge genommen.", //'Merc name' has taken the drug - L"%s hat keine medizinischen Fhigkeiten",//40 'Merc name' has no medical skill. + L"%s hat die Droge genommen.", //'Merc name' has taken the drug + L"%s hat keine medizinischen Fhigkeiten",//40 //'Merc name' has no medical skill. //CDRom errors (such as ejecting CD while attempting to read the CD) L"Die Integritt des Spieles wurde beschdigt.", //The integrity of the game has been compromised @@ -3848,15 +4208,14 @@ STR16 pMessageStrings[] = L"Kein Platz, um von hier aus zu feuern.", //Can't change stance due to objects in the way... - L"Kann seine Position jetzt nicht ndern.", + L"Kann seine Position hier nicht ndern.", //Simple text indications that appear in the game, when the merc can do one of these things. L"Ablegen", L"Werfen", L"Weitergeben", - L"%s weitergegeben an %s.", //"Item" passed to "merc". Please try to keep the item %s before the merc %s, otherwise, - //must notify SirTech. + L"%s weitergegeben an %s.", //"Item" passed to "merc". Please try to keep the item %s before the merc %s, otherwise you must notify SirTech. L"Kein Platz, um %s an %s weiterzugeben.", //pass "item" to "merc". Same instructions as above. //A list of attachments appear after the items. Ex: Kevlar vest ( Ceramic Plate 'Attached )' @@ -3867,10 +4226,10 @@ STR16 pMessageStrings[] = L"Cheat-Level ZWEI erreicht", //Toggling various stealth modes - L"Stealth Mode fr Trupp ein.", - L"Stealth Mode fr Trupp aus.", - L"Stealth Mode fr %s ein.", - L"Stealth Mode fr %s aus.", + L"Schleichbewegung fr Trupp ein.", + L"Schleichbewegung fr Trupp aus.", + L"Schleichbewegung fr %s ein.", + L"Schleichbewegung fr %s aus.", //Wireframes are shown through buildings to reveal doors and windows that can't otherwise be seen in //an isometric engine. You can toggle this mode freely in the game. @@ -3880,7 +4239,7 @@ STR16 pMessageStrings[] = //These are used in the cheat modes for changing levels in the game. Going from a basement level to //an upper level, etc. L"Von dieser Ebene geht es nicht nach oben...", - L"Noch tiefere Ebenen gibt es nicht...", // 60 + L"Noch tiefere Ebenen gibt es nicht...", // 60 L"Gewlbeebene %d betreten...", L"Gewlbe verlassen...", @@ -3896,24 +4255,26 @@ STR16 pMessageStrings[] = L"Spielstand namens Spielstand99.sav kreiert. Wenn ntig, in Spielstand01 - Spielstand10 umbennen und ber die Option 'Laden' aufrufen.", L"%s hat %s getrunken.", L"Paket in Drassen angekommen.", - L"%s kommt am %d. um ca. %s am Zielort an (Sektor %s).", //first %s is mercs name(OK), next is the sector location and name where they will be arriving in, lastely is the day an the time of arrival !!!7 It should be like this: first one is merc (OK), next is day of arrival (OK) , next is time of the day for ex. 07:00 (not OK, now it is still sector), next should be sector (not OK, now it is still time of the day) + L"%s kommt am %d. um ca. %s am Zielort an (Sektor %s).", //first %s is mercs name(OK), next is the sector location and name where they will be arriving in, lastely is the day an the time of arrival !!!7 It should be like this: first one is merc (OK), next is day of arrival (OK) , next is time of the day for ex. 07:00 (not OK, now it is still sector), next should be sector (not OK, now it is still time of the day) //LOOTF - is this still valid? I assume it's not. L"Logbuch aktualisiert.", - L"Granaten Feuerste verwenden Ziel Cursor (Sperrfeuer aktiviert).", - L"Granaten Feuerste verwenden Flugbahn Cursor (Sperrfeuer deaktiviert).", - L"Alles fallen lassen einschalten.", - L"Alles fallen lassen ausschalten.", // 80 - L"Granatwerfer schieen im normalen Winkel.", - L"Granatwerfer schieen im erhhten Winkel.", + L"Granatenwerfer-Feuerste verwenden Ziel-Cursor (Sperrfeuer aktiviert).", + L"Granatenwerfer-Feuerste verwenden Flugbahn-Cursor (Sperrfeuer deaktiviert).", + L"Soldaten-Kurzinfo (\"Tooltips\") aktiviert", // Changed from Drop All On - SANDRO + L"Soldaten-Kurzinfo (\"Tooltips\") deaktiviert", // Changed from Drop All Off - SANDRO + L"Granatwerfer schieen in flachem Winkel.", + L"Granatwerfer schieen in steilem Winkel.", // forced turn mode strings - L"Erzwungener Runden Modus", - L"Normaler Runden Modus", - L"Verlasse Kampf Modus", - L"Erzwungener Runden Modus ist aktiv, gehen in Kampf Modus", + L"Erzwungener Rundenmodus", + L"Normaler Rundenmodus", + L"Verlasse Kampfmodus", + L"Erzwungener Rundenmodus ist aktiv, gehe in Kampfmodus", #ifdef JA2BETAVERSION - L"Spiel erfolgreich im Slot End Turn Auto Save gespeichert.", // 83 + L"Spiel erfolgreich im Slot End Turn Auto Save gespeichert.", // 83 #endif - L"..\\Spielstnde\\MP_Spielstnde", //The name of the directory where games are saved. + L"..\\Spielstnde\\MP_Spielstnde", //The name of the directory where games are saved. L"Client", + + L"Sie knnen nicht altes Inventar und neues Attachment System gleichzeitig verwenden.", }; CHAR16 ItemPickupHelpPopup[][40] = @@ -3941,7 +4302,7 @@ STR16 pMilitiaButtonsHelpText[] = STR16 pMapScreenJustStartedHelpText[] = { - L"Zu AIM gehen und Sldner anheuern ( *Tip*: Befindet sich im Laptop )", // to inform the player to hired some mercs to get things going + L"Zu AIM gehen und Sldner anheuern ( *Tip*: Befindet sich im Laptop )", // to inform the player to hire some mercs to get things going L"Sobald Sie fr die Reise nach Arulco bereit sind, klicken Sie auf den Zeitraffer-Button unten rechts auf dem Bildschirm.", // to inform the player to hit time compression to get the game underway }; @@ -4047,7 +4408,7 @@ STR16 wMapScreenSortButtonHelpText[] = STR16 BrokenLinkText[] = { L"Error 404", - L"Site nicht gefunden.", + L"Seite nicht gefunden.", }; STR16 gzBobbyRShipmentText[] = @@ -4080,57 +4441,57 @@ STR16 gzCreditNames[]= STR16 gzCreditNameTitle[]= { L"Game Internals Programmer", // Chris Camfield - L"Co-designer/Writer", // Shaun Lyng - L"Strategic Systems & Editor Programmer", //Kris \"The Cow Rape Man\" Marnes - L"Producer/Co-designer", // Ian Currie - L"Co-designer/Map Designer", // Linda Currie - L"Artist", // Eric \"WTF\" Cheng - L"Beta Coordinator, Support", // Lynn Holowka - L"Artist Extraordinaire", // Norman \"NRG\" Olsen - L"Sound Guru", // George Brooks - L"Screen Designer/Artist", // Andrew Stacey - L"Lead Artist/Animator", // Scot Loving - L"Lead Programmer", // Andrew \"Big Cheese Doddle\" Emmons - L"Programmer", // Dave French - L"Strategic Systems & Game Balance Programmer", // Alex Meduna - L"Portraits Artist", // Joey \"Joeker\" Whelan", + L"Co-designer/Writer", // Shaun Lyng + L"Strategic Systems & Editor Programmer", // Kris \"The Cow Rape Man\" Marnes + L"Producer/Co-designer", // Ian Currie + L"Co-designer/Map Designer", // Linda Currie + L"Artist", // Eric \"WTF\" Cheng + L"Beta Coordinator, Support", // Lynn Holowka + L"Artist Extraordinaire", // Norman \"NRG\" Olsen + L"Sound Guru", // George Brooks + L"Screen Designer/Artist", // Andrew Stacey + L"Lead Artist/Animator", // Scot Loving + L"Lead Programmer", // Andrew \"Big Cheese Doddle\" Emmons + L"Programmer", // Dave French + L"Strategic Systems & Game Balance Programmer", // Alex Meduna + L"Portraits Artist", // Joey \"Joeker\" Whelan", }; STR16 gzCreditNameFunny[]= { - L"", // Chris Camfield - L"(still learning punctuation)", // Shaun Lyng - L"(\"It's done. I'm just fixing it\")", //Kris \"The Cow Rape Man\" Marnes - L"(getting much too old for this)", // Ian Currie - L"(and working on Wizardry 8)", // Linda Currie - L"(forced at gunpoint to also do QA)", // Eric \"WTF\" Cheng + L"", // Chris Camfield + L"(still learning punctuation)", // Shaun Lyng + L"(\"It's done. I'm just fixing it\")", //Kris \"The Cow Rape Man\" Marnes + L"(getting much too old for this)", // Ian Currie + L"(and working on Wizardry 8)", // Linda Currie + L"(forced at gunpoint to also do QA)", // Eric \"WTF\" Cheng L"(Left us for the CFSA - go figure...)", // Lynn Holowka - L"", // Norman \"NRG\" Olsen - L"", // George Brooks - L"(Dead Head and jazz lover)", // Andrew Stacey - L"(his real name is Robert)", // Scot Loving - L"(the only responsible person)", // Andrew \"Big Cheese Doddle\" Emmons - L"(can now get back to motocrossing)", // Dave French - L"(stolen from Wizardry 8)", // Alex Meduna + L"", // Norman \"NRG\" Olsen + L"", // George Brooks + L"(Dead Head and jazz lover)", // Andrew Stacey + L"(his real name is Robert)", // Scot Loving + L"(the only responsible person)", // Andrew \"Big Cheese Doddle\" Emmons + L"(can now get back to motocrossing)", // Dave French + L"(stolen from Wizardry 8)", // Alex Meduna L"(did items and loading screens too!)", // Joey \"Joeker\" Whelan", }; STR16 sRepairsDoneString[] = { - L"%s hat seine eigenen Gegenstnde repariert", + L"%s hat seine eigenen Gegenstnde repariert", L"%s hat die Waffen und Rstungen aller Teammitglieder repariert", L"%s hat die aktivierten Gegenstnde aller Teammitglieder repariert", L"%s hat die groen mitgefhrten Gegenstnde aller Teammitglieder repariert", L"%s hat die mittelgroen mitgefhrten Gegenstnde aller Teammitglieder repariert", L"%s hat die kleinen mitgefhrten Gegenstnde aller Teammitglieder repariert", - L"%s hat die LBE-Gegenstnde aller Teammitglieder repariert", + L"%s hat die Trageausrstung aller Teammitglieder repariert", }; STR16 zGioDifConfirmText[]= { - L"Sie haben sich fr den EINSTEIGER-Modus entschieden. Dies ist die passende Einstellung fr Spieler, die noch nie zuvor Jagged Alliance oder hnliche Spiele gespielt haben oder fr Spieler, die sich ganz einfach krzere Schlachten wnschen. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im Einsteiger-Modus spielen wollen?", - L"Sie haben sich fr den FORTGESCHRITTENEN-Modus entschieden. Dies ist die passende Einstellung fr Spieler, die bereits Erfahrung mit Jagged Alliance oder hnlichen Spielen haben. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im Fortgeschrittenen-Modus spielen wollen?", - L"Sie haben sich fr den PROFI-Modus entschieden. Na gut, wir haben Sie gewarnt. Machen Sie hinterher blo nicht uns dafr verantwortlich, wenn Sie im Sarg nach Hause kommen. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im Profi-Modus spielen wollen?", + L"Sie haben sich fr den Einsteiger-Modus entschieden. Dies ist die passende Einstellung fr Spieler, die noch nie zuvor Jagged Alliance oder hnliche Spiele gespielt haben oder fr Spieler, die sich ganz einfach krzere Schlachten wnschen. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im Einsteiger-Modus spielen wollen?", + L"Sie haben sich fr den Profi-Modus entschieden. Dies ist die passende Einstellung fr Spieler, die bereits Erfahrung mit Jagged Alliance oder hnlichen Spielen haben. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im Profi-Modus spielen wollen?", + L"Sie haben sich fr den Alter Hase-Modus entschieden. Na gut, wir haben Sie gewarnt. Machen Sie hinterher blo nicht uns dafr verantwortlich, wenn Sie im Sarg nach Hause kommen. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im Alter Hase-Modus spielen wollen?", L"Sie haben sich fr den WAHNSINNIG-Modus entschieden. WARNUNG: Beschweren Sie sich nicht, wenn Sie in kleinen Stcken zurckkommen ... Deidranna wird Sie in den Allerwertesten treten und das schmerzhaft. Ihre Wahl wird den Verlauf des ganzen Spiels beeinflussen. Treffen Sie also eine sorgfltige Wahl. Sind Sie ganz sicher, dass Sie im WAHNSINNIG-Modus spielen wollen?", }; @@ -4235,7 +4596,7 @@ STR16 gzLateLocalizedString[] = //46-48 L"%ss Gewehrlauf-Verlngerung fllt ab!", L"Es sind nicht mehr als %d Milizenausbilder in diesem Sektor erlaubt.", - L"Sind Sie sicher?", // + L"Sind Sie sicher?", // //49-50 L"Zeitraffer", //time compression @@ -4269,7 +4630,7 @@ STR16 gzLateLocalizedString[] = L"%s's Rstungsverstrkung wurde zertrmmert!", L"%s feuert %d Schsse mehr als beabsichtigt!", - L"%s feuert %d Schuss mehr als beabsichtigt!", + L"%s feuert einen Schuss mehr als beabsichtigt!", }; STR16 gzCWStrings[] = @@ -4320,6 +4681,10 @@ STR16 gzTooltipStrings[] = L"keine Weste", L"keine Hose", L"|Rstung: %s\n", + // Added - SANDRO + L"%s|Fertigkeit 1: %s\n", + L"%s|Fertigkeit 2: %s\n", + L"%s|Fertigkeit 3: %s\n", }; STR16 New113Message[] = @@ -4328,35 +4693,54 @@ STR16 New113Message[] = L"Sturm endet.", L"Regen startet.", L"Regen endet.", - L"Achtung vor Heckenschtzen...", + L"Vorsicht vor Scharfschtzen...", L"Unterdrckungsfeuer!", L"BRST", L"AUTO", L"GL", L"GL BRST", L"GL AUTO", - L"Heckenschtze!", + L"Scharfschtze!", L"Geld kann nicht aufgeteilt werden, weil ein Gegenstand am Cursor ist.", - L"Ankunft der neuen Sldner wurde in den Sektor %s verlegt, weil der vorhergesehene Sektor %s von Feinden belagert ist.", + L"Ankunft der neuen Sldner wurde in den Sektor %s verlegt, weil der geplante Sektor %s von Feinden belagert ist.", L"Gegenstand gelscht.", L"Alle Gegenstnde dieses Typs gelscht.", - L"Gegestand verkauft.", + L"Gegenstand verkauft.", L"Alle Gegenstnde dieses Typs verkauft.", - L"Sie sollten Ihre Brillen prfen!", + L"berprfen Sie die Sichtgerte Ihrer Sldner!", // Real Time Mode messages L"Sie sind bereits im Kampfmodus", L"Keine Gegner in Sicht", - L"Echtzeit Schleichmodus AUS", - L"Echtzeit Schleichmodus AN", - L"Gegner gesichtet! (Ctrl + x fr Rundenmodus)", + L"Echtzeit-Schleichmodus AUS", + L"Echtzeit-Schleichmodus AN", + //L"Gegner gesichtet! (Ctrl + x fr Rundenmodus)", + L"Gegner gesichtet!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s hatte Erfolg beim Stehlen!", + L"%s hatte nicht genug Aktionspunkte um alles zu stehlen.", + L"Mchten Sie %s vor dem Bandagieren operativ behandeln? (Sie knnen etwa %i Lebenspunkte wiederherstellen.)", + L"Mchten Sie %s operativ behandeln? (Sie knnen etwa %i Lebenspunkte wiederherstellen.)", + L"Mchten Sie zuerst Operationen durchfhren? (%i Patient(en))", + L"Mchten Sie an diesem Patienten zuerst eine Operation durchfhren?", + L"Erste Hilfe automatisch mit entsprechender operativer Behandlung durchfhren oder ohne?", + L"%s wurde erfolgreich operiert.", + L"%s ist am Torso getroffen und verliert einen Punkt maximaler Gesundheit!", + L"%s ist am Torso getroffen und verliert %d Punkte maximaler Gesundheit!", + L"%s hat einen Punkt an %s wiedergewonnen." + L"%s hat %d Punkte an %s wiedergewonnen.", + L"Ihre Spher-Fertigkeit hat Sie davor bewahrt, vom Gegner in einen Hinterhalt gelockt zu werden.", + L"Dank Ihrer Spher-Fertigkeit haben Sie erfolgreich ein Rudel Bloodcats umgangen.", + L"%s wurde in die Leiste getroffen und windet sich in Schmerzen!", + ////////////////////////////////////////////////////////////////////////////////////// }; STR16 New113HAMMessage[] = { // 0 - 5 L"%s zittert vor Angst!", - L"%s is festgenagelt!", - L"%s feuert mehr Schsse mehr als beabsichtigt!", + L"%s ist festgenagelt!", + L"%s feuert mehr Schsse als beabsichtigt!", L"Sie knnen keine Miliz in diesem Sektor ausbilden.", L"Miliz hebt %s auf.", L"Wenn Feinde im Sektor sind knnen Sie keine Miliz ausbilden!", @@ -4370,8 +4754,8 @@ STR16 New113HAMMessage[] = L"%s hat nicht gengend Weisheit um diese Anlage betreiben zu knnen.", L"%s ist schon voll besetzt.", L"Diese Anlage zu betreiben kostet $%d pro Stunde. Weitermachen?", - L"Sie haben nicht genug Geld um alle heutigen Betriebskosten zu zahlen. $%d wurden bezahlt, Sie schulden weiterhin $%d. Die Einwohner sind nicht erfreut.", - L"Sie haben nicht genug Geld um alle heutigen Betriebskosten zu zahlen. Sie schulden $%d. Die Einwohner sind nicht erfreut.", + L"Sie haben nicht genug Geld um alle heutigen Betriebskosten zu zahlen. $%d wurden bezahlt, $%d fehlen noch. Die Einwohner sind nicht erfreut.", + L"Sie haben nicht genug Geld um alle heutigen Betriebskosten zu zahlen. Es stehen $%d aus. Die Einwohner sind nicht erfreut.", // 16 - 20 L"Sie haben eine ausstehende Forderung von $%d fr Betriebskosen und kein Geld um zu bezahlen!", L"Sie haben eine ausstehende Forderung von $%d fr Betriebskosen. Dieser Anlage knnen Sie keinen Sldner zuweisen bis Sie Ihre gesamten Schulden beglichen haben.", @@ -4383,18 +4767,54 @@ STR16 New113HAMMessage[] = }; -// WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends +// WANNE: These are the email texts Speck sends when one of the 4 new 1.13 MERC mercs have levelled up // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 New113MERCMercMailTexts[] = { // Gaston: Text from Line 39 in Email.edt L"Hiermit geben wir zur Kenntnis, dass aufgrund von Gastons guten Leistungen in der Vergangenheit sein Sold erhht wurde. Ich persnlich bin darber nicht berrascht. Speck T. Kline ", // Stogie: Text from Line 43 in Email.edt - L"Bitte nehmen Sie zur Kenntnis, dass Stogies Bezge fr seine geleisteten Dienste mit sofortiger Wirkung erhht wurden in Anpassung an seine verbesserten Fhigkeiten. Speck T. Kline ", + L"Bitte nehmen Sie zur Kenntnis, dass Stogies Bezge fr seine geleisteten Dienste mit sofortiger Wirkung erhht werden in Anpassung an seine verbesserten Fhigkeiten. Speck T. Kline ", // Tex: Text from Line 45 in Email.edt - L"Bitte nehmen Sie zur Kenntnis, dass Tex aufgrund seiner Erfahrung Anspruch auf eine angemessenere Entlohnung hat. Seine Bezge wurden daher ab sofort seinem Wert entsprechend erhht. Speck T. Kline ", - // Biggens: Text from Line 49 in Email.edt - L"Zur Kenntnisnahme. Aufgrund seiner verbesserten Leistungen wurden Biggens Dienstbezge erhht. Speck T. Kline ", + L"Bitte nehmen Sie zur Kenntnis, dass Tex aufgrund seiner Erfahrung Anspruch auf eine angemessenere Entlohnung hat. Seine Bezge werden daher ab sofort seinem Wert entsprechend erhht. Speck T. Kline ", + // Biggins: Text from Line 49 in Email.edt + L"Zur Kenntnisnahme. Aufgrund seiner verbesserten Leistungen wurden Colonel Biggins' Dienstbezge erhht. Speck T. Kline ", +}; + +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"Weitergeleitet von AIM-Server: Nachricht von Victor Kolesnikov", + L"Vielen Dank fr Nachricht auf Anrufbeantworter. Nun stehe ich zur Verfgung. Allerdings bin ich whlerisch mit meine Komamandanten. Ich werde mich noch ber Sie erkundigen. V.K. ", + + // Brain + L"Weitergeleitet von AIM-Server: Nachricht von Janno Allik", + L"Jetzt wre ich bereit fr einen Auftrag. Sie wissen schon, alles zu seiner Zeit. Janno Allik ", + + // Scream + L"Weitergeleitet von AIM-Server: Nachricht von Lennart Vilde", + L"Vielen Dank fr Ihre Kontaktaufnahme. Sagen Sie mir bescheid, wenn die nchste Party steigen kann. Ab sofort erreichen Sie mich ber die AIM page. Lennart Vilde.", + + // Henning + L"Weitergeleitet von AIM-Server: Nachricht von Henning von Branitz", + L"Ihre Nachricht hat mich erreicht, vielen Dank. Falls Sie mich engagieren mchten, kontaktieren Sie mich ber die AIM Website. Bis die Tage! Henning von Branitz ", + + // Luc + L"Weitergeleitet von AIM-Server: Nachricht von Luc Fabre", + L"Ich habe Ihre Nachricht erhalten, merci. Zur Zeit knnte ich gerne einen Auftrag annehmen. Sie wissen ja, wo Sie mich erreichen. Sicher hren wir bald von einander ", + + // Laura + L"Weitergeleitet von AIM-Server: Nachricht von Dr. Laura Colin", + L"Ich gre Sie! Schn, dass Sie mir eine Nachricht hinterlassen haben. Es hrte sich interessant an. Wenn Sie wieder bei AIM vorbeischauen, wrde ich mich freuen, von Ihnen zu hren. Noch viel Erfolg! Dr. Laura Colin ", + + // Grace + L"Weitergeleitet von AIM-Server: Nachricht von Graziella Girelli", + L"Sie wollten mich kontaktieren, aber ich war leider nicht zu erreichen. Ein Familientreffen. Sie kennen das ja sicher... Jetzt hab' ich erst mal wieder genug von Familie. Jedenfalls freue ich mich, wenn Sie sich auf der AIM Site mit mir in Verbindung setzen. Ciao! ", + + // Rudolf + L"Weitergeleitet von AIM-Server: Nachricht von Rudolf Steiger", + L"Wissen Sie eigentlich, wieviel Anrufe ich jeden Tag kriege? Jeder Pisser meint, er msste hier anrufen. Aber gut, ich bin jetzt wieder da. Falls Sie einen interessanten Auftrag haben. ", }; // WANNE: These are the missing skills from the impass.edt file @@ -4402,9 +4822,34 @@ STR16 New113MERCMercMailTexts[] = STR16 MissingIMPSkillsDescriptions[] = { // Sniper - L"Scharfschtze: Sie haben Augen wie ein Falke. Dadurch knnen sie sogar auf die Flgel einer Fliege aus hunderten von Metern schieen! ", + //L"Scharfschtze: Sie haben Augen wie ein Falke. Dadurch knnen sie sogar auf die Flgel einer Fliege aus hunderten von Metern schieen! ", + //LOOTF - ersetzt mit: + L"Scharfschtze: Sie haben einen scharfen Blick und eine ruhige Hand, neben Ihrem guten Gespr fr die Windrichtung die perfekten Voraussetzungen fr das Przisionsschieen auf groe Entfernung oder eine Partie 'Jenga'. Gut so, bleiben Sie auf Distanz, so ersparen Sie sich sptere medizinische Betreuung. " + // Camouflage - L"Tarnung: Neben Ihnen schauen sogar Bsche synthetisch aus! ", + //L"Tarnung: Neben Ihnen schauen sogar Bsche synthetisch aus! ", + //LOOTF - ersetzt mit: + L"Tarnung: Sie haben das berkleistern des eigenen Gesichts mit Tarnfarbe zu einer Kunstform erhoben und erschaffen aus Zwang durchweg wundervolle Illusionen der umgebenden Flora auf Ihrem eher langweiligen Antlitz. Dadurch wirken Sie im rtlichen ALDI wie ein Wunderling, sind aber als Heckenschtze im Dschungel nahezu unsichtbar. " + + // SANDRO - new strings for new traits added + // Ranger + L"Jger: Vermutlich lesen Sie diese Nachricht auf einem tragbaren Gert von einem Dschungel eines Dritte-Welt-Lands aus und ich ahne, dass Sie dabei nicht einmal aufrecht sitzen. Sie haben eine bemerkenswerte Affinitt zu schwer passierbarem Gelnde und Ihre unermdlichen Beine tragen Sie im Handumdrehen ber Stock und Stein. Sie scheuen sich auch nicht vor Dreck und so passen Sie sich mehr als alle anderen an Ihre Umgebung an. Setzen Sie diese Qualitten als Fhrer ein um Ihr Team auf bestem Wege ans Ziel zu bringen! ", + // Gunslinger + L"Revolverheld: Ob es an ihrer handlichen Effizienz im Nahkampf liegt oder einfach daran, dass sonst niemand sonst so gut mit ihnen umgehen kann, aber Sie lieben Faustfeuerwaffen, das ist klar. Sie beweisen enormes Talent im Umgang mit Pistolen und Revolvern aller Art und in Ihrem Beruf ist das nicht das Schlechteste. Passen Sie nur auf, dass Sie neben all dem Pistolenrumwirbeln und den coolen Magazintricks auch noch an Ihre Nchsten denken, falls nach der Waffe noch jemand kommt. ", + // Squadleader + L"Zugfhrer: Normalerweise wrde ich Sie ja wie einen gewhnlichen (wenn auch den bisherig besten) Kunden behandeln, aber ich sehe ein wenig zu Ihnen auf. Die Rhetorik in Ihrem Fragebogen hat einige hier ganz schn beeindruckt und Ihre generelle Erscheinung motiviert einfach. Das enorme Wissen ber die Kunst der Kriegsfhrung, das Sie sich angeeignet haben, kommt den Ihnen unterstellten Mnnern und Frauen sicher sehr zugute. In Ihrer Nhe kann eigentlich nichts schiefgehen. ", + // Technician + L"Ingenieur: Im Rahmen der Sldnerevaluierung fhren wir einen generellen Schnelltest auf handwerkliche und technische Befhigung durch und knnen dabei offenbar nicht die ganze Palette menschlichen Knnens abdecken. Die Bilder des von Ihnen gebauten reaktorbetriebenen, dreibeinigen Rasenmhers, die Sie auf unsere Server geladen haben, fanden wir sehr beeindruckend. Wir wissen also, dass Sie mit Hufeisen und altem Garn so gut wie alles reparieren knnen, aber bitte nutzen Sie demnchst unsere Webprsenz, statt sich direkt in unser System zu hacken. ", + // Doctor + L"Arzt: rzte wie Sie braucht das Land! Es sind immer die besten, die sich in den Krieg strzen, aber womglich knnen Sie in rauchenden Trmmern mehr bewirken als in einem heruntergewirtschafteten und von fetter Dekadenz gezeichneten Gesundheitssystem. Gibt man Ihnen die Ausrstung, knnen Sie auf einem Strohbett Schusswunden operieren und Kranke heilen wie ein junger Jesus. Sollten Sie zurckkehren, es wartet immer eine Beschftigung auf Sie! ", + // Athletics + L"Lufer: Am Anfang waren wir besorgt, Sie wren der erste beinlose Kunde, der sich ins Ausland wagt, doch offenbar waren die Testwerte einfach nur auerhalb des Berechnungsrahmens, also Glckwunsch, hier sind Sie Rekordhalter. So schnell und ausdauernd wie Sie rennen, mchte ich annehmen, Sie sind mit dem Wort Marathon vertraut. Ich schlage vor, wenn es rger gibt, laufen Sie einfach! Einholen wird Sie eh niemand. ", + // Bodybuilding + L"Kraftsportler: Manche meinen ja, es ist eine abscheuliche Form der Krperkunst, aber Sie scheinen damit recht gut leben zu knnen. Durch Ihr intensives Muskeltraining fllt Ihnen das Schleppen schwerer Gertschaften garantiert leicht und so einen Typen wie Sie kriegt man vermutlich nicht einmal mit dem Brecheisen auf die Knie gezwungen. Und hey, ganz so schlimm wie die EU-Verfassung sehen Sie nun auch nicht aus. ", + // Demolitions + L"Sprengmeister: Unsere fachmnnischen Psychoanalysten meinen, Sie sind als Kind nicht oft genug oder gar nicht von Ihren Eltern daran erinnert worden, dass Messer, Gabel, Plastiksprengstoff und Licht fr kleine Kinder nicht sind. Machen Sie aus Ihrem verschobenen Weltbild einfach das Beste und nutzen Sie Ihre Begeisterung fr alles, was mit mehrfacher Schallgeschwindigkeit expandiert um sich im Training mit Granaten und Sprengstoffen hervorzutun. ", + // Scouting + L"Aufklrer: Sie sind ber die Maen aufmerksam, haben ein sehr reges Auge und einen nimmermden Geist. Ihnen entgeht nicht das geringste Detail, vor allem nicht, wenn Sie mit Ihrem alten Feldstecher unterwegs sind. Ihre Prsenz zahlt sich aus, denn durch die Anzeichen nahender Bedrohung, die nur Sie erkennen, knnen Sie Ihre Liebsten oder Ihre Kameraden vor Hinterhalten bewahren. Waren Sie mal bei der Stasi? ", }; STR16 NewInvMessage[] = @@ -4424,7 +4869,7 @@ STR16 MPServerMessage[] = { // 0 L"Initialisiere RakNet Server...", - L"Server gestartet, warte auf Client Verbindungen...", + L"Server gestartet, warte auf Client-Verbindungen...", L"Sie mssen sich nun als Client durch drcken von '2' mit dem Server verbinden.", L"Server luft bereits.", L"Starten des Servers ist fehlgeschlagen. Abbruch.", @@ -4444,8 +4889,8 @@ STR16 MPClientMessage[] = { // 0 L"Initialisiere RakNet Client...", - L"Verbinde zur ausgewhlten Server IP...", - L"Erhalte Spiel Einstellungen:", + L"Verbinde zur ausgewhlten Server-IP...", + L"Erhalte Spieleinstellungen:", L"Sie sind bereits verbunden.", L"Sie verbinden sich bereits...", // 5 @@ -4459,21 +4904,21 @@ STR16 MPClientMessage[] = L"Client #%d - '%S' ist nicht mehr bereit - Gesamt bereit = %d/%d", L"Sie sind bereit. Warte auf die anderen Clients... Drcken Sie 'OK' wenn Sie doch noch nicht bereit sind.", L"Lass uns das Gefecht beginnen!", - L"Ein Client muss laufen, um das Spiel beginnen zu knnen.", + L"Ein Client muss laufen, um das Spiel beginnen zu knnen.", //LOOTF - Hintergrund? Wenn kein Client aktiv ist, gibt es doch auch niemanden, der eine Aufforderung zum Spielstart setzt? oO // 15 L"Spiel kann nicht gestartet werden. Es sind noch keine Sldner angeheuert.", L"Erwarte Freigabe vom Server fr den Laptop...", L"Unterbrochen", L"Unterbrechung beendet", - L"Maus Raster Koordinaten:", + L"Maus-Raster-Koordinaten:", // 20 L"X: %d, Y: %d", - L"Raster Nummer: %d", + L"Raster-Nummer: %d", L"Aktion kann nur der Server durchfhren.", - L"Whle exklusive Server Aktion: ('1' - Laptop freischalten/anheuern) ('2' - Gefecht starten/Sektor laden) ('3' - Interface freischalten ) ('4' - Sldner Platzierung abschlieen) ", - L"Sektor=%s, Max. Clients=%d, Teamgre=%d, Spieltyp=%d, Gleiche Sldner=%d, Schaden Mult.=%f, Zeitl. Runden=%d, Seks/Tik=%d, Kein Bobby Ray=%d, Keine Aim/Merc Ausrstung=%d, Keine Moral=%d, Testen=%d", + L"Whle exklusive Server-Aktion: ('1' - Laptop freischalten/anheuern) ('2' - Gefecht starten/Sektor laden) ('3' - Interface freischalten ) ('4' - Sldner Platzierung abschlieen) ", + L"Sektor=%s, Max. Clients=%d, Teamgre=%d, Spieltyp=%d, Gleiche Sldner=%d, Schaden-Mult.=%f, Rundenzeitbeschr.=%d, Seks/Tik=%d, Kein Bobby Ray=%d, Keine Aim/Merc-Ausrstung=%d, Keine Moral=%d, Testen=%d", //LOOTF - Was ist Seks/Tik? Lol. Sextick. Finde gut. Englisch = Secs/Tic, aber das sagt mir auch nix. // 25 - L"Testmodus und Cheat-Funktion mit '9' ist freigeschalten.", + L"Testmodus und Cheat-Funktion mit '9' ist freigeschaltet.", L"Neue Verbindung: Client #%d - '%S'.", L"Team: %d.", L"'%s' (Client #%d - '%S') wurde gettet von '%s' (Client #%d - '%S')", @@ -4481,27 +4926,27 @@ STR16 MPClientMessage[] = // 30 L"Starte Spielzug fr Client Nummer: #1 - '%S' | #2 - '%S' | #3 - '%S' | #4 - '%S'", L"Starte Spielzug fr Client #%d", - L"Anforderung fr Echtzeit-Modus...", + L"Anfrage auf Echtzeit-Modus...", L"In Echtzeit-Modus gewechselt.", L"Fehler: Es ist ein Fehler beim Zurckwechseln in den Echtzeit-Modus aufgetreten", // 35 L"Laptop freischalten um Sldner anzuheuern? (Sind alle Clients bereits verbunden?)", - L"Server hat den Laptop freigeschalten. Sldner anheuern!", - L"Unterbrecher.", + L"Server hat den Laptop freigeschaltet. Sldner anheuern!", + L"Unterbrechung.", L"Sie knnen die Absprungzone nicht ndern, wenn Sie nur der Client und nicht zustzlich der Server sind.", L"Sie haben das Angebot zur Kampfaufgabe abgelehnt.", // 40 L"Alle Ihre Sldner wurden gettet!", - L"berwachungsmodus wurde eingeschalten.", + L"berwachungsmodus wurde eingeschaltet.", L"Sie wurden besiegt!", - L"Auf Dcher klettern ist nicht erlaubt in einem Mehrspieler Spiel.", + L"Auf Dcher klettern ist in einem Mehrspieler-Spiel nicht erlaubt.", L"Sie haben '%s' angeheuert.", // 45 L"Sie knnen den Sektor nicht ndern, wenn bereits Einkufe begonnen haben", L"Sektor gewechselt zu '%s'", - L"Client '%s' Verbindung abgebrochen, entferne Client vom Spiel.", - L"Ihre Verbindung zum Spiel wurde unterbrochen, gehen zurck zum Hauptmen.", - L"Verbindung fehlgeschlagen. Wiederverbindungsaufbau in 5 Sekunden. %i Versuche brig...", + L"Verbindung zu Client '%s' abgebrochen, entferne Client vom Spiel.", + L"Ihre Verbindung zum Spiel wurde unterbrochen, gehe zurck zum Hauptmen.", + L"Verbindung fehlgeschlagen. Wiederholung des Verbindungsaufbaus in 5 Sekunden. %i Versuche brig...", //50 L"Verbindung fehlgeschlagen, Abbruch...", L"Sie knnen das Spiel nicht beginnen, solange sich noch kein weiterer Spieler verbunden hat.", @@ -4525,31 +4970,18 @@ STR16 MPClientMessage[] = L"Kann keine Verbindung herstellen, weil Ihre Version %S unterschiedlich zur Server Version %S ist.", L"Sie haben einen gegnerischen Soldaten gettet.", L"Spiel kann nicht gestartet werden, weil es keine unterschiedlichen Teams gibt.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Willkommen zu Jagged Alliance 2 v1.13 Multiplayer", - L"Drcken Sie 'F1' um die Hilfe aufzurufen", - L"Mehrspieler Aktionen (Strategische Ansicht)", - L"* zuerst solle die Datei ja2_mp.ini angepasst werden *", - L"'1' - Starte Server", - // 5 - L"'2' - Verbindung zum Server", - L"'3' - Wenn Server, dann Laptop freischalten, ansonsten bereit fr Gefecht", - L"'4' - Beende Server und Client", - L"'5' - Anzeige der Maus Koordinaten (Taktische Ansicht)", - L"'7' - Server-Dialog um Aktionen zu bersteuern", - // 10 - L"'F2' - Weitere Hilfe anzeigen", - L"Siehe readme_mp.html fr weitere Informationen", - L"Tipps:", - L"* Alle Clients mssen eine eindeutige CLIENT_NUM (ja2_mp.ini) haben *", - L"* Gespeichertes Spiel verwirft die Bestellungen von Bobby Ray*", - // 15 - L"* Vermeide eigene Sldner in der Nhe von gegnerischen Sldnern zu platzieren *", - L"'F1' - Anzeige der primren Hilfe", + L"Die Spieleinstellungen erfordern Neues Inventar (NIV), aber NIV ist aufgrund der Spielauflsung nicht verwendbar.", + // 70 + L"Kann erhaltene Datei '%S' nicht speichern", + L"%s's Sprengstoff wurde von &s entschrft", + L"Sie haben verloren. Was fr eine Schande", // All over red rover + L"berwachungsmodus wurde ausgeschaltet", + L"Welcher Client soll vom Spiel entfernt werden:", + // 75 + L"Team #%d wurde vernichtet", + L"Client konnte nicht gestartet werden. Beendigung.", + L"Client Verbindung aufgelst und heruntergefahren.", + L"Client luft nicht.", }; STR16 gszMPEdgesText[] = @@ -4627,8 +5059,12 @@ STR16 gzMPChatboxText[] = // Translated by Scheinworld STR16 pSkillTraitBeginIMPStrings[] = { - L"Auf der nchsten Seite knnen Sie die Fertigkeit(en) angeben, durch die Sie sich auszeichnen. Mehr als zwei verschiedene Fertigkeiten oder eine, die Sie in diesem Gebiet automatisch als Experten ausweist, knnen bzw. kann nicht gewhlt werden.", - L"Whlen Sie nur eine oder gar keine Fertigkeit aus, so erhalten Sie einen Bonus in Form von zustzlichen Eigenschaftspunkten. Bitte beachten Sie, dass die Fertigkeiten: 'Elektronik' und 'Beidhndig geschickt' ber keinen Expertenstatus verfgen.", + // For old traits + L"Auf der nchsten Seite knnen Sie Ihre Fertigkeiten entsprechend Ihrer Spezialisierung als Sldner festlegen. Es knnen nicht mehr als zwei verschiedene Fertigkeiten oder eine Expertenfertigkeit gewhlt werden.", + L"Sie knnen auch nur eine oder gar keine Fertigkeit auswhlen. Sie erhalten dafr einen Bonus zu Ihren Attributpunkten als Gegenleistung. Beachten Sie, dass die Fertigkeiten 'Elektronik', 'Beidhndig geschickt' und 'Getarnt' keine Experten-Spezialisierung erhalten.", + // For new major/minor traits + L"Auf der nchsten Seite knnen Sie Ihre Fertigkeiten entsprechend Ihrer Spezialisierung festlegen. Auf der ersten Seite knnen Sie bis zu zwei Hauptfertigkeiten auswhlen, die Ihre Rolle in einem Team reprsentieren, whrend Sie auf der zweiten Seite eine Liste der mglichen Nebenfertigkeiten finden.", + L"Es knnen nicht mehr als insgesamt drei Fertigkeiten gewhlt werden, was bedeutet, dass, wenn Sie keine Hauptfertigkeiten angeben, dafr drei Nebenfertigkeiten verfgbar sind.", }; STR16 sgAttributeSelectionText[] = @@ -4637,6 +5073,10 @@ STR16 sgAttributeSelectionText[] = L"B.S.E. Eigenschaften und Fhigkeiten.", L"Bonus Pkt.:", L"Anfangs-Level", + // New strings for new traits - SANDRO + L"Im nchsten Schritt knnen Sie Ihre Attribute und Fhigkeiten festlegen. Attribute sind Gesundheit, Geschicklichkeit, Beweglichkeit, Strke und Weisheit. Sie knnen nicht weniger als %d Punkte verteilen.", + L"Der Rest sind Ihre Fhigkeiten, die Sie auch auf 0 setzen knnen.", + L"Beachten Sie, dass bestimmte Attribute auf spezifische Minimalwerte gesetzt werden, die den Voraussetzungen der Fertigkeiten entsprechen. Sie knnen diese Werte nicht weiter senken.", }; STR16 pCharacterTraitBeginIMPStrings[] = @@ -4646,9 +5086,9 @@ STR16 pCharacterTraitBeginIMPStrings[] = L"Die zweite Seite dient der Erfassung Ihrer Unzulnglichkeiten, die Sie mglicherweise haben (wir glauben, dass jeder Mensch nur eine groe Schwche hat). Bitte seien Sie dabei ehrlich, damit potentielle Arbeitgeber ber Ihr zuknftiges Einsatzfeld informiert werden knnen.", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { - L"Normal", + L"Neutral", L"Freundlich", L"Einzelgnger", L"Optimist", @@ -4658,7 +5098,25 @@ STR16 gzIMPCharacterTraitText[]= L"Bonze", L"Arschloch", L"Feigling", - L"Charaktereigenschaften", + L"B.S.E. - Persnlichkeit", +}; + +STR16 gzIMPCharacterTraitText[]= +{ + L"Neutral", + L"Umgnglich", //LOOTF - alt. "Extrovertiert" + L"Einzelgngerisch", + L"Optimistisch", + L"Selbstsicher", + L"Lernbegeistert", + L"Primitiv", + L"Aggressiv", + L"Phlegmatisch", + L"Tollkhn", + L"Pazifistisch", + L"Sadistisch", + L"Machohaft", //LOOTF - alt. "Angeberisch" + L"B.S.E. - Charakterzge", }; STR16 gzIMPColorChoosingText[] = @@ -4668,6 +5126,7 @@ STR16 gzIMPColorChoosingText[] = L"Bitte geben Sie Ihre Haar- und Hautfarbe, Ihre Statur, sowie Ihre bevorzugten Kleidungsfarben an.", L"Bitte geben Sie Ihre Haar- und Hautfarbe, sowie Ihre bevorzugten Kleidungsfarben an.", L"Eingeschaltet, wird ein Gewehr einhndig abgefeuert.", + L"\n(Warnung: Sie werden eine Menge Strke dafr bentigen.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -4804,4 +5263,499 @@ STR16 Additional113Text[]= L"Fr die korrekte Arbeit im Fenster-Modus bentigt Jagged Alliance 2 v1.13 16-bit Farbmodus.", //Jagged Alliance 2 v1.13 windowed mode requires a color depth of 16bpp or less. }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Friss Blei!", + L"Duck dich!", + L"Komm und hol mich!", + L"Du gehrst mir!", + L"Stirb!", + L"Zeit zu sterben.", + L"Vorsicht, Kugel!", + L"Komm her, du Mistkerl!", + L"Rrraaaaaah!", + L"Komm zu Papa.", + L"Du kommst unter die Erde.", + L"Du kommst hier nicht lebend raus!", + L"Aufs Maul!", + L"Du httest daheim bleiben sollen!", + L"Stirb doch!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"Wird Zeit den Ballermann aus dem Sack zu holen.", + L"berraschung.", + L"Beenden wir das schmerzhaft.", + L"Bitte lcheln!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Hier, fang!", + L"Die ist fr dich.", + L"Spiel doch damit!", + L"Hab da was fallen gelassen.", + L"Hahaha.", + L"Viel Spa damit!", + L"Hrrmmgh... uff!", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"Ich hol mir deinen Skalp.", + L"Komma her, du.", + L"Zeig mir dein Innerstes.", + L"Ich schneid dich in Streifen.", + L"Hjaaaaah!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"Wir sitzen in der Scheie! Raus hier!", + L"Komm zur Armee, haben sie gesagt... Tze!", + L"Aufklrung erfolgreich, Feind berlegen, weg hier!", + L"Ohmeingottohmeingottohmeingott.", + L"Ganze Kampfgruppe - Rckzug!", + L"Rckzug! Alle Mann Rckzug!", + L"Weg von hier, die machen uns platt!", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"Ich hab da was gehrt.", + L"Wer ist da? Ist da einer?", + L"Was war das eben?", + L"Paul, bist du das? Alles in Ordnung?", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"Alarm! Feindkontakt!", + L"Es geht los! Da sind sie!", + L"Ich seh einen von ihnen hier drben!", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Argh!", + L"Hnngh!", + L"Der sa...", + L"Au! Du Penner!", + L"Das wirst du bereuen!", + L"Sanitter!", + L"Ich hab doch gar nichts gemacht!", + +}; + + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //GERMAN diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 49975a78..366607dd 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -1,5 +1,13 @@ -#include "Utils All.h" -#include "Language Defines.h" +//#pragma setlocale("ITALIAN") +#ifdef PRECOMPILEDHEADERS + #include "Utils All.h" +#else + #include "Language Defines.h" + #if defined( ITALIAN ) + #include "text.h" + #include "Fileman.h" + #endif +#endif //suppress : warning LNK4221: no public symbols found; archive member will be inaccessible void this_is_the_ItalianText_public_symbol(void){;} @@ -102,6 +110,25 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +// TODO.Translate +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Page 1/2", //0 + L"Page 2/2", + + L"Page 1/3", + L"Page 2/3", + L"Page 3/3", + + L"Page 1/1", //5 +}; + +// by Jazz: TODO.Translate +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Development Team", @@ -304,6 +331,20 @@ CHAR16 Message[][STRING_LENGTH] = L"no full auto", L"The enemy has no more items to steal!", L"The enemy has no item in its hand!", +// TODO.Translate + L"%s's desert camouflage has worn off.", + L"%s's desert camouflage has washed off.", + + L"%s's wood camouflage has worn off.", + L"%s's wood camouflage has washed off.", + + L"%s's urban camouflage urban has worn off.", + L"%s's urban camouflage urban has washed off.", + + L"%s's snow camouflage snow has worn off.", + L"%s's snow camouflage has washed off.", + + L"You cannot attach %s to this slot.", }; @@ -456,9 +497,12 @@ STR16 pPersonnelAssignmentStrings[] = L"In transito", L"Riparare", L"Esercitarsi", - L"Allenamento Esercito", + L"Allenamento Esercito", + L"Training Mobile Militia", // TODO.Translate L"Allenatore", - L"Studente", + L"Studente", + L"Facility Staff", // TODO.Translate + L"Resting at Facility", // TODO.Translate L"Morto", L"Incap.", L"PDG", @@ -498,9 +542,12 @@ STR16 pLongAssignmentStrings[] = L"In transito", L"Ripara", L"Esercitarsi", - L"Allenatore esercito", + L"Allenatore esercito", + L"Train Mobiles", // TODO.Translate L"Allena squadra", - L"Studente", + L"Studente", + L"Staff Facility", // TODO.Translate + L"Rest at Facility", // TODO.Translate L"Morto", L"Incap.", L"PDG", @@ -744,6 +791,63 @@ STR16 pPersonnelScreenStrings[] = L"Numero ferite:", // number of times merc has been wounded L"Destrezza:", L"Nessuna abilit", + L"Achievements:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elite soldiers: %d\n", + L"Regular soldiers: %d\n", + L"Admin soldiers: %d\n", + L"Hostile groups: %d\n", + L"Creatures: %d\n", + L"Tanks: %d\n", + L"Others: %d\n", + + L"Mercs: %d\n", + L"Militia: %d\n", + L"Others: %d\n", + + L"Shots fired: %d\n", + L"Missiles fired: %d\n", + L"Grenades thrown: %d\n", + L"Knives thrown: %d\n", + L"Blade attacks: %d\n", + L"Hand to hand attacks: %d\n", + L"Successful hits: %d\n", + + L"Locks picked: %d\n", + L"Locks breached: %d\n", + L"Traps removed: %d\n", + L"Explosives detonated: %d\n", + L"Items repaired: %d\n", + L"Items combined: %d\n", + L"Items stolen: %d\n", + L"Militia trained: %d\n", + L"Mercs bandaged: %d\n", + L"Surgeries made: %d\n", + L"Persons met: %d\n", + L"Sectors discovered: %d\n", + L"Ambushes prevented: %d\n", + L"Quests handled: %d\n", + + L"Tactical battles: %d\n", + L"Autoresolve battles: %d\n", + L"Times retreated: %d\n", + L"Ambushes experienced: %d\n", + L"Hardes battle: %d Enemies\n", + + L"Shot: %d\n", + L"Stabbed: %d\n", + L"Punched: %d\n", + L"Blasted: %d\n", + L"Suffered damages in facilities: %d\n", + L"Surgeries undergoed: %d\n", + L"Facility accidents: %d\n", + + L"Character:", + L"Weakening:", }; @@ -766,12 +870,52 @@ STR16 gzMercSkillText[] = L"Coltelli", L"Sniper", L"Camuffato", - L"Camuffato (Urban)", - L"Camuffato (Desert)", - L"Camuffato (Snow)", + // SANDRO - removed this + //L"Camuffato (Urban)", + //L"Camuffato (Desert)", + //L"Camuffato (Snow)", L"(Esperto)", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"No Skill", + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + // Minor traits + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + // second names for major skills + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", + L"More...", +}; +////////////////////////////////////////////////////////// // This is pop up help text for the options that are available to the merc @@ -1078,11 +1222,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Stato:", - L"Peso (%s):", + L"Peso:", L"AP Costs", L"Git:", // Range L"Dan:", // Damage @@ -1099,35 +1243,41 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L"Attachments:", //14 // TODO.Translate L"AUTO/5:", //15 - L"Amount:", //16 + L"Remaining ammo:", //16 // TODO.Translate + + // TODO.Translate + L"Default:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (Lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"Flash Suppression", - L"Loudness (Lower is better)", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", + L"", //19 L"Bipod Modifier", + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 L"APs to Throw", L"APs to Launch", L"APs to Stab", @@ -1139,28 +1289,31 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Burst Penalty (Lower is better)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (Lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", - L"Flash Suppression", - L"Loudness (Lower is better)", + L"", //19 L"Bipod Modifier", + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 L"APs to Throw", L"APs to Launch", L"APs to Stab", @@ -1284,6 +1437,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1862,6 +2029,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"Mostra spazio |aereo", L"Mostra oggett|i", L"Mostra esercito & nemici (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1895,7 +2063,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc", @@ -1950,7 +2122,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings @@ -2295,7 +2467,7 @@ STR16 pImpButtonText[] = L"INIZIO", // begin profiling L"Personalit", // personality section L"Attributi", // personal stats/attributes section - L"Appearance", // changed from portrait - SANDRO + L"Appearance", // changed from portrait L"Voce %d", // the voice selection L"Fine", // done profiling L"Ricomincio", // start over profiling @@ -2316,12 +2488,12 @@ STR16 pImpButtonText[] = L"Immatricolazione", // the IMP site registry..when name and gender is selected L"Analisi", // analyzing your profile results L"OK", - L"Character", // Change from "Voice" - SANDRO + L"Character", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO + // These texts have been also slightly changed L"With your character traits chosen, it is time to select your skills.", L"To complete the process, select your attributes.", L"To commence actual profiling, select portrait, voice and colors.", @@ -3236,7 +3408,13 @@ STR16 CharacterInfo[] = L"Ulteriori informazioni", // Title for the additional info for the merc's bio L"Membri attivi", //20 // Title of the page L"Dispositivo opzionale:", // Displays the optional gear cost + L"gear", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"Deposito MEDICO richiesto", // If the merc required a medical deposit, this is displayed + L"Kit 1", // Text on Starting Gear Selection Button 1 // TODO.Translate + L"Kit 2", // Text on Starting Gear Selection Button 2 + L"Kit 3", // Text on Starting Gear Selection Button 3 + L"Kit 4", // Text on Starting Gear Selection Button 4 + L"Kit 5", // Text on Starting Gear Selection Button 5 }; @@ -3613,7 +3791,10 @@ STR16 zMarksMapScreenText[] = L"Non ci sono abbastanza persone che vogliono essere addestrate ora.", L"%s pieno di soldati.", L"Il mercenario ha un contratto a tempo determinato.", - L"Il contratto del mercenario non assicurato", + L"Il contratto del mercenario non assicurato", + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3679,22 +3860,25 @@ STR16 zOptionsToggleText[] = L"Mostra il cursore 3D", L"Show Chance to Hit on cursor", L"GL Burst uses Burst cursor", - L"Enemies Drop all Items", + L"Allow Enemy Taunts", // Changed from "Enemies Drop all Items" - SANDRO L"High angle Grenade launching", - L"Restrict extra Aim Levels", + L"Allow Real Time Sneaking", // Changed from "Restrict extra Aim Levels" - SANDRO L"Space selects next Squad", L"Show Item Shadow", L"Show Weapon Ranges in Tiles", L"Tracer effect for single shot", L"Rain noises", L"Allow crows", - L"Show Soldier Tooltips", // Changed from "Random I.M.P personality" - SANDRO + L"Show Soldier Tooltips", L"Auto save", L"Silent Skyrider", L"Low CPU usage", L"Enhanced Description Box", L"Forced Turn Mode", // add forced turn mode L"Stat Progress Bars", // Show progress towards stat increase // TODO.Translate + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) // TODO.Translate L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3713,13 +3897,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"Attivate questa opzione, se volete ascoltare il dialogo dei personaggi.", //Mute Confirmation L"Attivate o disattivate le conferme verbali dei personaggi.", - //Subtitles + //Subtitles L"Controllate se il testo su schermo viene visualizzato per il dialogo.", //Key to advance speech @@ -3775,22 +3961,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"When ON, the chance to hit is shown on the cursor.", L"When ON, GL burst uses burst cursor.", - L"When ON, dead enemies drop all items.", + L"When ON, enemies will occasionally comment certain actions.", // Changed from Enemies Drop All Items - SANDRO L"When ON, grenade launchers fire grenades at higher angles (|Q).", - L"When ON, aim levels beyond 4 are restricted to rifles and sniper rifles.", + L"When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"When ON, |S|p|a|c|e selects next squad automatically.", L"When ON, item shadows will be shown.", L"When ON, weapon ranges will be shown in tiles.", L"When ON, tracer effect will be shown for single shots.", L"When ON, you will hear rain noises when it is raining.", L"When ON, the crows are present in game.", - L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", // - Changed from random IMP personality - SANDRO + L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", L"When ON, game will be saved after each players turn.", L"When ON, Skyrider will not talk anymore.", L"When ON, game will run with much lower CPU usage.", L"When ON, enhanced descriptions will be shown for items and weapons.", L"When ON and enemy present, Turn Base mode persists untill sector is free (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode L"When ON, shows character progress towards gaining levels.", // TODO.Translate + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"When ON, alternate bullet graphics will be shown when you shoot.", // TODO.Translate L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3816,13 +4005,14 @@ STR16 gzGIOScreenText[] = L"Fantascientifica", L"Platinum", //Placeholder English L"Opzioni delle armi", + L"Available Arsenal", // changed by SANDRO L"Variet di armi", L"Normale", L"Livello di difficolt", L"Principiante", L"Esperto", L"Professionista", - L"Ok", + L"Start", // TODO.Translate L"Annulla", L"Difficolt extra", L"Tempo illimitato", @@ -3834,11 +4024,42 @@ STR16 gzGIOScreenText[] = L"Excellent", L"Awesome", L"INSANE", - L"Inventory System", - L"Old", - L"New", + L"Inventory / Attachments", // TODO.Translate + L"NOT USED", + L"NOT USED", L"Load MP Game", L"INITIAL GAME SETTINGS (Only the server settings take effect)", + // Added by SANDRO + L"Skill Traits", + L"Old", + L"New", + L"Max IMP Characters", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Enemies Drop All Items", + L"Off", + L"On", + L"Number of Terrorists", + L"Random", + L"All", + L"Secret Weapon Caches", + L"Random", + L"All", + L"Progress Speed of Item Choices", + L"Very Slow", + L"Slow", + L"Normal", + L"Fast", + L"Very Fast", + + // TODO.Translate + L"Old / Old", + L"New / Old", + L"New / New", }; STR16 gzMPJScreenText[] = @@ -3861,6 +4082,24 @@ STR16 gzMPJScreenText[] = L"You must enter a valid Server Port between 1 and 65535.", }; +// TODO.Translate +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { L"HOST GAME", @@ -3869,36 +4108,72 @@ STR16 gzMPHScreenText[] = L"Server Name", L"Game Type", L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"Max Players", - L"Squad Size", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", L"Merc Selection", - L"Random Mercs", + L"Merc Hiring", L"Hired by Player", - L"Starting Balance", - L"Can Hire Same Merc", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"Allow Bobby Rays", - L"Randomise Starting Edge", + L"Bobby Rays", + L"Sector Starting Edge", L"You must enter a server name", - L"Max Players must be between 2 and 4", - L"Squad size must be between 1 and 6", - L"Time of Day", - L"Time of Day must be a 24 hour time (HH:MM)", - L"Starting Cash must be a valid dollar amount (no cents)" , - L"Damage Multiplier", - L"Damage Multiplier must be a number between 0 and 5", - L"Turn Timer Multiplier", - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", L"Enable Civilians in CO-OP", - L"Use New Inventory (NIV)", - L"Enforce Maximum AI Enemies", - L"Sync. MP Clients Directory", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", L"MP Sync. Directory", L"You must enter a file transfer directory.", L"(Use '/' instead of '\\' for directory delimiters.)", L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4076,8 +4351,8 @@ STR16 pMessageStrings[] = L"Registro aggiornato.", L"Grenade Bursts use Targeting Cursor (Spread fire enabled)", L"Grenade Bursts use Trajectory Cursor (Spread fire disabled)", - L"Drop All Enabled", - L"Drop All Disabled", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"Grenade Launchers fire at standard angles", L"Grenade Launchers fire at higher angles", // forced turn mode strings @@ -4090,6 +4365,9 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved. L"Client", + + // TODO.Translate + L"You cannot use the Old Inventory and the New Attachment System at the same time.", }; @@ -4459,7 +4737,7 @@ STR16 gzLateLocalizedString[] = L"%s's armour attachment has been smashed!", L"%s fires %d more rounds than intended!", - L"%s fires %d more round than intended!", + L"%s fires one more round than intended!", }; STR16 gzCWStrings[] = @@ -4510,6 +4788,10 @@ STR16 gzTooltipStrings[] = L"no Vest", L"no Leggings", L"|Armor: %s\n", + // Added - SANDRO + L"%s|Skill 1: %s\n", + L"%s|Skill 2: %s\n", + L"%s|Skill 3: %s\n", }; STR16 New113Message[] = @@ -4538,7 +4820,26 @@ STR16 New113Message[] = L"No enemies in sight", L"Real-time sneaking OFF", L"Real-time sneaking ON", - L"Enemy spotted! (Ctrl + x to enter turn based)", + //L"Enemy spotted! (Ctrl + x to enter turn based)", + L"Enemy spotted!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s was successful on stealing!", + L"%s had not enough action points to steal all selected items.", + L"Do you want to make surgery on %s before bandaging? (You can heal about %i Health.)", + L"Do you want to make surgery on %s? (You can heal about %i Health.)", + L"Do you wish to make necessary surgeries first? (%i patient(s))", + L"Do you wish to make the surgery on this patient first?", + L"Apply first aid automatically with necessary surgeries or without them?", + L"Surgery on %s finished.", + L"%s is hit in the chest and loses a point of maximum health!", + L"%s is hit in the chest and loses %d points of maximum health!", + L"%s has regained one point of lost %s", + L"%s has regained %d points of lost %s", + L"Your scouting skills prevented you to be ambushed by the enemy!", + L"Thanks to your scouting skills you have successfuly avoided a pack of bloodcats!", + L"%s is hit to groin and falls down in pain!", + ////////////////////////////////////////////////////////////////////////////////////// }; // TODO.Translate @@ -4587,6 +4888,43 @@ STR16 New113MERCMercMailTexts[] = L"Please take note. Due to the improved performance of Biggens his fees for services rendered have undergone an increase. Speck T. Kline ", }; +// TODO.Translate +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"FW from AIM Server: Message from Victor Kolesnikov", + L"You want to talk to me? I have time.", + + // Brain + L"FW from AIM Server: Message from Janno Allik", + L"I am back. Waiting for your call.", + + // Scream + L"FW from AIM Server: Message from Lennart Vilde", + L"Sorry, I was out of office, now I am back.", + + // Henning + L"FW from AIM Server: Message from Henning von Branitz", + L"Back from business. You want my help?", + + // Luc + L"FW from AIM Server: Message from Luc Fabre", + L"Give me a call, if you are interested.", + + // Laura + L"FW from AIM Server: Message from Dr. Laura Colin", + L"I am now available.", + + // Grace + L"FW from AIM Server: Message from Graziella Girelli", + L"Got your message. If you still want me, you know what to do.", + + // Rudolf + L"FW from AIM Server: Message from Rudolf Steiger", + L"Rudolf here. Call me back.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4595,6 +4933,25 @@ STR16 MissingIMPSkillsDescriptions[] = L"Sniper: Occhi di un hawk, potete sparare le ale da un mosca ad cento yarde! ", // Camouflage L"Camuffamento: Oltre voi persino i cespugli sembrano sintetici! ", + // SANDRO - new strings for new traits added + // Ranger + L"Ranger: You are the one from Texas deserts, aren't you! ", + // Gunslinger + L"Gunslinger: With a handgun or two, you can be as lethal as the Billy Kid! ", + // Squadleader + L"Squadleader: Natural leader and boss, you are the big shot no kidding! ", + // Technician + L"Technician: Fixing stuff, removing traps, planting bombs, that's your bussiness! ", + // Doctor + L"Doctor: You can make a quick surgery with pocket-knife and chewing gum anywhere! ", + // Athletics + L"Athletics: Your speed and vitality is on top of possibilities! ", + // Bodybuilding + L"Bodybuilding: That big muscular figure which cannot be overlooked is you actually! ", + // Demolitions + L"Demolitions: You can blow up a whole city just by common home stuff! ", + // Scouting + L"Scouting: Nothing can escape your notice! ", }; STR16 NewInvMessage[] = @@ -4660,11 +5017,10 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"Grid Number: %d", L"Server only feature", - L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", + L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Timed Turns=%d, Secs/Tic=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", // 25 - L"Testing and cheat function '9' is enabled.", + L"", L"New connection: Client #%d - '%S'.", L"Team: %d.",//not used any more L"'%s' (client %d - '%S') was killed by '%s' (client %d - '%S')", @@ -4716,31 +5072,18 @@ STR16 MPClientMessage[] = L"Cannot connect because your version %S is different from the server version %S.", L"You killed an enemy soldier.", L"Cannot start the game, because all teams are the same.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Welcome to Jagged Alliance 2 v1.13 Multiplayer", - L"Press 'F1' for help", - L"Multiplayer controls (from strategy screen)", - L"* first set up ja2_mp.ini *", - L"'1' - Start server", - // 5 - L"'2' - Connect to server", - L"'3' - If server unlock laptop, set client ready for battle", - L"'4' - Quit server and client", - L"'5' - Display mouse coords (from tactical screen)", - L"'7' - Popup dialog for server override panel", - // 10 - L"'F2' - Display secondary help", - L"See readme_mp.html for further details", - L"Tips: (assuming ja2_mp.ini is set up)", - L"* Make sure all clients have unique CLIENT_NUM *", - L"* Game save doesn't record bobby rays order *", - // 15 - L"* Avoid placing opposed mercs in immediate sight *", - L"'F1' - Display primary help", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 // TODO.Translate + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; STR16 gszMPEdgesText[] = @@ -4817,16 +5160,23 @@ STR16 gzMPChatboxText[] = // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected. To achieve an expert level on a trait, simply choose only that one trait.", - L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels, and if you choose one of them only, you will have only one skill trait.", + // For old traits + L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected.", + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics, Ambidextrous and Camouflage traits cannot be achieved at expert levels.", + // For new major/minor traits + L"Next stage is about choosing your skill traits according to your proffessional specialization as a mercenary. On first page you can select up to two potential major traits, which mostly represent your main role in a team. While on second page is list of possible minor traits, which represent personal feats.", + L"No more then three choices altogeher are possible. Which means if you choose no major traits, you can then choose three minor traits. If you choose both major traits (or one enhanced), you can then choose only one minor trait...", }; - STR16 sgAttributeSelectionText[] = { - L"Please adjust your physical attributes as comapred to that of an avarage merc. You cannot raise any score above", + L"Please adjust your physical attributes according to your true abilities. You cannot raise any score above", L"I.M.P. Attributes and skills review.", L"Bonus Pts.:", L"Starting Level", + // New strings for new traits + L"On the next page you are going to specify your physical attributes and skills. As 'attributes' are called: health, dexterity, agility, strength and wisdom. Attributes cannot go lower than %d.", + L"The rest are called 'skills' and unlike attributes skills can be set to zero meaning you have absolutely no proficieny in it.", + L"All scores are set to a minimum at the beginning. Note that certain attributes are set to specific values according to skill traits you have selected. You cannot set those attributes lower than that.", }; STR16 pCharacterTraitBeginIMPStrings[] = @@ -4836,7 +5186,7 @@ STR16 pCharacterTraitBeginIMPStrings[] = L"The second page enlists possible disabilities you might have. If you suffer from any of these disabilities, choose which one (we believe that everyone has only one such disablement). Be honest, as it is important to inform potential employers of your true condition.", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"Normal", L"Friendly", @@ -4848,6 +5198,24 @@ STR16 gzIMPCharacterTraitText[]= L"Big Shot", L"Asshole", L"Coward", + L"I.M.P. Attitudes", +}; + +STR16 gzIMPCharacterTraitText[]= +{ + L"Normal", + L"Sociable", + L"Loner", + L"Optimist", + L"Assertive", + L"Intellectual", + L"Primitive", + L"Aggressive", + L"Phlegmatic", + L"Dauntless", + L"Pacifist", + L"Malicious", + L"Show-off", L"I.M.P. Character Traits", }; @@ -4858,6 +5226,7 @@ STR16 gzIMPColorChoosingText[] = L"Please select the respective colors of your skin, hair and clothing. And select what body type you have.", L"Please select the respective colors of your skin, hair and clothing.", L"Toggle this to use alternative rifle holding.", + L"\n(Caution: you will need a big strength for this.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -4996,4 +5365,498 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 modalit finestra richiede una profondit di colore di 16bpp o meno.", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Suck this!", + L"Touch this!", + L"Come get some!", + L"You're mine!", + L"Die!", + L"You scared, motherfucker?", + L"This will hurt!", + L"Come on you bastard!", + L"Come on! I don't got all day!", + L"Come to daddy!", + L"You'll be six feet under in no time!", + L"Will send ya home in a pinebox, loser!", + L"Hey, wanna play?", + L"You should have stayed home, bitch.", + L"Sucker!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"We have a barbecue here.", + L"I got a present for ya.", + L"Bam!", + L"Smile!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Catch!", + L"Here ya go!", + L"Pop goes the weasel.", + L"This one's for you.", + L"Muhehe.", + L"Catch this, swine!", + L"I like this.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"I'll get your scalp.", + L"Come to papa.", + L"Show me your guts!", + L"I'll rip you to pieces!", + L"Motherfucker!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"We're in some real shit...", + L"They said join the army. Not for this shit!", + L"I have enough.", + L"Oh my God.", + L"They ain't paying us enough for this.", + L"It's just too much for me.", + L"I'll bring some friends.", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"I heard that!", + L"Who's there?", + L"What was that?", + L"Hey! What the...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"They are here!", + L"Now the fun can start.", + L"I hoped this will never happen.", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Ouch!", + L"Ugh!", + L"This.. hurts!", + L"You fuck!", + L"You will regret.. uhh.. this.", + L"What the..!", + L"Now you have.. pissed me off.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //ITALIAN diff --git a/Utils/_Ja25ChineseText.cpp b/Utils/_Ja25ChineseText.cpp index d44a5e15..fc96a143 100644 --- a/Utils/_Ja25ChineseText.cpp +++ b/Utils/_Ja25ChineseText.cpp @@ -1,4 +1,5 @@ -#ifdef PRECOMPILEDHEADERS +//#pragma setlocale("CHINESE") +#ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25Englishtext.h" #else @@ -77,6 +78,8 @@ STR16 zNewTacticalMessages[]= L"如果你要使用编辑器的话,请选择一个战役,不要用默认战役。", }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { @@ -97,7 +100,394 @@ STR16 gzIMPSkillTraitsText[]= L"无", //"None", L"I.M.P 专属技能", //"I.M.P. Specialties", + L"(Expert)", }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + + L"None", + L"I.M.P. Major Traits", + // second names + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + + L"None", + L"I.M.P. Minor Traits", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Chance to Hit with Assault Rifles\n", + L"+%d%s Chance to Hit with SMGs\n", + L"+%d%s Chance to Hit with LMGs\n", + L"-%d%s APs needed to fire with LMGs\n", + L"-%d%s APs needed to ready light machine guns\n", + L"Auto fire/burst chance to hit penalty is reduced by %d%s\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs needed to fire grenade launchers\n", + L"-%d%s APs needed to fire rocket launchers\n", + L"+%d%s chance to hit with grenade launchers\n", + L"+%d%s chance to hit with rocket launchers\n", + L"-%d%s APs needed to fire mortar\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to raise pistols and revolvers\n", + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change state (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", + L"-%d%s APs needed to change state (stand, crouch, lie down)\n", + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors\n", + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance of other mercs in vicinity and %s himself\n", + L"+%d morale gain of other mercs in vicinity\n", + L"-%d morale loss of other mercs in vicinity\n", + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to make surgical intervention by using medical bag on wounded soldier\n", + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed of all soldiers in the same sector", + L" (max %d these bonuses per sector)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage of blades\n", + L"+%d%s damage of blunt melee weapons\n", + L"Aimed attack by any melee weapon deals +%d%s damage\n", + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if having a blade in hands\n", + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if having a blade in hands\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage of throwing blades\n", + L"+%d%s damage of throwing blades per aim click\n", + L"+%d%s chance to inflict critical hit by throwing blade if not seen or heard\n", + L"+%d critical hit by throwing blade multiplier\n", + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, swatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to train militia\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies if any\n", + L"Prevents the enemy to ambush your squad\n", + L"Prevents the bloodcats to ambush your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to train militia and instruct other mercs\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty for second hand when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25DutchText.cpp b/Utils/_Ja25DutchText.cpp index 454cad9e..1f09d656 100644 --- a/Utils/_Ja25DutchText.cpp +++ b/Utils/_Ja25DutchText.cpp @@ -1,3 +1,4 @@ +//#pragma setlocale("DUTCH") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25Dutchtext.h" @@ -43,13 +44,16 @@ STR16 zNewTacticalMessages[]= L"In order to use the editor, please select a campaign other than the default.", ///@@new }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { - L"Lock picking", - L"Hand to hand combat", + // made this more elegant + L"Lock Picking", + L"Hand to Hand", L"Electronics", - L"Night operations", + L"Night Operations", L"Throwing", L"Teaching", L"Heavy Weapons", @@ -58,12 +62,400 @@ STR16 gzIMPSkillTraitsText[]= L"Ambidextrous", L"Knifing", L"Sniper", - L"Camouflage", + L"Camouflaged", L"Martial Arts", L"None", L"I.M.P. Specialties", + L"(Expert)", + }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + + L"None", + L"I.M.P. Major Traits", + // second names + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + + L"None", + L"I.M.P. Minor Traits", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Chance to Hit with Assault Rifles\n", + L"+%d%s Chance to Hit with SMGs\n", + L"+%d%s Chance to Hit with LMGs\n", + L"-%d%s APs needed to fire with LMGs\n", + L"-%d%s APs needed to ready light machine guns\n", + L"Auto fire/burst chance to hit penalty is reduced by %d%s\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs needed to fire grenade launchers\n", + L"-%d%s APs needed to fire rocket launchers\n", + L"+%d%s chance to hit with grenade launchers\n", + L"+%d%s chance to hit with rocket launchers\n", + L"-%d%s APs needed to fire mortar\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to raise pistols and revolvers\n", + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change state (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", + L"-%d%s APs needed to change state (stand, crouch, lie down)\n", + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors\n", + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance of other mercs in vicinity and %s himself\n", + L"+%d morale gain of other mercs in vicinity\n", + L"-%d morale loss of other mercs in vicinity\n", + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to make surgical intervention by using medical bag on wounded soldier\n", + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed of all soldiers in the same sector", + L" (max %d these bonuses per sector)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage of blades\n", + L"+%d%s damage of blunt melee weapons\n", + L"Aimed attack by any melee weapon deals +%d%s damage\n", + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if having a blade in hands\n", + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if having a blade in hands\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage of throwing blades\n", + L"+%d%s damage of throwing blades per aim click\n", + L"+%d%s chance to inflict critical hit by throwing blade if not seen or heard\n", + L"+%d critical hit by throwing blade multiplier\n", + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, swatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to train militia\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies if any\n", + L"Prevents the enemy to ambush your squad\n", + L"Prevents the bloodcats to ambush your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to train militia and instruct other mercs\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty for second hand when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25DutchText.h b/Utils/_Ja25DutchText.h index c621b858..5badfb39 100644 --- a/Utils/_Ja25DutchText.h +++ b/Utils/_Ja25DutchText.h @@ -32,6 +32,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25EnglishText.cpp b/Utils/_Ja25EnglishText.cpp index 5c8453bb..8d47a040 100644 --- a/Utils/_Ja25EnglishText.cpp +++ b/Utils/_Ja25EnglishText.cpp @@ -1,3 +1,4 @@ +//#pragma setlocale("ENGLISH") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25Englishtext.h" @@ -43,13 +44,16 @@ STR16 zNewTacticalMessages[]= L"In order to use the editor, please select a campaign other than the default.", ///@@new }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { - L"Lock picking", - L"Hand to hand combat", + // made this more elegant + L"Lock Picking", + L"Hand to Hand", L"Electronics", - L"Night operations", + L"Night Operations", L"Throwing", L"Teaching", L"Heavy Weapons", @@ -58,12 +62,400 @@ STR16 gzIMPSkillTraitsText[]= L"Ambidextrous", L"Knifing", L"Sniper", - L"Camouflage", + L"Camouflaged", L"Martial Arts", L"None", L"I.M.P. Specialties", + L"(Expert)", + }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + + L"None", + L"I.M.P. Major Traits", + // second names + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + + L"None", + L"I.M.P. Minor Traits", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Chance to Hit with Assault Rifles\n", + L"+%d%s Chance to Hit with SMGs\n", + L"+%d%s Chance to Hit with LMGs\n", + L"-%d%s APs needed to fire with LMGs on autofire or burst mode\n", + L"-%d%s APs needed to ready light machine guns\n", + L"Auto fire/burst chance to hit penalty is reduced by %d%s\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs needed to fire grenade launchers\n", + L"-%d%s APs needed to fire rocket launchers\n", + L"+%d%s chance to hit with grenade launchers\n", + L"+%d%s chance to hit with rocket launchers\n", + L"-%d%s APs needed to fire mortar\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to ready pistols and revolvers\n", // MINTY - "raise" changed to "ready" + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change stance (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", // MINTY - "state" changed to "stance" + L"-%d%s APs needed to change stance (stand, crouch, lie down)\n", // MINTY - "state" changed to "stance" + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors in\n", // MINTY - Changed to "kick doors in" + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance for other mercs in the vicinity and %s himself\n", // MINTY - Changed "of" to "for" + L"+%d morale gain for other mercs in the vicinity\n", // MINTY - Changed "of" to "for" + L"-%d morale loss for other mercs in the vicinity\n", // MINTY - Changed "of" to "for" + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to perform surgical intervention by using medical bag on wounded soldier\n", // MINTY - "make" changed to "perform" + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed for all soldiers in the same sector", // MINTY - Changed "of" to "for" + L" (max %d of these bonuses per sector stack)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage with blades\n", // MINTY - Changed "of" to "with" + L"+%d%s damage with blunt melee weapons\n", // MINTY - Changed "of" to "with" + L"Aimed attack with any melee weapon deals +%d%s damage\n", // MINTY - Changed "by" to "with" + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if holding a blade\n", // MINTY - "having a blade in hands" changed to "holding a blade" + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if holding a blade\n", // MINTY - "having a blade in hands" changed to "holding a blade" + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage with throwing blades\n", // MINTY - Changed "of" to "with" + L"+%d%s damage with throwing blades per aim click\n", // MINTY - Changed "of" to "with" + L"+%d%s chance to inflict critical hit with throwing blade if not seen or heard\n", // MINTY - Changed "by" to "with" + L"+%d critical hit with throwing blade multiplier\n", // MINTY - Changed "by" to "with" + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in the dark\n", + L"+%d to general effective hearing range\n", + L"+%d additional hearing range in the dark\n", // MINTY - Changed "effective hearing range in dark on top" to "additional hearing range in the dark" + L"+%d to interrupts modifier in the dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, squatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to militia training speed\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies, if any\n", + L"Prevents enemy ambushes on your squad\n", + L"Prevents bloodcat ambushes on your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in the dark\n", + L"+%d to general effective hearing range\n", + L"+%d extra hearing range in the dark\n", + L"+%d to interrupts modifier in the dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to militia training and other mercs instructing speed\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25EnglishText.h b/Utils/_Ja25EnglishText.h index 96c204fd..b0175964 100644 --- a/Utils/_Ja25EnglishText.h +++ b/Utils/_Ja25EnglishText.h @@ -1,4 +1,4 @@ - #ifndef _JA25ENGLISHTEXT__H_ +#ifndef _JA25ENGLISHTEXT__H_ #define _JA25ENGLISHTEXT__H_ @@ -33,6 +33,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25FrenchText.cpp b/Utils/_Ja25FrenchText.cpp index 17ce38c0..b841bcbc 100644 --- a/Utils/_Ja25FrenchText.cpp +++ b/Utils/_Ja25FrenchText.cpp @@ -1,4 +1,4 @@ -#pragma setlocale("FRENCH") +//#pragma setlocale("FRENCH") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25Frenchtext.h" @@ -44,6 +44,8 @@ STR16 zNewTacticalMessages[]= L"Pour pouvoir utiliser l'diteur, veuillez choisir une autre campagne que celle par defaut.", ///@@new }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { @@ -64,7 +66,395 @@ STR16 gzIMPSkillTraitsText[]= L"aucune", L"Spcialts I.M.P.", + L"(Expert)", + }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + + L"None", + L"I.M.P. Major Traits", + // second names + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + + L"None", + L"I.M.P. Minor Traits", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Chance to Hit with Assault Rifles\n", + L"+%d%s Chance to Hit with SMGs\n", + L"+%d%s Chance to Hit with LMGs\n", + L"-%d%s APs needed to fire with LMGs\n", + L"-%d%s APs needed to ready light machine guns\n", + L"Auto fire/burst chance to hit penalty is reduced by %d%s\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs needed to fire grenade launchers\n", + L"-%d%s APs needed to fire rocket launchers\n", + L"+%d%s chance to hit with grenade launchers\n", + L"+%d%s chance to hit with rocket launchers\n", + L"-%d%s APs needed to fire mortar\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to raise pistols and revolvers\n", + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change state (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", + L"-%d%s APs needed to change state (stand, crouch, lie down)\n", + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors\n", + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance of other mercs in vicinity and %s himself\n", + L"+%d morale gain of other mercs in vicinity\n", + L"-%d morale loss of other mercs in vicinity\n", + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to make surgical intervention by using medical bag on wounded soldier\n", + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed of all soldiers in the same sector", + L" (max %d these bonuses per sector)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage of blades\n", + L"+%d%s damage of blunt melee weapons\n", + L"Aimed attack by any melee weapon deals +%d%s damage\n", + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if having a blade in hands\n", + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if having a blade in hands\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage of throwing blades\n", + L"+%d%s damage of throwing blades per aim click\n", + L"+%d%s chance to inflict critical hit by throwing blade if not seen or heard\n", + L"+%d critical hit by throwing blade multiplier\n", + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, swatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to train militia\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies if any\n", + L"Prevents the enemy to ambush your squad\n", + L"Prevents the bloodcats to ambush your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to train militia and instruct other mercs\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty for second hand when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25FrenchText.h b/Utils/_Ja25FrenchText.h index ad44a04c..9f4599a0 100644 --- a/Utils/_Ja25FrenchText.h +++ b/Utils/_Ja25FrenchText.h @@ -32,6 +32,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25GermanText.cpp b/Utils/_Ja25GermanText.cpp index 3c54412c..098a736a 100644 --- a/Utils/_Ja25GermanText.cpp +++ b/Utils/_Ja25GermanText.cpp @@ -1,11 +1,13 @@ -#pragma setlocale("GERMAN") +//#pragma setlocale("GERMAN") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25GermanText.h" #else #include "Language Defines.h" - #include "text.h" - #include "Fileman.h" + #ifdef GERMAN + #include "text.h" + #include "Fileman.h" + #endif #endif //suppress : warning LNK4221: no public symbols found; archive member will be inaccessible @@ -42,6 +44,8 @@ STR16 zNewTacticalMessages[]= L"Um den Editor zu benutzen, mssen Sie eine andere als die Standardkampgane auswhlen.", }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { @@ -52,7 +56,7 @@ STR16 gzIMPSkillTraitsText[]= L"Werfen", L"Lehren", L"Schwere Waffen", - L"Automatische Waffen", + L"Autom. Waffen", L"Schleichen", L"Beidhndig geschickt", L"Messer", @@ -61,13 +65,402 @@ STR16 gzIMPSkillTraitsText[]= L"Kampfsport", L"Keine", - L"B.S.E. Persnlichkeiten", + L"B.S.E. - Spezialisierungen", + L"(Experte)", }; +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"MG-Schtze", //LOOTF - Alle Namen sehr gewagt, aber wenigstens volldeutsch. + L"Grenadier" , + L"Przisionsschtze", + L"Pfadfinder", + L"Pistolenschtze", //Option: Pistolenschtze + L"Faustkmpfer", + L"Gruppenfhrer", //GrpFhr und ZgFhr sind scheie, aber mir fllt ohne Dienstgrade nscht ein + L"Mechaniker", //Option: Techniker + L"Sanitter", //Option: Rettungsassistent + + L"Nichts", + L"B.S.E. Hauptfertigkeiten", + + // second names + L"MG-Veteran", //Option "MG-Veteran"? + L"Artillerist", + L"Scharfschtze", + L"Jger", //"Ranger" ist toll, aber nicht wirklich deutsch + L"Revolverheld", + L"Kampfsportler", //Kung-Fu-Typ ohne Nennung von Kung-Fu oder Wu-Shu oder derart Zeug, PS: KampfSPORTLER ist kacke + L"Zugfhrer", + L"Ingenieur", + L"Arzt", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Beidhnder", // alt. "Beidhndig geschickt" + L"Messerkmpfer", // alt. "Hieb- und Stichwaffen" //gesucht: Begriff fr Nahkampfwaffenkmpfer + L"Messerwerfer", // alt. "Wurfwaffen" + L"Nachtmensch", // alt. "Nachteinsatz" + L"Schleicher", // alt. "Schleichen" + L"Lufer", // alt. "Athletisch" + L"Kraftsportler", // alt. "Bodybuilding" + L"Sprengmeister", // alt. "Kampfmittel" + L"Ausbilder", // alt. "Lehren" + L"Aufklrer", // alt. "Sphen" + + L"Keine", + L"B.S.E. Nebenfertigkeiten", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Trefferchance mit Sturmgewehren\n", + L"+%d%s Trefferchance mit Maschinenpistolen\n", + L"+%d%s Trefferchance mit Maschinengewehren\n", + L"-%d%s APs bentigt fr MG-Feuerste (Burst/Auto) abzugeben\n", + L"-%d%s APs bentigt um Maschinengewehre auszurichten\n", + L"Trefferratenabzug bei Feuersten reduziert um %d%s\n", + L"Reduzierte Chance bei Feuersten ungewollt mehr Schsse abzugeben\n", + + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs bentigt um Granatwerfer abzufeuern\n", + L"-%d%s APs bentigt um Raketenwerfer abzufeuern\n", + L"+%d%s Trefferchance mit Granatwerfern\n", + L"+%d%s Trefferchance mit Raketenwerfern\n", + L"-%d%s APs bentigt fr den Abschuss von Mrsergranaten\n", + L"Trefferchancenreduktion fr Mrser gesenkt um %d%s\n", + L"+%d%s Schaden an Panzern mit schweren Waffen, Granaten und Bomben\n", + L"+%d%s schaden an allen anderen Zielen mit schweren Waffen\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Trefferchance mit Gewehren\n", + L"+%d%s Trefferchance mit Scharfschtzengewehren\n", + L"-%d%s effektive Reichweite zum Ziel mit allen Waffen\n", + L"+%d%s Zielbonus pro Zielerfassungs-Klick (auer fr Faustfeuerwaffen)\n", + L"+%d%s Schaden pro Schuss", + L" plus", + L" fr jeden Zielerfassungs-Klick", + L" nach dem ersten", + L" nach dem zweiten", + L" nach dem dritten", + L" nach dem vierten", + L" nach dem fnften", + L" nach dem sechsten", + L" nach dem siebenten", + L"-%d%s APs bentigt um ein Repetiergewehr erneut fertigzuladen.\n", + L"Gibt einen weiteren Ziel-Klick fr gewehrartige Waffen\n", + L"Gibt weitere %d Ziel-Klicks fr gewehrartige Waffen\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Trefferchance mit Gewehren\n", + L"+%d%s Trefferchance mit Schrotflinten\n", + L"-%d%s APs gebraucht um Schrotflinten zu repetieren\n", + L"+%d%s Marschgeschwindigkeit der Gruppe zwischen Sektoren zu Fu\n", + L"+%d%s Marschgeschwindigkeit der Gruppe zwischen Sektoren bei Benutzung von Fahrzeugen (auer dem Helikopter)\n", + L"-%d%s weniger Energieverlust beim Reisen zwischen Sektoren\n", + L"-%d%s Einfluss durch schlechtes Wetter\n", + L"+%d%s Tarnungs-Effektivitt\n", + L"-%d%s Abnutzung von Gesichtstarnung durch Wasser oder Zeit\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs bentigt um mit Pistolen oder Revolvern zu schieen\n", + L"+%d%s effektive Reichweite mit Pistolen und Revolvern\n", + L"+%d%s Trefferchance mit mit Pistolen und Revolvern\n", + L"+%d%s Trefferchance mit vollautomatischen Pistolen", + L" (nur bei Einzelfeuer)", + L"+%d%s Zielbonus pro Klick mit Pistolen, vollautomatischen Pistolen und Revolvern\n", + L"-%d%s APs bentigt um Pistolen und Revolver in Vorhalte zu bringe\n", + L"-%d%s APs bentigt um Pistolen, vollautomatische Pistolen und Revolver nachzuladen\n", + L"Gibt fr Pistolen, vollautomatische Pistolen und Revolver einen weiteren Zielklick\n", + L"%d weiteren Zielklick fr Pistolen, vollautomatische Pistolen und Revolver\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP-Kosten fr den Faustkampf (bloe Hnde oder mit Schlagring)\n", + L"+%d%s Trefferchance bei Nahkampfangriffen mit bloen Hnden\n", + L"+%d%s Trefferchance bei Nahkampfangriffen mit dem Schlagring\n", + L"+%d%s Schaden im Faustkampf (bloe Hnde oder mit Schlagring)\n", + L"+%d%s Ausdauerschaden im Faustkampf (bloe Hnde oder mit Schlagring)\n", + L"Ein im Nahkampf niedergestreckter Gegner braucht etwas lnger um sich zu erholen\n", + L"Ein im Nahkampf niedergestreckter Gegner braucht lnger um sich zu erholen\n", + L"Ein im Nahkampf niedergestreckter Gegner braucht deutlich lnger um sich zu erholen\n", + L"Ein im Nahkampf niedergestreckter Gegner braucht viel lnger um sich zu erholen\n", + L"Ein im Nahkampf niedergestreckter Gegner braucht sehr viel lnger um sich zu erholen\n", + L"Ein im Nahkampf niedergestreckter Gegner schlft wie ein Baby bevor er sich erholt\n", + L"Ein im Nahkampf niedergestreckter Gegner steht vermutlich erstmal gar nicht mehr auf\n", + L"Ein gezielter Schlag richtet +%d%s mehr Schaden an\n", + L"Ein gezielter Tornadotritt richtet +%d%s mehr Schaden an\n", + L"+%d%s Chance, Schlgen und Tritten auszuweichen\n", + L"Dazu +%d%s Chance mit freien Hnden", + L" oder nur mit Schlagring", + L" (+%d%s mit Schlagring)", + L"+Dazu %d%s Chance, Schlgen und Tritten mit ausgerstetem Schlagring auszuweichen\n", + L"+%d%s Chance einem Angriff mit einer beliebigen Nahkampfwaffe auszuweichen\n", + L"-%d%s APs bentigt um einen Gegner zu entwaffnen\n", + L"-%d%s APs bentigt um die Krperhaltung zu ndern, sich umzudrehen, auf oder von Dchern zu klettern und Hindernisse zu berspringen\n", + L"-%d%s APs bentigt um die Krperhaltung zu ndern (stehen, ducken, liegen)\n", + L"-%d%s APs bentigt um sich umzudrehen\n", + L"-%d%s APs bentigt um auf oder von Dchern zu klettern und Hindernisse zu berspringen\n", + L"+%d%s Chance eine Tr erfolgreich einzutreten\n", + L"Sie erhalten besondere Kung-Fu-Animationen fr den Nahkampf\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs pro Runde fr die umgebenden Sldner innerhalb des Einflussbereichs\n", + L"+%d effektiven Erfahrungslevel fr umgebende Sldner im Einflussbereich mit weniger Erfahrungsgrad als der %s\n", + L"+%d auf den Erfahrungslevel beim Berechnen des Gruppeneffekts auf Unterdrckungsfeuer\n", + L"+%d%s Resistenz gegen Unterdrckungsfeuer fr jeden Sldner im Einflussbereich, auch den %s\n", + L"+%d Moralgewinn fr umgebende Sldner innerhalb des Einflussbereichs\n", + L"-%d Moralverlust fr umgebende Sldner innerhalb des Einflussbereichs\n", + L"Der Einflussbereich hat einen Radius von %d Feldern", + L" (%d Felder mit Kopfhrer-Funkgert)", + L"(Maximal auf einen Sldner wirkende Boni: %d )\n", + L"+%d%s Resistenz gegen Angst fr %s\n", + L"Nachteil: %dx Moralverlust bei Tod des %ss fr alle anderen Sldner\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s schnellere Reparaturen\n", + L"+%d%s mehr Erfolg beim Knacken normaler und elektronischer Schlsser\n", + L"+%d%s mehr Erfolg beim Entschrfen elektronischer Fallen\n", + L"+%d%s mehr Erfolg beim Anbringen besonderer Gegenstnde und Verbinden von Gertschaften\n", + L"+%d%s mehr Erfolg beim Beheben von Waffenstrungen im Gefecht\n", + L"Der Malus beim Reparieren elektronischer Gegenstnde wird um %d%s gesenkt\n", + L"Erhhte Chance, Fallen und Minen zu entdecken (+%d zum Erkennungslevel)\n", + L"+%d%s Trefferchance des Roboters, wenn vom %s gesteuert\n", + L"Der %s kann den Roboter reparieren\n", + L"%d%s Reduzierung des Geschwindigkeitsabzugs beim Reparieren des Roboters\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Kann chirurgisch operieren (Benutzung eines Arztkoffers auf einen verletzten Sldner)\n", + L"Die Operation stellt sofort %d%s der verlorenen Lebenspunkte wieder her.", + L" (Dieser Vorgang verbraucht einen Groteil des Arztkoffers.)", + L"Kann verlorene Attributpunkte (von kritischen Treffern) durch", + L" eine Operation oder", + L" den Auftrag 'Doktor' wiederherstellen.\n", + L"+%d%s bessere Heilungsrate beim Einsatz am Patienten\n", + L"+%d%s schnelleres Anlegen von Wundverbnden\n", + L"+%d%s natrliche Regenerationsrate aller Sldner im selben Sektor", + L" (maximal %d Instanzen dieses Bonus pro Sektor)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"Keine Boni", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Die Ungenauigkeit beim Schieen mit zwei Waffen wird um %d%s reduziert\n", + L"+%d%s schnelleres Nachladen mit Magazinen\n", + L"+%d%s schnelleres Nachladen mit einzelnen Patronen\n", + L"-%d%s APs bentigt um Gegenstnde aufzuheben\n", + L"-%d%s APs bentigt fr die Handhabe des Rucksacks\n", + L"-%d%s APs bentigt um mit Tren zu interagieren\n", + L"-%d%s APs bentigt um Bomben und Minen zu legen oder zu entschrfen\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs bentigt fr den Angriff mit Klingenwaffen\n", + L"+%d%s Trefferchance mit Klingenwaffen\n", + L"+%d%s Trefferchance mit Schlagwaffen\n", + L"+%d%s Schaden mit Klingenwaffen\n", + L"+%d%s Schaden mit Schlagwaffen\n", + L"Ein gezielter Hieb mit einer Nahkampfwaffe richtet %d%s mehr Schaden an\n", + L"+%d%s Chance Angriffen durch Klingenwaffen auszuweichen\n", + L"Dazu +%d%s Chance Klingenwaffen auszuweichen wenn man selber eine in der Hand hat\n", + L"+%d%s Chance Angriffen durch Schlagwaffen auszuweichen\n", + L"Dazu +%d%s Chance Schlagwaffen auszuweichen wenn man eine Klingenwaffe fhrt\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s Basis-APs bentigt fr den Angriff mit Wurfwaffen\n", + L"+%d%s maximale Reichweite beim Einsatz von Wurfwaffen\n", + L"+%d%s Trefferchance mit Wurfwaffen\n", + L"+%d%s Trefferchance mit Wurfwaffen fr jeden Ziel-Klick\n", + L"+%d%s Schaden geworfener Klingen\n", + L"+%d%s Schaden geworfener Klingen fr jeden Ziel-Klick\n", + L"+%d%s Chance auf kritischen Treffer beim Angriff mit Wurfwaffen, falls das Ziel den Werfer nicht bemerkt hat\n", + L"+%d Multiplikator fr kritische Treffer durch Wurfwaffen\n", + L"Gibt einen weiteren Zielklick beim Einsatz von Wurfwaffen\n", + L"Gibt %d weitere Zielklicks beim Einsatz von Wurfwaffen\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d zur effektiven Sichtweite im Dunkeln\n", + L"+%d zum allgemeinen effektiven Hrweite\n", + L"Dazu +%d zum effektive Hrweite in der Dunkelheit\n", + L"+%d zum Unterbrechungs-Modifikator in der Dunkelheit\n", + L"-%d weniger Schlafbedarf\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs zum Schleichen ntig\n", + L"+%d%s Chance beim Schleichen kein Gerusch zu erzeugen zu sein\n", + L"+%d%s Chance, 'unsichtbar' zu sein wenn man sich nicht verrt (schleichen)\n", + L"Der Abzug der berechneten Sichtdeckung beim Bewegen ist %d%s geringer\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs bentigt fr Bewegung (rennen, aufrecht oder geduckt gehen, gleiten, schwimmen, usw.)\n", + L"-%d%s weniger Ausdauerverbrauch fr fr Bewegung, Dachklettern, Hindernisse berwinden, usw.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Hat eine Schadensresistenz von %d%s\n", + L"+%d%s effektive Strke fr das Berechnen der maximalen Traglast\n", + L"%d%s weniger Energieverlust beim Erleiden von Schlgen und Tritten\n", + L"Fllt bei Beintreffern weniger leicht um durch um %d%s erhhte Schadenstoleranz\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs bentigt um Handgranaten und hnliches zu werfen\n", + L"+%d%s mehr Reichweite beim Werfen von Handgranaten und hnlichem\n", + L"+%d%s mehr Wurfgenauigkeit beim Einsatz von Handgranaten und hnlichem\n", + L"Gelegte Bomben und Minen sind +%d%s effizienter\n", + L"+%d%s mehr Erfolg beim Anbringen von Zndern an Sprengstoff\n", + L"+%d%s mehr Erfolg beim Schrfen und Entschrfen von Bomben\n", + L"Verringerte Chance, dass der Gegner eigene Bomben und Minen entdeckt (%d zum Bombenlevel)\n", + L"Erhhter Erfolg beim Aufbrechen einer Tr mit einer Durchbruchladung (Schaden multipliziert mit %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"Bei der Ausbildung von Milizen +%d%s schneller\n", + L"Bei der Ausbildung von Milizen +%d%s Bonus zur effektiven Fhrungsfhigkeit\n", + L"Beim Ausbilden von Sldnern +%d%s schneller\n", + L"Beim Ausbilden von Sldnern +d% zum effektiven Fhigkeitslevel des Ausbilders\n", + L"Beim eigenstndigen Lernen +%d%s schneller\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d zur effektiven Sichtweite mit Zielfernrohren an Waffen\n", + L"+%d zur effektiven Sichtweite mit Doppelfernrohren und losen Zielfernrohren\n", + L"-%d Tunnelblick mit Doppelfernrohren und losen Zielfernrohren\n", + L"Auf der Weltkarte wird in angrenzenden Sektoren die genaue Feindstrke (Anzahl) bestimmt\n", + L"Auf der Weltkarte wird in angrenzenden Sektoren die Prsenz von vorhandenem Feind enthllt\n", + L"Verhindert, dass der Feind die Gruppe in den Hinterhalt lockt\n", + L"Verhindert, das Umzingeln der Gruppe durch Bloodcats\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"Keine Boni", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s Bonus zum Schlsser Knacken\n", // 0 + L"+%d%s Trefferchance im Faustkampf\n", + L"+%d%s Schaden im Faustkampf\n", + L"+%d%s Chance Schlgen auszuweichen\n", + L"Bei der Reparatur und Bedienung von Elektrotechnik\n(Schlsser, Fallen, Fernznder, Roboter...) kein Abzug\n", + L"+%d zur effektiven Sichtweite im Dunkeln\n", + L"+%d zur allgemeinen effektiven Hrweite\n", + L"Dazu +%d zur effektiven Hrweite in der Dunkelheit\n", + L"+%d zum Unterbrechungsmodifikator in der Dunkelheit\n", + L"-%d weniger Schlafbedarf\n", + L"+%d%s maximale Reichweite beim Werfen\n", // 10 + L"+%d%s Trefferchance beim Werfen\n", + L"+%d%s Chance auf sofortige Ttung mit Wurfmesser wenn unbemerkt\n", + L"+%d%s Bonus zum Trainieren von Milizen und anderen Sldnern\n", + L"+%d%s effektive Fhrungsfertigkeit beim Ausbilden von Milizen\n", + L"+%d%s Trefferchance mit Raketen-/Granatwerfern und Mrsern\n", + L"Trefferchancenabzug bei Dauerfeuer und Feuersto wird durch %d geteilt\n", + L"Das Verschieen von zu viel Munition bei Dauerfeuer wird unwahrscheinlicher\n", + L"+%d%s Chance sich leise zu bewegen\n", + L"+%d%s stealth (unsichtbar sein, wenn man sich nicht verrt)\n", + L"Beim Schieen mit zwei Waffen mit jeder so przise wie mit nur einer\n", // 20 + L"+%d%s Trefferchance mit Stichwaffen\n", + L"+%d%s Chance, Stichwaffen auszuweichen, wenn man selber eine fhrt\n", + L"+%d%s Chance, Stichwaffen auszuweichen, wenn man etwas anderes in der Hand hat\n", + L"+%d%s Chance Schlgen auszuweichen, wenn man eine Stichwaffe hlt\n", + L"-%d%s effektive Reichweite zum Ziel mit allen Waffen\n", + L"+%d%s Bonus zum Zielen pro Mausklick\n", + L"Immer vollstndig getarnt sein\n", + L"+%d%s Trefferchance im Faustkampf\n", + L"+%d%s Schaden im Faustkampf\n", + L"+%d%s Chance, Schlge mit leeren Hnden zu blocken\n", // 30 + L"+%d%s Chance, Schlge mit etwas in der Hand zu blocken\n", + L"+%d%s Chance, Stichwaffenangriffen auszuweichen\n", + L"Kann angeschlagenen Gegnern einen Tornadotritt verpassen, der doppelten Schaden anrichtet\n", + L"Sie erhalten besondere Animationen fr den Faustkampf (etwas fernstlicher)\n", + L"Keine Boni", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"V: Keine Vorteile.\nN: Keine Nachteile.", + L"V: Hat eine erhhte Leistung im Verbund mit anderen Sldnern.\nN: Erhlt keinen Moralzuwachs, wenn niemand in der Nhe ist.", + L"V: Hat eine erhhte Leistung, wenn niemand in der Nhe ist.\nN: Erhlt keinen Moralzuwachs im Verbund mit anderen Sldnern.", + L"V: Seine Moral sinkt etwas langsamer und steigt schneller.\nN: Hat weniger Chance, Fallen und Minen zu entdecken.", + L"V: Erhlt Boni beim Ausbilden von Miliz und kann besser mit Menschen reden.\nN: Erhlt keinen Moralzuwachs fr Aktionen anderer Sldner.", + L"V: Lernt etwas schneller in Schulung durch sich selbst oder andere.\nN: Hat weniger Unterdrckungs- und Angstresistenz.", + L"V: Verbraucht etwas weniger Energie, auer bei Aufgaben in Medizin, Technik oder anspruchsvollen Ausbildung.\nN: Weisheit, Fhrungskraft, Sprengstoff-, Mechanik- und Medizinkenntnisse entwickeln sich bei ihm langsamer.", + L"V: Hat eine leicht erhhte Trefferchance bei Feuersten und richtet etwas mehr Schaden im Nahkampf an.\n Erhlt ein wenig mehr Moralzuwachs beim Tten.\nN: Ist schlechter bei Aufgaben, die Geduld erfordern, wie Reparatur, Schlossknacken, Fallen Entschrfen, Patientenbetreuung und Ausbildung von Miliz.", + L"V: Erhlt Boni fr Aufgaben mit Geduldsanspruch wie Reparatur, Schlossknacken, Fallen Entschrfen, Patientenbetreuung und Ausbildung von Miliz.\nN: Erhlt weniger oft Unterbrechungen im Kampf.", + L"V: Erhhte Resistenz gegenber Unterdrckungsfeuer und Angst.\n Verliert weniger Moral beim Erleiden von Schaden oder dem Tod von Kameraden.\nN: Wird leichter getroffen, und kann seltener Feindfeuer durch schnelle Bewegung ausweichen.", + L"V: Erhlt Moralzuwachs fr Ttigkeiten auerhalb des Kmpfens (auer der Ausbildung von Milizkrften).\nN: Erhlt keinerlei Moral beim Tten.", + L"V: Hat eine hhere Chance, Statusschden anzurichten und kann besonders fiese Wunden austeilen.\n Erhlt mehr Moral fr erfolgreiche Statusschden.\nN: Kann schlechter mit Leuten reden und seine Moral sinkt schneller, wenn er nicht kmpft.", + L"V: Hat eine erhhte Leistung wenn Sldner des anderen Geschlechts in der Nhe sind.\nN: Die Moral anderer naher Sldner des gleichen Geschlechts steigt langsamer.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"Keine Auswirkungen.", + L"Hat Atemnot und allgemein schlechtere Leistung in tropischen und Wstensektoren.", + L"Kann Panikattacken erleiden, wenn in gewissen Situationen auf sich gestellt.", + L"Zeigt geringere Leistung unter Tage (in Hhlen und Kellern).", + L"Kann beim Versuch zu schwimmen leicht ertrinken.", + L"Ertrgt den Anblick groer Insekten nicht und\nzeigt verringerte Leistung in tropischen Sektoren.", + L"Vergisst manchmal seine Befehle und verliert dadurch im Kampf einen Teil seiner APs.", + L"Dreht im Umgang mit Waffen manchmal durch und gibt Dauerfeuer.\nIst ihm das mit seiner Waffe nicht mglich, kann das zu Moralabzgen fhren.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"Ein Profil kostet %d$. Genehmigen Sie die Zahlung? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"Sie knnen das neue Fertigkeitensystem nicht ohne aktivierte PROFEX-Utility benutzen. Suchen Sie in Ihrer JA2_Options.ini den Eintrag: READ_PROFILE_DATA_FROM_XML.", +}; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { - L"Sie haben sich fr den Ironman- Modus entschieden. Mit dieser Einstellung knnen Sie das Spiel nicht speichern, wenn Feinde im Sektor sind. Sind Sie sicher, dass Sie im Ironman- Modus spielen wollen?", + L"Sie haben sich fr den Ironman-Modus entschieden. Mit dieser Einstellung knnen Sie das Spiel nicht speichern, wenn Feinde im Sektor sind. Sind Sie sicher, dass Sie im Ironman-Modus spielen wollen?", }; STR16 gzDisplayCoverText[]= diff --git a/Utils/_Ja25GermanText.h b/Utils/_Ja25GermanText.h index fe13b484..5f2291e7 100644 --- a/Utils/_Ja25GermanText.h +++ b/Utils/_Ja25GermanText.h @@ -33,6 +33,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25ItalianText.cpp b/Utils/_Ja25ItalianText.cpp index cbd08c5b..9be815c3 100644 --- a/Utils/_Ja25ItalianText.cpp +++ b/Utils/_Ja25ItalianText.cpp @@ -1,4 +1,4 @@ -#pragma setlocale("ITALIAN") +//#pragma setlocale("ITALIAN") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25Italiantext.h" @@ -44,6 +44,8 @@ STR16 zNewTacticalMessages[]= L"Per usare l'editor, selezionare una campagna diversa da quella di default.", }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { @@ -64,7 +66,394 @@ STR16 gzIMPSkillTraitsText[]= L"Nessuna", L"Specialit I.M.P.", + L"(Expert)", }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + + L"None", + L"I.M.P. Major Traits", + // second names + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + + L"None", + L"I.M.P. Minor Traits", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Chance to Hit with Assault Rifles\n", + L"+%d%s Chance to Hit with SMGs\n", + L"+%d%s Chance to Hit with LMGs\n", + L"-%d%s APs needed to fire with LMGs\n", + L"-%d%s APs needed to ready light machine guns\n", + L"Auto fire/burst chance to hit penalty is reduced by %d%s\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs needed to fire grenade launchers\n", + L"-%d%s APs needed to fire rocket launchers\n", + L"+%d%s chance to hit with grenade launchers\n", + L"+%d%s chance to hit with rocket launchers\n", + L"-%d%s APs needed to fire mortar\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to raise pistols and revolvers\n", + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change state (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", + L"-%d%s APs needed to change state (stand, crouch, lie down)\n", + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors\n", + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance of other mercs in vicinity and %s himself\n", + L"+%d morale gain of other mercs in vicinity\n", + L"-%d morale loss of other mercs in vicinity\n", + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to make surgical intervention by using medical bag on wounded soldier\n", + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed of all soldiers in the same sector", + L" (max %d these bonuses per sector)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage of blades\n", + L"+%d%s damage of blunt melee weapons\n", + L"Aimed attack by any melee weapon deals +%d%s damage\n", + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if having a blade in hands\n", + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if having a blade in hands\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage of throwing blades\n", + L"+%d%s damage of throwing blades per aim click\n", + L"+%d%s chance to inflict critical hit by throwing blade if not seen or heard\n", + L"+%d critical hit by throwing blade multiplier\n", + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, swatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to train militia\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies if any\n", + L"Prevents the enemy to ambush your squad\n", + L"Prevents the bloodcats to ambush your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to train militia and instruct other mercs\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty for second hand when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25ItalianText.h b/Utils/_Ja25ItalianText.h index ad44a04c..9f4599a0 100644 --- a/Utils/_Ja25ItalianText.h +++ b/Utils/_Ja25ItalianText.h @@ -32,6 +32,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25PolishText.cpp b/Utils/_Ja25PolishText.cpp index 079f784f..5f16f196 100644 --- a/Utils/_Ja25PolishText.cpp +++ b/Utils/_Ja25PolishText.cpp @@ -1,4 +1,4 @@ -#pragma setlocale("POLISH") +//#pragma setlocale("POLISH") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25Polishtext.h" @@ -32,8 +32,8 @@ STR16 zNewTacticalMessages[]= L"Nowi rekruci nie mog tam przyby.", L"Dopki twj laprop bdzie bez nadajnika, nie bdziesz mg zatrudnia nowych czonkw zespou. Moliwe, e to odpowiedni moment eby odczyta zapisany stan gry lub zacz gra od nowa!", L"%s syszy dwik zgniatanego metalu dochodzcy spod ciaa Jerrego. To niestety zabrzmiao jak dwik zgniatanej anteny od twojego laptopa.", //the %s is the name of a merc. @@@ Modified - L"After scanning the note left behind by Deputy Commander Morris, %s senses an oppurtinity. The note contains the coordinates for launching missiles against different towns in Arulco. It also gives the coodinates of the origin - the missile facility.", - L"Noticing the control panel, %s figures the numbers can be reveresed, so that the missile might destroy this very facility. %s needs to find an escape route. The elevator appears to offer the fastest solution...", + L"Po przejeniu notatki zostawionej przez zastpce dowdcy Morris'a, %s zauwaa pewn moliwo. Notatka zawiera koordynaty do wystrzelenia pociskw w dwa miasteczka w Arulco. S na niej rwnie koordynaty z ktrych te pociski zostan wystrzelone - wojskowej placwki.", + L"Przygldajc si panelowi kontrolnemu, %s zauwaa, e cyfry mona odwrci, tak, e pociski mog zniszczy t placwk. %s musi znale drog ucieczki. Wydaje si, e winda jest najszybszym rozwizaniem...", L"To jest tryb CZOWIEK ZE STALI i nie moesz zapisywa gry gdy wrg jest w sektorze.", // @@@ new text L"(Nie mona zapisywa gry podczas walki)", //@@@@ new text L"Kampania ma wicej ni 30 postaci.", // @@@ new text @@ -44,6 +44,8 @@ STR16 zNewTacticalMessages[]= L"eby uy edytora powiniene wczeniej wybra kampani inn ni standardowa.", ///@@new }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { @@ -64,7 +66,395 @@ STR16 gzIMPSkillTraitsText[]= L"Brak", L"Umiejtnoci", + L"(Ekspert)", + }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Bro automatyczna", + L"Bro cika", + L"Strzelec wyborowy", + L"owca", + L"Rewolwerowiec", + L"Walka wrcz", + L"Zastpca szeryfa", + L"Technik", + L"Paramedyk", + + L"None", + L"Gwne cechy I.M.P", + // second names + L"Strzelec CKM", + L"Bombardier", + L"Snajper", + L"Leniczy", + L"Rewolwerowiec", + L"Walka wrcz", + L"Dowdca druyny", + L"Inynier", + L"Doktor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Oburczno", + L"Walka wrcz", + L"Rzucanie", + L"Operacje nocne", + L"Cichy", + L"Atletyka", + L"Bodybuilding", + L"adunki wybuchowe", + L"Nauczanie", + L"Zwiad", + + L"Brak", + L"Pomniejsze cechy I.M.P", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s do szansy trafienia karabinem szturmowym\n", + L"+%d%s do szansy trafienia pistoletem maszynowym\n", + L"+%d%s do szansy trafienia erkaemem\n", + L"-%d%s do liczby PA potrzebnych do strzau erkaemem w trybie automatycznym lub seri\n", + L"-%d%s do liczby PA potrzebnych do przygotowania erkaemu\n", + L"Kara do szansy trafienia ogniem automatycznym/seri jest zmniejszona o %d%s\n", + L"Zmniejszona szansa na wystrzelenie przez przypadek wikszej liczby pociskw w ogniu automatycznym o -%d%s\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s do liczby PA potrzebnych do strzau z granatnika\n", + L"-%d%s do liczby PA potrzebnych do strzau z wyrzutni rakiet\n", + L"+%d%s do szansy trafienia grantnikiem\n", + L"+%d%s do szansy trafienia wyrzutni rakiet\n", + L"-%d%s do liczby PA potrzebnych do strzau z modzierza\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to ready pistols and revolvers\n", // MINTY - "raise" changed to "ready" + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change stance (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", // MINTY - "state" changed to "stance" + L"-%d%s APs needed to change stance (stand, crouch, lie down)\n", // MINTY - "state" changed to "stance" + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors in\n", // MINTY - Changed to "kick doors in" + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance for other mercs in the vicinity and %s himself\n", // MINTY - Changed "of" to "for" + L"+%d morale gain for other mercs in the vicinity\n", // MINTY - Changed "of" to "for" + L"-%d morale loss for other mercs in the vicinity\n", // MINTY - Changed "of" to "for" + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to perform surgical intervention by using medical bag on wounded soldier\n", // MINTY - "make" changed to "perform" + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed for all soldiers in the same sector", // MINTY - Changed "of" to "for" + L" (max %d of these bonuses per sector stack)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage with blades\n", // MINTY - Changed "of" to "with" + L"+%d%s damage with blunt melee weapons\n", // MINTY - Changed "of" to "with" + L"Aimed attack with any melee weapon deals +%d%s damage\n", // MINTY - Changed "by" to "with" + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if holding a blade\n", // MINTY - "having a blade in hands" changed to "holding a blade" + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if holding a blade\n", // MINTY - "having a blade in hands" changed to "holding a blade" + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage with throwing blades\n", // MINTY - Changed "of" to "with" + L"+%d%s damage with throwing blades per aim click\n", // MINTY - Changed "of" to "with" + L"+%d%s chance to inflict critical hit with throwing blade if not seen or heard\n", // MINTY - Changed "by" to "with" + L"+%d critical hit with throwing blade multiplier\n", // MINTY - Changed "by" to "with" + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in the dark\n", + L"+%d to general effective hearing range\n", + L"+%d additional hearing range in the dark\n", // MINTY - Changed "effective hearing range in dark on top" to "additional hearing range in the dark" + L"+%d to interrupts modifier in the dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, squatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to militia training speed\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies, if any\n", + L"Prevents enemy ambushes on your squad\n", + L"Prevents bloodcat ambushes on your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in the dark\n", + L"+%d to general effective hearing range\n", + L"+%d extra hearing range in the dark\n", + L"+%d to interrupts modifier in the dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to militia training and other mercs instructing speed\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25PolishText.h b/Utils/_Ja25PolishText.h index ad44a04c..9f4599a0 100644 --- a/Utils/_Ja25PolishText.h +++ b/Utils/_Ja25PolishText.h @@ -32,6 +32,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25RussianText.cpp b/Utils/_Ja25RussianText.cpp index fe1de952..801ec076 100644 --- a/Utils/_Ja25RussianText.cpp +++ b/Utils/_Ja25RussianText.cpp @@ -1,11 +1,13 @@ -#pragma setlocale("RUSSIAN") +//#pragma setlocale("RUSSIAN") #ifdef PRECOMPILEDHEADERS #include "Utils All.h" #include "_Ja25RussianText.h" #else #include "Language Defines.h" - #include "text.h" - #include "Fileman.h" + #ifdef RUSSIAN + #include "text.h" + #include "Fileman.h" + #endif #endif //suppress : warning LNK4221: no public symbols found; archive member will be inaccessible @@ -29,23 +31,25 @@ STR16 zNewTacticalMessages[]= L" ", L" .", L" , . , , !", - L"%s . , .", //the %s is the name of a merc. @@@ Modified + L"%s . , .", //the %s is the name of a merc. L" , , %s , . . , .", L" , %s , , . %s , . , ...", - L" \" \" .", // @@@ new text - L"( )", //@@@@ new text - L" 30 .", // @@@ new text - L" .", // @@@ new text - L": ( %S )", // @@@ new text - L": %S", // @@@ new text - L" %S. Unfinished Business. , %S?", // @@@ new text - L" , .", ///@@new + L" \" \" .", + L"( )", + L" 30 .", + L" .", + L": ( %S )", + L": %S", + L" %S. Unfinished Business. , %S?", + L" , .", }; - +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { + // made this more elegant L" ", L" ", L"", @@ -55,7 +59,7 @@ STR16 gzIMPSkillTraitsText[]= L" ", L" ", L"", - L" ", + L"", L" ", L"", L"", @@ -63,25 +67,422 @@ STR16 gzIMPSkillTraitsText[]= L"", L"I.M.P.: ", + L"()", }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"", //Auto Weapons + L"", //Heavy Weapons + L"", //Marksman + L"", //Hunter + L"", //Gunslinger + L"", //Hand to Hand + L"", //Deputy + L"-", //Technician + L"", //Paramedic + + L"", + L"I.M.P.: ", //I.M.P. Major Traits + // second names + L"", //Machinegunner + L"", //Bombardier + L"", //Sniper + L"", //Ranger + L"", //Gunfighter + L" ", //Martial Arts + L"", //Squadleader + L"", //Engineer + L"", //Doctor +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"", //Ambidextrous + L" ", //Melee + L" ", //Throwing + L" ", //Night Ops + L" ", //Stealthy + L"", //Athletics + L"", //Bodybuilding + L"", //Demolitions + L"", //Teaching + L"", //Scouting + + L"", + L"I.M.P.: ", //I.M.P. Minor Traits +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s \n", + L"+%d%s -\n", + L"+%d%s \n", + L"-%d%s \n", + L"-%d%s \n", + L" %d%s\n", + L" \n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s \n", + L"-%d%s \n", + L"+%d%s \n", + L"+%d%s \n", + L"-%d%s \n", + L" %d%s\n", + L"+%d%s , \n", + L"+%d%s \n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s \n", + L"+%d%s \n", + L"-%d%s \n", //-%d%s effective range to target with all weapons + L"+%d%s ( )\n", + L"+%d%s ", //+%d%s damage on shot + L" ", + L" ", + L" ", + L" ", + L" ", + L" ", + L" ", + L" ", + L" ", + L"-%d%s \n", + L" 1 - \n", + L" %d - \n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s \n", + L"+%d%s \n", + L"-%d%s \n", + L"+%d%s , \n", + L"+%d%s , \n ( )\n", + L"-%d%s \n", // + L"-%d%s \n", + L"+%d%s \n", + L"-%d%s \n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s \n", + L"+%d%s \n", + L"+%d%s \n", + L"+%d%s -", + L" ( )", + L"+%d%s , - \n", + L"-%d%s \n", + L"-%d%s , - \n", + L" %d , - ", + L" %d , - \n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change stance (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", + L"-%d%s APs needed to change stance (stand, crouch, lie down)\n", + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors in\n", + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance for other mercs in the vicinity and %s himself\n", + L"+%d morale gain for other mercs in the vicinity\n", + L"-%d morale loss for other mercs in the vicinity\n", + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to perform surgical intervention by using medical bag on wounded soldier\n", + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed for all soldiers in the same sector", + L" (max %d of these bonuses per sector stack)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L" ", //No bonuses +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L" %d%s\n", + L"+%d%s \n", + L"+%d%s \n", + L"-%d%s \n", + L"-%d%s \n", + L"-%d%s \n", + L"-%d%s , / \n", + L"-%d%s , \n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage with blades\n", + L"+%d%s damage with blunt melee weapons\n", + L"Aimed attack with any melee weapon deals +%d%s damage\n", + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if holding a blade\n", + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if holding a blade\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage with throwing blades\n", + L"+%d%s damage with throwing blades per aim click\n", + L"+%d%s chance to inflict critical hit with throwing blade if not seen or heard\n", + L"+%d critical hit with throwing blade multiplier\n", + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d \n", + L"+%d \n", + L"+%d \n", + L"+%d \n", + L"-%d \n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s , \n", + L"+%d%s \n", + L"+%d%s ( '' )\n", + L" %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s (, , , , ..)\n", + L"-%d%s , , , ..\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L" %d%s \n", + L"+%d%s \n", + L" %d%s\n", + L" , %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to militia training speed\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies, if any\n", + L"Prevents enemy ambushes on your squad\n", + L"Prevents bloodcat ambushes on your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L" ", //No bonuses +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in the dark\n", + L"+%d to general effective hearing range\n", + L"+%d extra hearing range in the dark\n", + L"+%d to interrupts modifier in the dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to militia training and other mercs instructing speed\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty when firing two weapons at once\n", + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L" ", //No bonuses +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ +//I.M.P. Character Traits help text +//Neutral + L": .\n \n: .", +//Sociable + L": .\n \n: , .", +//Loner + L": .\n \n: .", +//Optimist + L": , .\n \n: .", +//Assertive + L": .\n \n: .", +//Intellectual + L": .\n \n: .", +//Primitive + L": , , , .\n \n: , , , .", +//Aggressive + L": . \n , .\n \n: , : \n, , , , .", +//Phlegmatic + L": , : \n, , , , .\n \n: .", +//Dauntless + L": . \n , .\n \n: .", +//Pacifist + L": ( ).\n \n: .", +//Malicious + L": , .\n \n: , .", +//Show-off + L": .\n \n: .", +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L" .", + L" \n .", + L" .", + L" , .", + L" .", + L" ... \n .", + L" , - \n .", + L" . \n . \n , .", +}; + + +STR16 gzIMPProfileCostText[]= +{ + L" %d$. ? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L" IMP PROFEX. JA2_Options.ini, : READ_PROFILE_DATA_FROM_XML.", //You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML. +}; + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { - L" \" \". , , . . , \" \"?", + L" \" \". , . . , ?", }; STR16 gzDisplayCoverText[]= { - L": %d/100 %s, : %d/100", //Cover: %d/100 %s, Brightness: %d/100 - L" : %d/%d ., : %d/100", //Gun Range: %d/%d tiles, Chance to hit: %d/100 - L" ", //Disabling cover display - L" ", //Showing mercenary view - L" ", //Showing danger zones for mercenary + L": %d/100 %s, : %d/100", + L" : %d/%d ., : %d/100", + L" ", + L" ", + L" ", L"", //Wood //wanted to use jungle , but wood is shorter in german too (dschungel vs wald) - L"", //Urban - L"", //Desert - L"", //Snow //NOT USED!!! - L" ", //Wood and Desert + L"", + L"", + L"", //NOT USED!!! + L" ", L"" // yes empty for now }; diff --git a/Utils/_Ja25RussianText.h b/Utils/_Ja25RussianText.h index ad44a04c..9f4599a0 100644 --- a/Utils/_Ja25RussianText.h +++ b/Utils/_Ja25RussianText.h @@ -32,6 +32,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_Ja25TaiwaneseText.cpp b/Utils/_Ja25TaiwaneseText.cpp index af0012e1..b5163b09 100644 --- a/Utils/_Ja25TaiwaneseText.cpp +++ b/Utils/_Ja25TaiwaneseText.cpp @@ -43,13 +43,16 @@ STR16 zNewTacticalMessages[]= L"In order to use the editor, please select a campaign other than the default.", ///@@new }; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SANDRO - New STOMP laptop strings //these strings match up with the defines in IMP Skill trait.cpp STR16 gzIMPSkillTraitsText[]= { - L"Lock picking", - L"Hand to hand combat", + // made this more elegant + L"Lock Picking", + L"Hand to Hand", L"Electronics", - L"Night operations", + L"Night Operations", L"Throwing", L"Teaching", L"Heavy Weapons", @@ -58,12 +61,400 @@ STR16 gzIMPSkillTraitsText[]= L"Ambidextrous", L"Knifing", L"Sniper", - L"Camouflage", + L"Camouflaged", L"Martial Arts", L"None", L"I.M.P. Specialties", + L"(Expert)", + }; + +//added another set of skill texts for new major traits +STR16 gzIMPSkillTraitsTextNewMajor[]= +{ + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + + L"None", + L"I.M.P. Major Traits", + // second names + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", +}; + +//added another set of skill texts for new minor traits +STR16 gzIMPSkillTraitsTextNewMinor[]= +{ + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + + L"None", + L"I.M.P. Minor Traits", +}; + +//these texts are for help popup windows, describing trait properties +STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]= +{ + L"+%d%s Chance to Hit with Assault Rifles\n", + L"+%d%s Chance to Hit with SMGs\n", + L"+%d%s Chance to Hit with LMGs\n", + L"-%d%s APs needed to fire with LMGs\n", + L"-%d%s APs needed to ready light machine guns\n", + L"Auto fire/burst chance to hit penalty is reduced by %d%s\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]= +{ + L"-%d%s APs needed to fire grenade launchers\n", + L"-%d%s APs needed to fire rocket launchers\n", + L"+%d%s chance to hit with grenade launchers\n", + L"+%d%s chance to hit with rocket launchers\n", + L"-%d%s APs needed to fire mortar\n", + L"Reduce penalty for mortar CtH by %d%s\n", + L"+%d%s damage to tanks with heavy weapons, grenades and explosives\n", + L"+%d%s damage to other targets with heavy weapons\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSniper[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Sniper Rifles\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click (except for handguns)\n", + L"+%d%s damage on shot", + L" plus", + L" per every aim click", + L" after first", + L" after second", + L" after third", + L" after fourth", + L" after fifth", + L" after sixth", + L" after seventh", + L"-%d%s APs needed to chamber a round with bolt-action rifles \n", + L"Adds one more aim click for rifle-type guns\n", + L"Adds %d more aim clicks for rifle-type guns\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsRanger[]= +{ + L"+%d%s Chance to Hit with Rifles\n", + L"+%d%s Chance to Hit with Shotguns\n", + L"-%d%s APs needed to pump Shotguns\n", + L"+%d%s group travelling speed between sectors if traveling by foot\n", + L"+%d%s group travelling speed between sectors if traveling in vehicle (except helicopter)\n", + L"-%d%s less energy spent for travelling between sectors\n", + L"-%d%s weather penalties\n", + L"+%d%s camouflage effectiveness\n", + L"-%d%s worn out speed of camouflage by water or time\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsGunslinger[]= +{ + L"-%d%s APs needed to fire with pistols and revolvers\n", + L"+%d%s effective range with pistols and revolvers\n", + L"+%d%s chance to hit with pistols and revolvers\n", + L"+%d%s chance to hit with machine pistols", + L" (on single shots only)", + L"+%d%s aiming bonus per click with pistols, machine pistols and revolvers\n", + L"-%d%s APs needed to raise pistols and revolvers\n", + L"-%d%s APs needed to reload pistols, machine pistols and revolvers\n", + L"Adds %d more aim click for pistols, machine pistols and revolvers\n", + L"Adds %d more aim clicks for pistols, machine pistols and revolvers\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= +{ + L"-%d%s AP cost of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s chance to hit with hand to hand attacks with bare hands\n", + L"+%d%s chance to hit with hand to hand attacks with brass knuckles\n", + L"+%d%s damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"+%d%s breath damage of hand to hand attacks(bare hands or with brass knuckles)\n", + L"Enemy knocked out due to your HtH attacks takes slightly longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes much longer to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes very long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes extremely long to recuperate\n", + L"Enemy knocked out due to your HtH attacks takes long hours to recuperate\n", + L"Enemy knocked out due to your HtH attacks probably never stand up\n", + L"Focused (aimed) punch deals +%d%s more damage\n", + L"Your special spinning kick deals +%d%s more damage\n", + L"+%d%s change to dodge hand to hand attacks\n", + L"+%d%s on top chance to dodge HtH attacks with bare hands", + L" or brass knuckles", + L" (+%d%s with brass knuckles)", + L"+%d%s on top chance to dodge HtH attacks with brass knuckles\n", + L"+%d%s chance to dodge attacks by any melee weapon\n", + L"-%d%s APs needed to steal weapon from enemy hands\n", + L"-%d%s APs needed to change state (stand, crouch, lie down), turn around, climb on/off roof and jump obstacles\n", + L"-%d%s APs needed to change state (stand, crouch, lie down)\n", + L"-%d%s APs needed to turn around\n", + L"-%d%s APs needed to climb on/off roof and jump obstacles\n", + L"+%d%s chance to kick doors\n", + L"You gain special animations for hand to hand combat\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= +{ + L"+%d%s APs per round of other mercs in vicinity\n", + L"+%d effective exp level of other mercs in vicinity, which have lesser level than the %s\n", + L"+%d effective exp level to count as a standby when counting friends' bonus for suppression\n", + L"+%d%s total suppression tolerance of other mercs in vicinity and %s himself\n", + L"+%d morale gain of other mercs in vicinity\n", + L"-%d morale loss of other mercs in vicinity\n", + L"The vicinity for bonuses is %d tiles", + L" (%d tiles with extended ears)", + L"(Max simultaneous bonuses for one soldier is %d)\n", + L"+%d%s fear resistence of %s\n", + L"Drawback: %dx morale loss for %s's death for all other mercs\n", + +}; +STR16 gzIMPMajorTraitsHelpTextsTechnician[]= +{ + L"+%d%s to repairing speed\n", + L"+%d%s to lockpicking (normal/electronic locks)\n", + L"+%d%s to disarming electronic traps\n", + L"+%d%s to attaching special items and combining things\n", + L"+%d%s to unjamming a gun in combat\n", + L"Reduce penalty to repair electronic items by %d%s\n", + L"Increased chance to detect traps and mines (+%d detect level)\n", + L"+%d%s CtH of robot controlled by the %s\n", + L"%s trait grants you the ability to repair the robot\n", + L"Reduced penalty to repair speed of the robot by %d%s\n", +}; +STR16 gzIMPMajorTraitsHelpTextsDoctor[]= +{ + L"Has ability to make surgical intervention by using medical bag on wounded soldier\n", + L"Surgery instantly returns %d%s of lost health back.", + L" (This drains the medical bag a lot.)", + L"Can heal lost stats (from critical hits) by the", + L" surgery or", + L" doctor assignment.\n", + L"+%d%s effectiveness on doctor-patient assignment\n", + L"+%d%s bandaging speed\n", + L"+%d%s natural regeneration speed of all soldiers in the same sector", + L" (max %d these bonuses per sector)", + +}; +STR16 gzIMPMajorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]= +{ + L"Reduce penalty to shoot dual weapons by %d%s\n", + L"+%d%s speed of reloading guns with magazines\n", + L"+%d%s speed of reloading guns with loose rounds\n", + L"-%d%s APs needed to pickup items\n", + L"-%d%s APs needed to work backpack\n", + L"-%d%s APs needed to handle doors\n", + L"-%d%s APs needed to plant/remove bombs and mines\n", + L"-%d%s APs needed to attach items\n", +}; +STR16 gzIMPMinorTraitsHelpTextsMelee[]= +{ + L"-%d%s APs needed to attack by blades\n", + L"+%d%s chance to hit with blades\n", + L"+%d%s chance to hit with blunt melee weapons\n", + L"+%d%s damage of blades\n", + L"+%d%s damage of blunt melee weapons\n", + L"Aimed attack by any melee weapon deals +%d%s damage\n", + L"+%d%s chance to dodge attack by melee blades\n", + L"+%d%s on top chance to dodge melee blades if having a blade in hands\n", + L"+%d%s chance to dodge attack by blunt melee weapons\n", + L"+%d%s on top chance to dodge blunt melee weapons if having a blade in hands\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsThrowing[]= +{ + L"-%d%s basic APs needed to throw blades\n", + L"+%d%s max range when throwing blades\n", + L"+%d%s chance to hit when throwing blades\n", + L"+%d%s chance to hit when throwing blades per aim click\n", + L"+%d%s damage of throwing blades\n", + L"+%d%s damage of throwing blades per aim click\n", + L"+%d%s chance to inflict critical hit by throwing blade if not seen or heard\n", + L"+%d critical hit by throwing blade multiplier\n", + L"Adds %d more aim click for throwing blades\n", + L"Adds %d more aim clicks for throwing blades\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNightOps[]= +{ + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsStealthy[]= +{ + L"-%d%s APs needed to move quietly\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Reduced cover penalty for movement by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsAthletics[]= +{ + L"-%d%s APs needed for moving (running, walking, swatting, crawling, swimming, etc.)\n", + L"-%d%s energy spent for movement, roof-climbing, obstacle-jumping, swimming, etc.\n", +}; +STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]= +{ + L"Has %d%s damage resistance\n", + L"+%d%s effective strength for carrying weight capacity \n", + L"Reduced energy lost when hit by HtH attack by %d%s\n", + L"Increased damage needed to fall down if hit to legs by %d%s\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsDemolitions[]= +{ + L"-%d%s APs needed to throw grenades\n", + L"+%d%s max range when throwing grenades\n", + L"+%d%s chance to hit when throwing grenades\n", + L"+%d%s damage of set bombs and mines\n", + L"+%d%s to attaching detonators check\n", + L"+%d%s to planting/removing bombs check\n", + L"Decreases chance enemy will detect your bombs and mines (+%d bomb level)\n", + L"Increased chance shaped charge will open the doors (damage multiplied by %d)\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsTeaching[]= +{ + L"+%d%s bonus to train militia\n", + L"+%d%s bonus to effective leadership for determining militia training\n", + L"+%d%s bonus to teaching other mercs\n", + L"Skill value counts to be +%d higher for being able to teach this skill to other mercs\n", + L"+%d%s bonus to train stats through self-practising assignment\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsScouting[]= +{ + L"+%d to effective sight range with scopes on weapons\n", + L"+%d to effective sight range with binoculars (and scopes separated from weapons)\n", + L"-%d tunnel vision with binoculars (and scopes separated from weapons)\n", + L"If in sector, adjacent sectors will show exact number of enemies\n", + L"If in sector, adjacent sectors will show presence of enemies if any\n", + L"Prevents the enemy to ambush your squad\n", + L"Prevents the bloodcats to ambush your squad\n", + +}; +STR16 gzIMPMinorTraitsHelpTextsNone[]= +{ + L"No bonuses", +}; + +STR16 gzIMPOldSkillTraitsHelpTexts[]= +{ + L"+%d%s bonus to lockpicking\n", // 0 + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks\n", + L"Eliminates the penalty to repair and handle\nelectronic things (locks, traps, rem. detonators, robot, etc.)\n", + L"+%d to effective sight range in dark\n", + L"+%d to general effective hearing range\n", + L"+%d to effective hearing range in dark on top\n", + L"+%d to interrupts modifier in dark\n", + L"-%d need to sleep\n", + L"+%d%s max range when throwing anything\n", // 10 + L"+%d%s chance to hit when throwing anything\n", + L"+%d%s chance to instantly kill by throwing knife if not seen or heard\n", + L"+%d%s bonus to train militia and instruct other mercs\n", + L"+%d%s effective leadership for militia training calculations\n", + L"+%d%s chance to hit with rocket/greande launchers and mortar\n", + L"Auto fire/burst chance to hit penalty is divided by %d\n", + L"Reduced chance for shooting unwanted bullets on autofire\n", + L"+%d%s chance to move quietly\n", + L"+%d%s stealth (being 'invisible' if unnoticed)\n", + L"Eliminates the CtH penalty for second hand when firing two weapons at once\n", // 20 + L"+%d%s chance to hit with melee blades\n", + L"+%d%s chance to dodge attacks by melee blades if having blade in hands\n", + L"+%d%s chance to dodge attacks by melee blades if having anything else in hands\n", + L"+%d%s chance to dodge hand to hand attacks if having blade in hands\n", + L"-%d%s effective range to target with all weapons\n", + L"+%d%s aiming bonus per aim click\n", + L"Provides permanent camouflage\n", + L"+%d%s hand to hand chance to hit\n", + L"+%d%s hand to hand damage\n", + L"+%d%s chance to dodge hand to hand attacks if having empty hands\n", // 30 + L"+%d%s chance to dodge hand to hand attacks if not having empty hands\n", + L"+%d%s chance to dodge attacks by melee blades\n", + L"Can perform spinning kick attack on weakened enemies to deal double damage\n", + L"You gain special animations for hand to hand combat\n", + L"No bonuses", +}; + +STR16 gzIMPNewCharacterTraitsHelpTexts[]= +{ + L"A: No advantage.\nD: No disadvantage.", + L"A: Has better performance when couple of mercs are nearby.\nD: Gains no morale when no other merc is nearby.", + L"A: Has better performance when no other merc is nearby.\nD: Gains no morale when in a group.", + L"A: His morale sinks a little slower and grows faster than normal.\nD: Has lesser chance to detect traps and mines.", + L"A: Has bonus on training militia and is better at communication with people.\nD: Gains no morale for actions of other mercs.", + L"A: Slightly faster learning when assigned on practicing or as a student.\nD: Has lesser suppression and fear resistance.", + L"A: His energy goes down a bit slower except on assignments as doctor, repairman, militia trainer or if learning certain skills.\nD: His wisdom, leadership, explosives, mechanical and medical skills improve slightly slower.", + L"A: Has slightly better chance to hit on burst/autofire and inflicts slightly bigger damage in close combat\n Gains a little more morale for killing.\nD: Has penalty for actions which needs patience like repairing items, picking locks, removing traps, doctoring, training militia.", + L"A: Has bonus for actions which needs patience like repairing items, picking locks, removing traps, doctoring and training militia.\nD: His interrupts chance is slightly lowered.", + L"A: Incresed resistance to suppression and fear.\n Morale loss for taking damage and companions deaths is lower for him.\nD: Can be hit easier and enemy penalty for moving target is lesser in his case.", + L"A: He gains morale when on non-combat assignments (except training militia).\nD: Gains no morale for killing.", + L"A: Has bigger chance for inflicting stat loss and can inflict special painful wounds when able to\n Gains bonus morale for inflicting stat loss.\nD: Has penalty for communication with people and his morale sinks faster if not fighting.", + L"A: Has better performance when there are some mercs of opposite gender nearby.\nD: Morale of other mercs of the same gender grows slower if nearby.", + +}; + +STR16 gzIMPDisabilitiesHelpTexts[]= +{ + L"No effects.", + L"Has problems with breathing and reduced overall performance if in tropical or desert sectors.", + L"Can suffer panic attack if left alone in certain situations.", + L"His overall performance is reduced if underground.", + L"If trying to swim he can easily drown.", + L"A look at large insects can make a big problems\nand being in tropical sectors also reduce his performance a bit.", + L"Sometimes forgets what orders he got and therefore loses some APs if in combat.", + L"He can go psycho and shoot like mad once per a while\nand can lose morale if unable to do that with given weapon.", + +}; + + + +STR16 gzIMPProfileCostText[]= +{ + L"The profile cost is %d$. Do you authorize the payment? ", +}; + +STR16 zGioNewTraitsImpossibleText[]= +{ + L"You cannot choose the New Trait System with PROFEX utility deactivated. Check your JA2_Options.ini for entry: READ_PROFILE_DATA_FROM_XML.", +}; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //@@@: New string as of March 3, 2000. STR16 gzIronManModeWarningText[]= { diff --git a/Utils/_Ja25TaiwaneseText.h b/Utils/_Ja25TaiwaneseText.h index ad44a04c..9f4599a0 100644 --- a/Utils/_Ja25TaiwaneseText.h +++ b/Utils/_Ja25TaiwaneseText.h @@ -32,6 +32,45 @@ enum extern STR16 zNewTacticalMessages[]; extern STR16 gzIMPSkillTraitsText[]; +//////////////////////////////////////////////////////// +// added by SANDRO +extern STR16 gzIMPSkillTraitsTextNewMajor[]; +extern STR16 gzIMPSkillTraitsTextNewMinor[]; + +extern STR16 gzIMPMajorTraitsHelpTextsAutoWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsHeavyWeapons[]; +extern STR16 gzIMPMajorTraitsHelpTextsSniper[]; +extern STR16 gzIMPMajorTraitsHelpTextsRanger[]; +extern STR16 gzIMPMajorTraitsHelpTextsGunslinger[]; +extern STR16 gzIMPMajorTraitsHelpTextsMartialArts[]; +extern STR16 gzIMPMajorTraitsHelpTextsSquadleader[]; +extern STR16 gzIMPMajorTraitsHelpTextsTechnician[]; +extern STR16 gzIMPMajorTraitsHelpTextsDoctor[]; +extern STR16 gzIMPMajorTraitsHelpTextsNone[]; + +extern STR16 gzIMPMinorTraitsHelpTextsAmbidextrous[]; +extern STR16 gzIMPMinorTraitsHelpTextsMelee[]; +extern STR16 gzIMPMinorTraitsHelpTextsThrowing[]; +extern STR16 gzIMPMinorTraitsHelpTextsStealthy[]; +extern STR16 gzIMPMinorTraitsHelpTextsNightOps[]; +extern STR16 gzIMPMinorTraitsHelpTextsAthletics[]; +extern STR16 gzIMPMinorTraitsHelpTextsBodybuilding[]; +extern STR16 gzIMPMinorTraitsHelpTextsDemolitions[]; +extern STR16 gzIMPMinorTraitsHelpTextsTeaching[]; +extern STR16 gzIMPMinorTraitsHelpTextsScouting[]; +extern STR16 gzIMPMinorTraitsHelpTextsNone[]; + +extern STR16 gzIMPOldSkillTraitsHelpTexts[]; + +extern STR16 gzIMPNewCharacterTraitsHelpTexts[]; + +extern STR16 gzIMPDisabilitiesHelpTexts[]; + +extern STR16 gzIMPProfileCostText[]; + +extern STR16 zGioNewTraitsImpossibleText[]; +/////////////////////////////////////////////////////// + enum { IMM__IRON_MAN_MODE_WARNING_TEXT, diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index c42b1f86..d8b5636c 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -1,6 +1,13 @@ -#pragma setlocale("POLISH") -#include "Utils All.h" -#include "Language Defines.h" +//#pragma setlocale("POLISH") +#ifdef PRECOMPILEDHEADERS + #include "Utils All.h" +#else + #include "Language Defines.h" + #if defined( POLISH ) + #include "text.h" + #include "Fileman.h" + #endif +#endif //suppress : warning LNK4221: no public symbols found; archive member will be inaccessible void this_is_the_PolishText_public_symbol(void){;} @@ -103,6 +110,24 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Str. 1/2", //0 + L"Str. 2/2", + + L"Str. 1/3", + L"Str. 2/3", + L"Str. 3/3", + + L"Str. 1/1", //5 +}; + +// by Jazz: TODO.Translate +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Development Team", @@ -313,6 +338,21 @@ CHAR16 Message[][STRING_LENGTH] = L"bro samoczynna", L"Wrg nie ma przedmiotw, ktre mona ukra!", L"Wrg nie ma adnego przedmiotu w rce!", + + //add new camo string + L"%s: kamufla pustynny si star.", + L"%s: kamufla pustynny si zmy.", + + L"%s: kamufla leny si star.", + L"%s: kamufla leny si zmy.", + + L"%s: kamufla miejski si star.", + L"%s: kamufla miejski si zmy.", + + L"%s: kamufla zimowy si star.", + L"%s: kamufla zimowy si zmy.", + + L"Niemoesz przydzieli %s do tego slotu.", }; @@ -382,7 +422,7 @@ STR16 pAssignmentStrings[] = L"Naprawa", // repairing L"Praktyka", // training themselves L"Samoobr.", // training a town to revolt - L"M.Militia", //training moving militia units // TODO.Translate + L"R.Samoobr.", //training moving militia units L"Instruk.", // training a teammate L"Ucze", // being trained by someone else L"Staff", // operating a strategic facility // TODO.Translate @@ -400,15 +440,15 @@ STR16 pMilitiaString[] = L"Samoobrona", // the title of the militia box L"Bez przydziau", //the number of unassigned militia troops L"Nie moesz przemieszcza oddziaw samoobrony gdy nieprzyjaciel jest w sektorze!", - L"Some militia were not assigned to a sector. Would you like to disband them?", // TODO.Translate + L"Cz samoobrony nie zostaa przydzielona do sektoru. Czy chcesz ich rozwiza?", }; STR16 pMilitiaButtonString[] = { - L"Auto", // auto place the militia troops for the player + L"Automatyczne", // auto place the militia troops for the player L"OK", // done placing militia troops - L"Disband", // HEADROCK HAM 3.6: Disband militia // TODO.Translate + L"Rozwi", // HEADROCK HAM 3.6: Disband militia }; STR16 pConditionStrings[] = @@ -466,8 +506,11 @@ STR16 pPersonnelAssignmentStrings[] = L"Naprawa", L"Praktyka", L"Trenuje samoobron", + L"Training Mobile Militia", // TODO.Translate L"Instruktor", L"Ucze", + L"Facility Staff", // TODO.Translate + L"Resting at Facility", // TODO.Translate L"Nie yje", L"Obezwadniony", L"Jeniec", @@ -508,8 +551,11 @@ STR16 pLongAssignmentStrings[] = L"Naprawa", L"Praktyka", L"Trenuj samoobron", + L"Train Mobiles", // TODO.Translate L"Trenuj oddzia", L"Ucze", + L"Staff Facility", // TODO.Translate + L"Rest at Facility", // TODO.Translate L"Nie yje", L"Obezwadniony", L"Jeniec", @@ -753,6 +799,63 @@ STR16 pPersonnelScreenStrings[] = L"Ranny(a):", // number of times merc has been wounded L"Umiejtnoci:", L"Brak umijtnoci", + L"Osignicia:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elitarni: %d\n", + L"Regularni: %d\n", + L"Administratorzy: %d\n", + L"Wrodzy Cywile: %d\n", + L"Stworzenia: %d\n", + L"Czogi: %d\n", + L"Inne: %d\n", + + L"Do najemnikw: %d\n", + L"Milicja: %d\n", + L"Inni: %d\n", + + L"Strzaw: %d\n", + L"Wystrzelonych Pociskw: %d\n", + L"Rzuconych Granatw: %d\n", + L"Rzuconych Noy: %d\n", + L"Atakw Noem: %d\n", + L"Atakw Wrcz: %d\n", + L"Udanych Trafie: %d\n", + + L"Zamki Otwarte Wytrychem: %d\n", + L"Zamki Wyamane: %d\n", + L"Usunite Puapka: %d\n", + L"Zdetonowane adunki: %d\n", + L"Naprawione Przedmioty: %d\n", + L"Poczone Przedmioty: %d\n", + L"Ukradzione Przedmioty: %d\n", + L"Wytrenowana Milicja: %d\n", + L"Zabandaowani Najemnicy: %d\n", + L"Wykonane Operacje Chirurgiczne: %d\n", + L"Spotkani NPC: %d\n", + L"Odkryte Sektory: %d\n", + L"Uniknite Zasadzki: %d\n", + L"Wykonane Zadania: %d\n", + + L"Bitwy Taktyczne: %d\n", + L"Bitwy Autorozstrzygnite: %d\n", + L"Wykonane Odwroty: %d\n", + L"Napotkanych Zasadzek: %d\n", + L"Najwiksza Walka: %d Wrogw\n", + + L"Postrzelony: %d\n", + L"Ugodzony Noem: %d\n", + L"Uderzony: %d\n", + L"Wysadzony W Powietrze: %d\n", + L"Uszkodzonych Atrybutw: %d\n", + L"Poddany Zabiegom Chirurgicznym: %d\n", + L"Wypadkw Przy Pracy: %d\n", + + L"Charakter:", + L"Niepenosprawno:", }; @@ -775,12 +878,53 @@ STR16 gzMercSkillText[] = L"Bro biaa", L"Snajper", //JA25: modified L"Kamufla", //JA25: modified - L"Kamufla (miasto)", - L"Kamufla (pustynia)", - L"Kamufla (nieg)", + // SANDRO - removed this + //L"Kamufla (miasto)", + //L"Kamufla (pustynia)", + //L"Kamufla (nieg)", L"(Eksp.)", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ +// Major traits +L"Brak Umiejtnoci", +L"Bro Automatyczna", +L"Bro Cika", +L"Strzelec Wyborowy", +L"Myliwy", +L"Pistolero", +L"Walka Wrcz", +L"Zastpca Szeryfa", +L"Technik", +L"Paramedyk", +// Minor traits +L"Oburczno", +L"Walka Wrcz", +L"Rzucanie", +L"Operacje Nocne", +L"Ukradkowo", +L"Atletyka", +L"Bodybuilding", +L"adunki Wybuchowe", +L"Uczenie", +L"Zwiad", +// second names for major skills +L"Strzelec RKMu", +L"Bombardier", +L"Snajper", +L"Myliwy", +L"Pistolero", +L"Sztuki Walki", +L"Dowdca Druyny", +L"Inynier", +L"Doktor", +L"Wicej...", +}; +////////////////////////////////////////////////////////// + // This is pop up help text for the options that are available to the merc @@ -1087,11 +1231,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Stan:", - L"Waga (%s):", + L"Waga:", L"PA Koszty", L"Zas.:", // Range L"Sia:", // Damage @@ -1108,35 +1252,40 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L"Attachments:", //14 // TODO.Translate L"AUTO/5:", //15 - L"Liczba:", //16 + L"Remaining ammo:", //16 // TODO.Translate + + L"Domylne:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Zas.", - L"Obra.", - L"PA: (mniej - lepiej)", - L"Auto/5AP", L"Celno", + L"Obra.", + L"Zas.", + L"Aiming Levels", + L"Modf. celowania", + L"redni max zasg. lasera", + L"Tumienie bysku", + L"Gono (mniej - lepiej)", L"Stan", L"Trud napraw", + L"Min. zasg. dla bonusu cel.", + L"Modyf. trafie", + L"", //12 L"AP/przygot.", L"AP za 1 strza", L"AP za seri", L"AP za Auto", L"AP/przeaduj", L"AP/przeaduj rcznie", - L"Tumienie bysku", - L"Gono (mniej - lepiej)", - L"Modyf. trafie", - L"redni max zasg. lasera", - L"Modf. celowania", - L"Min. zasg. dla bonusu cel.", + L"", //19 L"Modf. dwjnogu", + L"Auto/5AP", + L"PA: (mniej - lepiej)", //22 L"AP za rzut", L"AP za strza", L"AP/cios-n", @@ -1148,28 +1297,31 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Burst Penalty (Lower is better)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Zas.", - L"Obra.", - L"PA: (mniej - lepiej)", - L"Auto/5AP", L"Celno", + L"Obra.", + L"Zas.", + L"Aiming Levels", + L"Modf. celowania", + L"redni max zasg. lasera", + L"Tumienie bysku", + L"Gono (mniej - lepiej)", L"Stan", L"Trud napraw", + L"Min. zasg. dla bonusu cel.", + L"Modyf. trafie", + L"", //12 L"AP/przygot.", L"AP za 1 strza", L"AP za seri", L"AP za Auto", L"AP/przeaduj", L"AP/przeaduj rcznie", - L"Modyf. trafie", - L"redni max zasg. lasera", - L"Modf. celowania", - L"Min. zasg. dla bonusu cel.", - L"Tumienie bysku", - L"Gono (mniej - lepiej)", + L"", //19 L"Modf. dwjnogu", + L"Auto/5AP", + L"PA: (mniej - lepiej)", //22 L"AP za rzut", L"AP za strza", L"AP/cios-n", @@ -1293,6 +1445,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1870,6 +2036,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"Poka przestrze powietrzn (|A)", L"Poka przedmioty (|I)", L"Poka samoobron i wrogw (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1903,7 +2070,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc", @@ -1958,7 +2129,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings @@ -2070,8 +2241,8 @@ STR16 pTransactionText[] = L"Zakupy u - %s.", //is used for the Shop keeper interface. The dealers name will be appended to the end of the string. L"%s wpaci(a) pienidze.", L"Sprzedano rzecz(y) miejscowym", - L"Facility Use", // HEADROCK HAM 3.6 // TODO.Translate - L"Militia upkeep", // HEADROCK HAM 3.6 // TODO.Translate + L"Wykorzystanie Placwki", // HEADROCK HAM 3.6 + L"Utrzymanie Samoobr.", // HEADROCK HAM 3.6 }; STR16 pTransactionAlternateText[] = @@ -2306,7 +2477,7 @@ STR16 pImpButtonText[] = L"ZACZNIJ", // begin profiling L"Umiejtnoci", // personality section L"Atrybuty", // personal stats/attributes section - L"Appearance", // changed from portrait - SANDRO + L"Appearance", // changed from portrait L"Gos %d", // the voice selection L"Gotowe", // done profiling L"Zacznij od pocztku", // start over profiling @@ -2327,16 +2498,16 @@ STR16 pImpButtonText[] = L"Rejestr", // the IMP site registry..when name and gender is selected L"Analizuj...", // analyzing your profile results L"OK", - L"Character", // Change from "Voice" - SANDRO + L"Posta", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO - L"With your character traits chosen, it is time to select your skills.", - L"To complete the process, select your attributes.", - L"To commence actual profiling, select portrait, voice and colors.", - L"Now that you have completed your appearence choice, procced to character analysis.", + // These texts have been also slightly changed + L"Po wybraniu twoich cech pora wybra twoje umiejtnoci.", + L"Wybierz twoje atrybuty.", + L"Aby dokona prawdziwego profilowania wybie portret, gos i kolory.", + L"Teraz, po wybraniu wygldu, przejd do analizy postaci.", }; STR16 pFilesTitle[] = @@ -3207,7 +3378,7 @@ STR16 AimMemberText[] = L"kontakt z najemnikiem", L"Prawy klawisz myszy", L"lista portretw", -}; +}; //Aim Member.c //The page in which the players hires AIM mercenaries @@ -3216,9 +3387,9 @@ STR16 CharacterInfo[] = { // The various attributes of the merc - L"Zdrowie", - L"Zwinno", - L"Sprawno", + L"Zdrowie", + L"Zwinno", + L"Sprawno", L"Sia", L"Um. dowodzenia", L"Inteligencja", @@ -3231,8 +3402,8 @@ STR16 CharacterInfo[] = // the contract expenses' area L"Zapata", - L"Czas", - L"1 dzie", + L"Czas", + L"1 dzie", L"1 tydzie", L"2 tygodnie", @@ -3246,7 +3417,13 @@ STR16 CharacterInfo[] = L"Dodatkowe informacje", // Title for the additional info for the merc's bio L"Aktywni czonkowie", //20 // Title of the page L"Opcjonalne wyposaenie:", // Displays the optional gear cost + L"gear", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"Wymagany jest zastaw na ycie", // If the merc required a medical deposit, this is displayed + L"Zestaw nr 1", // Text on Starting Gear Selection Button 1 + L"Zestaw nr 2", // Text on Starting Gear Selection Button 2 + L"Zestaw nr 3", // Text on Starting Gear Selection Button 3 + L"Zestaw nr 4", // Text on Starting Gear Selection Button 4 + L"Zestaw nr 5", // Text on Starting Gear Selection Button 5 }; @@ -3627,6 +3804,9 @@ STR16 zMarksMapScreenText[] = L"Najemnik ma kontrakt na okrelony czas.", L"Kontrakt najemnika nie jest ubezpieczony", L"Mapa", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3649,10 +3829,10 @@ STR16 pMilitiaConfirmStrings[] = L"Nie masz %d$, aby wyszkoli samoobron w tym miecie.", L"%s musi mie %d% lojalnoci, aby mona byo kontynuowa szkolenie samoobrony.", L"Nie moesz ju duej szkoli samoobrony w miecie %s.", - L"You cannot afford the $%d to train mobile militia here.", // HEADROCK HAM 3.6: Mobile Militia // TODO.Translate - L"Continue training mobile militia in %s (%s %d)?", // HEADROCK HAM 3.6: Mobile Militia // TODO.Translate - L"Training mobile militia in %d sectors will cost $ %d. %s", // HEADROCK HAM 3.6: Mobile Militia // TODO.Translate - L"Training a squad of mobile militia will cost $", // HEADROCK HAM 3.6: Mobile Militia // TODO.Translate + L"Nie masz %d$ i nie moesz trenowa tutaj ruchomej samoobrony.", // HEADROCK HAM 3.6: Mobile Militia + L"Kontynuuj trening ruchomej samoobrony w %s (%s %d)?", // HEADROCK HAM 3.6: Mobile Militia + L"Trenowanie ruchomej samoobrony w %d sektorach bdzie kosztowa %d$. %s", // HEADROCK HAM 3.6: Mobile Militia + L"Trenowanie ruchomej samoobrony bdzie kosztowa $", // HEADROCK HAM 3.6: Mobile Militia }; //Strings used in the popup box when withdrawing, or depositing money from the $ sign at the bottom of the single merc panel @@ -3692,22 +3872,25 @@ STR16 zOptionsToggleText[] = L"Pokazuj kursor 3D", L"Pokazuj szans na trafienie", L"Zamiana kursora granatnika", - L"Wrg opuszcza cay ekwipunek", + L"Pozwl na przechwaki wrogw", // Changed from "Enemies Drop all Items" - SANDRO L"Wysoki kt strzaw z granatnika", - L"Ograniczenie poziomw celowania", + L"Pozwl na skradanie si w czasie rzeczywistym", // Changed from "Restrict extra Aim Levels" - SANDRO L"Spacja = nastpny oddzia", L"Pokazuj cienie przedmiotw", L"Pokazuj zasig broni w polach", L"Efekt smugowy dla poj. strzau", L"Odgosy padajcego deszczu", L"Pokazuj wrony", - L"Show Soldier Tooltips", // Changed from "Random I.M.P personality" - SANDRO + L"Show Soldier Tooltips", L"Automatyczny zapis", L"Cichy Skyrider", L"Niskie obcienie procesora", L"Rozszerzone Okno Opisu (EDB)", //Enhanced Description Box L"Wymu tryb turowy", // add forced turn mode L"Stat Progress Bars", // Show progress towards stat increase // TODO.Translate + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) // TODO.Translate L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3726,13 +3909,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"Jeli WCZONE, w grze pojawia si bd dialogi.", //Mute Confirmation L"Jeli WCZONE, gosowe potwierdzenia postaci zostan wyciszone.", - //Subtitles + //Subtitles L"Jeli WCZONE, pojawia si bd napisy podczas rozmw z innymi postaciami.", //Key to advance speech @@ -3788,31 +3973,34 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"Jeli WCZONE, kursor bdzie pokazywa szans na trafienie.", L"Jeli WCZONE, seria z granatnika bdzie uywaa kursora serii z broni palnej.", - L"Jeli WCZONE, martwi wrogowie bd upuszcza cay ekwipunek.", + L"Jeeli wczone, to wrogowie bd czasami komentowa pewne akcje.", // Changed from Enemies Drop All Items - SANDRO L"Jeli WCZONE, granatniki bd strzelay pod wysokim ktem. ( |Q )", - L"Jeli WCZONE, poziom celowania powyej 4 bdzie dostpny tylko dla karabinw i karabinw snajperskich.", + L"Jeli WCZONE, zapobiega przejciu do trybu turowego po zauwaeniu wroga podczas skradania. Aby wymusi tryb turowy z t opcj aktywn nacinij |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"Jeli WCZONE, |S|p|a|c|j|a wybiera kolejny oddzia.", L"Jeli WCZONE, pokazywane bd cienie przedmiotw.", L"Jeli WCZONE, zasig broni bdzie wywietlany w polach.", L"Jeli WCZONE, pojedynczy strza bdzie z efektem pocisku smugowego", L"Jeli WCZONE, bdziesz sysza padajcy deszcz.", L"Jeli WCZONE, w grze pojawia si bd wrony.", - L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", // - Changed from random IMP personality - SANDRO + L"Gdy ta opcja jest AKTYWNA, wskazanie postaci wroga kursorem i nacinicie A|l|t ukae okienko informacji dodatkowych.", L"Jeli WCZONE, gra bdzie zapisywana kadorazowo po zakoczeniu tury gracza.", L"Jeli WCZONE, Skyrider nie bdzie nic mwi.", L"Jeli WCZONE, gra bdzie obciaa procesor w mniejszym stopniu.", L"Jeli WCZONE, rozszerzone opisy bd pokazane dla przedmiotw i broni.", L"Jeli WCZONE i wrg jest obecny, \ntryb turowy jest wczony, \ndopki sektor nie zostanie oczyszczony (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode - L"When ON, shows character progress towards gaining levels.", // TODO.Translate + L"Gdy WCZONE, pokazuje postp w dowiadczeniu postaci.", + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"Gdy WCZONE, zastpuje star animacj pocisku now.", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", - L"Force all pending Bobby Ray shipments", + L"Wymu wszystkie oczekiwane dostawy od Bobby Ray's.", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", L"(text not rendered)TOPTION_DEBUG_MODE_OPTIONS_HEADER", // an example options screen options header (pure text) - L"Click me to fix corrupt game settings", // failsafe show/hide option to reset all options - L"Click me to fix corrupt game settings", // a do once and reset self option (button like effect) - L"Allows debug options in release or mapeditor builds", // allow debugging in release or mapeditor - L"Toggle to display debugging render options", // an example option that will show/hide other options - L"Attempts to display slash-rects around mouse regions", // an example of a DEBUG build option + L"Kliknij by naprawi bdy w ustawieniach gry.", // failsafe show/hide option to reset all options + L"Kliknij by naprawi bdy w ustawieniach gry.", // a do once and reset self option (button like effect) + L"Udostpnia tryb debugowania w edytorze map oraz wersji kocowej.", // allow debugging in release or mapeditor + L"Przecz na tryb wywietlania/ukrycia opcji renderowania debugowego.", // an example option that will show/hide other options + L"Wywietl wymiary wok kursora myszy.", // an example of a DEBUG build option L"(text not rendered)TOPTION_DEBUG_MODE_OPTIONS_END", // an example options screen options divider (pure text) @@ -3835,7 +4023,7 @@ STR16 gzGIOScreenText[] = L"Dowiadczony", L"Ekspert", L"SZALONY", - L"Ok", + L"Start", // TODO.Translate L"Anuluj", L"Rozszerzony poziom trudnoci", L"Zapis gry w dowolnym momencie", @@ -3846,33 +4034,81 @@ STR16 gzGIOScreenText[] = L"wietne", L"Wymienite", L"Niewiarygodne", - L"System Inwentarza", - L"Tradycyjny", - L"Rozbudowany", - L"Load MP Game", + L"Ekwipunek / Dodatki", + L"Nie uywany", + L"Nie uywany", + L"Wczytaj gr MP", L"POCZTKOWE USTAWIENIA GRY (Only the server settings take effect)", + // Added by SANDRO + L"Cechy umiejtnoci", + L"Stare", + L"Nowe", + L"Maks. liczba IMP", + L"Jeden", + L"Dwa", + L"Trzy", + L"Cztery", + L"Pi", + L"Sze", + L"Wrogowie upuszczaj cao ekwipunku", + L"Wyczone", + L"Wczone", + L"Liczba terrorystw", + L"Losowe", + L"Wszystkie", + L"Tajne skady proni", + L"Losowe", + L"Wszystkie", + L"Szybko zwikszania dostpnoci przedmiotw", + L"Bardzo wolna", + L"Wolna", + L"Normala", + L"Szybka", + L"Bardzo szybkia", + + L"Stare / Stare", + L"Nowe / Stare", + L"Nowe / Nowe", }; STR16 gzMPJScreenText[] = { L"MULTIPLAYER", - L"Join", - L"Host", - L"Cancel", - L"Refresh", - L"Player Name", - L"Server IP", + L"Docz", + L"Uruchom serwer", + L"Anuluj", + L"Odwie", + L"Nazwa gracza", + L"IP Serwera", L"Port", - L"Server Name", - L"# Plrs", - L"Version", - L"Game Type", + L"Nazwa serwera", + L"# Plrs", // ?? if plrs=players then "# graczy" + L"Wersja", + L"Typ rozgrywki", L"Ping", - L"You must enter a player name", - L"You must enter a valid server IP address.\n (eg 84.114.195.239).", - L"You must enter a valid Server Port between 1 and 65535.", + L"Musisz poda nazw gracza", + L"Musisz poda odpowiedni numer IP serwera.\n (np. 84.114.195.239).", + L"Musisz poda odpowiedni port serwera pomidzy 1 i 65535.", }; +// TODO.Translate +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { L"HOST GAME", @@ -3881,35 +4117,72 @@ STR16 gzMPHScreenText[] = L"Server Name", L"Game Type", L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"Max Players", - L"Squad Size", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", L"Merc Selection", - L"Random Mercs", + L"Merc Hiring", L"Hired by Player", - L"Starting Balance", - L"Can Hire Same Merc", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"Allow Bobby Rays", - L"Randomise Starting Edge", + L"Bobby Rays", + L"Sector Starting Edge", L"You must enter a server name", - L"Max Players must be between 2 and 4", - L"Squad size must be between 1 and 6", - L"Time of Day", - L"Time of Day must be a 24 hour time (HH:MM)", - L"Starting Cash must be a valid dollar amount (no cents)" , - L"Damage Multiplier", - L"Damage Multiplier must be a number between 0 and 5", - L"Turn Timer Multiplier", - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", L"Enable Civilians in CO-OP", - L"Use New Inventory (NIV)", - L"Sync. MP Clients Directory", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", L"MP Sync. Directory", L"You must enter a file transfer directory.", L"(Use '/' instead of '\\' for directory delimiters.)", L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4087,8 +4360,8 @@ STR16 pMessageStrings[] = L"Lista historii zaktualizowana.", L"Seria z granatnika uywa kursora celowania (dostpny ogie rozproszony)", //L"Grenade Bursts use Targeting Cursor (Spread fire enabled)", BYO -->>L"Grenade Bursts - Using Targeting Cursor (Spread fire enabled)", L"Seria z granatnika uywa kursora trajektorii (dostpny ogie rozproszony)", //L"Grenade Bursts use Trajectory Cursor (Spread fire disabled)", BYO -->L"Grenade Bursts - Using Trajectory Cursor (Spread fire disabled)", - L"Upuszczanie wszystkiego wczone", - L"Upuszczanie wszystkiego wyczone", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"Granatniki strzelaj pod standardowymi ktami", //L"Grenade Launchers fire at standard angles", BYo->>L"Grenade Launchers - Fire at standard angles", L"Granatniki strzelaj pod wysokimi ktami", //L"Grenade Launchers fire at higher angles", BYo-->>L"Grenade Launchers - Fire at high angles", // forced turn mode strings @@ -4101,6 +4374,8 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved. L"Client", + + L"Nie moesz uywa nowego trybu wyposaenia i nowego systemu dodatkw jednoczenie.", }; @@ -4308,10 +4583,10 @@ STR16 sRepairsDoneString[] = L"%s skoczy(a) naprawia wasne wyposaenie", L"%s skoczy(a) naprawia bro i ochraniacze wszystkich czonkw oddziau", L"%s skoczy(a) naprawia wyposaenie wszystkich czonkw oddziau", - L"%s finished repairing everyone's large carried items", - L"%s finished repairing everyone's medium carried items", - L"%s finished repairing everyone's small carried items", - L"%s finished repairing everyone's LBE gear", + L"%s skoczy(a) naprawia cikie wyposaenie wszystkich czonkw oddziau", + L"%s skoczy(a) naprawia rednie wyposaenie wszystkich czonkw oddziau", + L"%s skoczy(a) naprawia lekkie wyposaenie wszystkich czonkw oddziau", + L"%s skoczy(a) naprawia strj LBE wszystkich czonkw oddziau", }; STR16 zGioDifConfirmText[]= @@ -4431,7 +4706,7 @@ STR16 gzLateLocalizedString[] = //46-48 L"%s - przeduka lufy jego/jej broni odpada!", - L"No more than %d militia trainers are permitted in this sector.", // TODO.Translate + L"W tym sektorze moe by maks. %d instruktorw szkolcych samoobron.", L"Na pewno?", //49-50 @@ -4464,12 +4739,12 @@ STR16 gzLateLocalizedString[] = L"%s: dodatki do pancerza zostay zniszczone!", L"%s wystrzeli(a) %d pocisk(w) wicej ni to byo zamierzone!", - L"%s wystrzeli(a) %d pocisk(w) wicej ni to byo zamierzone!", + L"%s wystrzeli(a) 1 pocisk(w) wicej ni to byo zamierzone!", }; STR16 gzCWStrings[] = { - L"Call reinforcements to %s from adjacent sectors?", // TODO.Translate + L"Wezwa posiki do %s z przylegych sektorw?", }; // WANNE: Tooltips @@ -4515,6 +4790,10 @@ STR16 gzTooltipStrings[] = L"brak kamizelki", L"brak getrw ochronnych", L"|Pancerz: %s\n", + // Added - SANDRO + L"%s|Umiejtno 1: %s\n", + L"%s|Umiejtno 2: %s\n", + L"%s|Umiejtno 3: %s\n", }; STR16 New113Message[] = @@ -4539,43 +4818,61 @@ STR16 New113Message[] = L"Wszystkie przedmioty tego typu sprzedane", L"Sprawd swoje gogle", // Real Time Mode messages - L"In combat already", - L"No enemies in sight", - L"Real-time sneaking OFF", - L"Real-time sneaking ON", - L"Enemy spotted! (Ctrl + x to enter turn based)", + L"W trakcie walki", + L"Brak wrogw w zasigu wzroku", + L"Wyczone skradanie w czasie rzeczywistym", + L"Wczone skradanie w czasie rzeczywistym", + //L"Spotkano wroga! (Ctrl + x by uruchomi tryb turowy)", + L"Spotkano wroga!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s dokona(a) udanej kradziey!", + L"%s nie posiada wystarczajcej liczby PA by ukra wszystkie zaznaczone przedmioty.", + L"Chcesz operowa %s zanim uyjesz banday? (moesz przywrci okoo %i punktw zdrowia.)", + L"Chcesz operowa %s zanim uyjesz banday? (moesz przywrci okoo %i punktw zdrowia.)", + L"Czy chcesz najpierw operowa przed uyciem banday? (%i pacjent(w))", + L"Czy chcesz najpierw operowa pacjenta?", + L"Czy podczas udzielania pierwszej pomocy wykonywa niezbdne operacje?", + L"operacja na %s zakoczona.", + L"%s otrzymuje trafienie w korpus i traci punkt maksymalnego zdrowia!", + L"%s otrzymuje trafienie w korpus i traci %d punktw maksymalnego zdrowia!", + L"%s odzyska(a) utracony punkt %s", + L"%s odzyska(a) %d utraconych punktw %s", + L"Twoja umiejtno zwiadowcy uchronia ci przed zasadzk!", + L"Twoja umiejtno zwiadowcy pozwolia ci omin stado krwawych kotw!", + L"%s zosta trafiony w pachwin i pada na ziemi!", + ////////////////////////////////////////////////////////////////////////////// }; -// TODO.Translate STR16 New113HAMMessage[] = { // 0 - 5 - L"%s cowers in fear!", - L"%s is pinned down!", - L"%s fires more rounds than intended!", - L"You cannot train militia in this sector.", - L"Militia picks up %s.", - L"Cannot train militia with enemies present!", + L"%s kuli si ze strachu!", + L"%s zosta przyparty do muru!", + L"%s odda(a) wicej strzaw ni zamierza(a)!", + L"Nie moesz szkoli samoobrony w tym sektorze.", + L"Samoobrona znajduje %s.", + L"Nie mona szkoli samoobrony, gdy wrg jest w sektorze!", // 6 - 10 - L"%s lacks sufficient Leadership score to train militia.", - L"No more than %d Mobile Militia trainers are permitted in this sector.", - L"No room in %s or around it for new Mobile Militia!", - L"You need to have %d Town Militia in each of %s's liberated sectors before you can train Mobile Militia here.", - L"Can't staff a facility while enemies are present!", + L"%s Brak odpowiednich umiejtnoci dowodzenia do szkolenia samoobrony.", + L"W tym sektorze jest dozwolonych nie wicej ni %d instruktorw samoobrony.", + L"W %s oraz okolicy nie ma miejsca dla nowych oddziaw samoobrony!", + L"Musisz mie conajmniej %d jednostek samoobrony w kadym z %s wyzwolonych sektorw zanim bdziesz mg szkoli tu nowe oddziay.", + L"Nie moesz obsadzi fabryki dopki w okolicy s wrogie jednostki!", // not sure // 11 - 15 - L"%s lacks sufficient Wisdom to staff this facility.", - L"The %s is already fully-staffed.", - L"It will cost $%d per hour to staff this facility. Do you wish to continue?", - L"You have insufficient funds to pay for all Facility work today. $%d have been paid, but you still owe $%d. The locals are not pleased.", - L"You have insufficient funds to pay for all Facility work today. You owe $%d. The locals are not pleased.", + L"%s zbyt niska inteligencja do obsadzenia tej fabryki.", + L"%s posiada ju maksymaln liczb personelu.", + L"Obsadzenie tej fabryki bdzie kosztowa $%d za godzin. Chcesz kontynuowa?", + L"Nie posiadasz funduszy potrzebnych na opacenie wszystkich fabryk. Zapacono $%d, ale wci pozostao $%d do zapaty. Tubylcy s zaniepokojeni.", + L"Nie posiadasz funduszy potrzebnych na opacenie wszystkich fabryk. Pozostao $%d do zapaty. Tubylcy s zaniepokojeni.", // 16 - 20 - L"You have an outstanding debt of $%d for Facility Operation, and no money to pay it off!", - L"You have an outstanding debt of $%d for Facility Operation. You can't assign this merc to facility duty until you have enough money to pay off the entire debt.", - L"You have an outstanding debt of $%d for Facility Operation. Would you like to pay it all back?", - L"N/A in this sector", - L"Daily Expenses", + L"Zalegasz $%d dla Fabryki i nie posiadasz funduszy umoliwiajcych spat dugu!", + L"Zalegasz $%d dla Fabryki!. Nie moesz przydzieli tego najemnika do fabryki do momentu spaty dugu.", + L"Zalegasz $%d dla Fabryki!. Czy chcesz spaci ten dug?", + L"Niedostpny w tym sektorze", + L"Dzienne wydatki", // 21 - 25 - L"Insufficient funds to pay all enlisted militia! %d militia have disbanded and returned home.", + L"Brak funduszy do opacenia wykazanych jednostek samoobrony! %d jednostek opuszcza oddziay i wraca do domu.", }; // WANNE: This are the email texts, when one of the 4 new 1.13 MERC mercs have levelled up, that Speck sends @@ -4592,6 +4889,43 @@ STR16 New113MERCMercMailTexts[] = L"Prosz o zwrcenie uwagi, i w zwizku ze wzrostem jakoci usug wiadczonych przez pana Biggens`a jego pensja take ulega podwyszeniu. Speck T. Kline ", }; +// TODO.Translate +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"PD z Serwera AIM: Wiadomo od - Victor Kolesnikov", + L"Hej, tu Monk. Dostaem Twoj wiadomo. Ju jestem z powrotem - jeli chcesz si skontaktowa. Zadzwo. ", + + // Brain + L"PD z Serwera AIM: Wiadomo od - Janno Allik", + L"Jestem ju gotw do przyjcia nowego zadania. Wszystko musi mie swoj por. Janno Allik ", + + // Scream + L"PD z Serwera AIM: Wiadomo od - Lennart Vilde", + L"Lennart Vilde jest obecnie dostpny! ", + + // Henning + L"PD z Serwera AIM: Wiadomo od - Henning von Branitz", + L"Otrzymaem Twoj wiadomo, dzikuj. Jeli chcesz omwi moliwo zatrudnienia, skontaktuj si ze mn za porednictwem strony AIM . Na razie! Henning von Branitz ", + + // Luc + L"PD z Serwera AIM: Wiadomo od - Luc Fabre", + L"Otrzymaem wiadomo, merci! Chtnie rozwa Twoje propozycje. Wiesz, gdzie mnie znale. Oczekuj odpowiedzi ", + + // Laura + L"PD z Serwera AIM: Wiadomo od - Laura Colin", + L"Pozdrowienia! Dobrze, e zostawie wiadomo. Sprawa wyglda interesujco. Zajrzyj jeszcze raz do AIM. Chtnie poznam wicej informacji. Wyrazy szacunku Dr Laura Colin ", + + // Grace + L"PD z Serwera AIM: Wiadomo od - Graziella Girelli", + L"Chciae si ze mn skontaktowa, ale Ci si nie udao. Miaam spotkanie rodzinne, na pewno to rozumiesz. Teraz mam ju do swojej rodziny i bardzo si uciesz, jeli skontaktujesz si ze mn ponownie za porednictwem witryny AIM . Ciao! ", + + // Rudolf + L"PD z Serwera AIM: Wiadomo od - Rudolf Steiger", + L"Wiesz, ile telefonw odbieram kadego dnia? Co drugi baran myli, e moe do mnie wydzwania. W kadym razie ju jestem, jeli masz dla mnie co ciekawego.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4600,6 +4934,25 @@ STR16 MissingIMPSkillsDescriptions[] = L"Snajper: Sokole oczy! Moesz odstrzeli skrzyda muszce ze stu jardw. ", // Camouflage L"Kamufla: Przy tobie nawet krzaki wygldaj na sztuczne! ", + // SANDRO - new strings for new traits added + // Ranger + L"Stranik: To ty jeste tym z pustyni Teksasu! ", + // Gunslinger + L"Rewolwerowiec: Z pistoletem lub dwoma, moesz by tak miercionony jak Billy Kid! ", + // Squadleader + L"Przywdca: Urodzony dowdca i szef, jeste naprawd grub ryb bez kitu! ", + // Technician + L"Mechanik: Naprawa sprztu, rozbrajanie puapek, podkadanie bomb, to twoja dziaka! ", + // Doctor + L"Chirurg: Moesz przeprowadzi skomplikowan operacj przy uyciu scyzoryka i gumy do ucia! ", + // Athletics + L"Atleta: Kondycji mgby ci pozazdroci niejeden maratoczyk! ", + // Bodybuilding + L"Budowa ciaa: Ta ogromna muskularna posta, ktrej nie sposb przeoczy, to w rzeczy samej ty! ", + // Demolitions + L"Materiay wybuchowe: Potrafisz wysadzi miasto przy uyciu standardowego wyposaenia kuchni! ", + // Scouting + L"Zwiadowca: Nic nie umknie twej uwadze! ", }; STR16 NewInvMessage[] = @@ -4630,15 +4983,15 @@ STR16 MPServerMessage[] = L"adowanie klientw, czekaj.", L"Nie mona zmienia miejsc zrzutu po starcie serwera.", // 10 - L"Sent file '%S' - 100/100", - L"Finished sending files to '%S'.", - L"Started sending files to '%S'.", + L"Wysano '%S' pliku - 100/100", + L"Zakoczono wysyanie plikw do '%S'.", + L"Rozpoczto wysyanie plikw do '%S'.", }; STR16 MPClientMessage[] = { // 0 - L"Inicjacja klienta RakNet", + L"Inicjacja klienta RakNet", L"czenie z IP: %S ...", L"Otrzymano ustawienia:", L"Jeste ju poczony.", @@ -4665,13 +5018,12 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"Numer siatki %d", L"Waciwoci serwera", - L"Ustaw rcznie stopie nadrzdnoci serwera: 1 w.laptop/rekrut.; 2- w./aduj poziom; 3 odblok. UI; 4 koczy rozmieszczanie", - //L"Sektor=%s, MaxKlientw=%d, Max Najem=%d, Tryb_Gry=%d, TenSamNaj=%d, Mnonik obra.=%f, Wrogw=%d, Stworze=%d, Milicji=%d, Cywili=%d, TuryCzasowe=%d, Sek/ruch=%d, Kasa na start=$%d, Kupa broni=%d, Sci-Fi=%d, Trudno=%d, Iron-Man=%d, Zasb BobbyRays=%d, Wy BobbyRay=%d, Wy ekwip Aim/Merc=%d, Wy morale=%d, Test=%d", + L"Ustaw rcznie stopie nadrzdnoci serwera: 1 w.laptop/rekrut.; 2- w./aduj poziom; 3 odblok. UI; 4 koczy rozmieszczanie", L"Sektor=%s, MaxKlientw=%d, Max Najem=%d, Tryb_Gry=%d, TenSamNaj=%d, Mnonik obra.=%f, TuryCzas=%d, Sek/ruch=%d, Dis BobbyRay=%d, Wy Aim/Merc Ekwip=%d, Wy morale=%d, Test=%d", // 25 - L"Test, funkcja cheatw '9' jest wczona.", + L"", L"Nowe poczenie Client #%d - '%S'.", - L"Team: %d.",//not used any more + L"Druyna: %d.",//not used any more L"'%s' (klient %d - '%S') zabity przez '%s' (client %d - '%S')", L"Wyrzucono #%d - '%S'", // 30 @@ -4693,68 +5045,55 @@ STR16 MPClientMessage[] = L"Wspinanie wyczone w MP", L"Wynajto '%s'", // 45 - L"You cant change the map once purchasing has commenced", - L"Map changed to '%s'", - L"Client '%s' disconnected, removing from game", - L"You were disconnected from the game, returning to the Main Menu", - L"Connection failed, Retrying in 5 seconds, %i retries left...", + L"Nie moesz zmieni mapy w trakcie dokonywania zakupu", + L"Mapa zmieniona na '%s'", + L"Klient '%s' rozczony, usuwanie z gry", + L"Zostae rozczony, powrt do gwnego menu", + L"Prba poczenia zakoczona niepowodzeniem, kolejna porba za 5 sekund, %i prb pozostao...", //50 - L"Connection failed, giving up...", - L"You cannot start the game until another player has connected", + L"Prba poczenia zakoczona niepowodzeniem, rezygnacja z kolejnych prb...", + L"Nie moesz rozpocz gry dopki nie s podczeni inni gracze", L"%s : %s", - L"Send to All", - L"Allies only", + L"Wylij do wszystkich", + L"Wylij do sprzymierzecw", // 55 - L"Cannot join game. This game has already started.", - L"%s (team): %s", + L"Nie mona doczy do gry. Ta gra ju si rozpocza", + L"%s (druyna): %s", L"#%i - '%s'", L"%S - 100/100", L"%S - %i/100", // 60 - L"Received all files from server.", - L"'%S' finished downloading from server.", - L"'%S' started downloading from server.", - L"Cannot start the game until all clients have finished receiving files", - L"This server requires that you download modified files to play, do you wish to continue?", + L"Pobrano wszystkie pliki z serwera.", + L"Pobrano '%S' z serwera", + L"Rozpoczto pobieranie '%s' z serwera", + L"Nie mona rozpocz gry dopki wszyscy nie zakocz pobierania plikw z serwera", + L"Ten serwer przed rozpoczciem gry wymaga pobrania zmodyfikowanych plikw, czy chcesz kontynuowa", // 65 - L"Press 'Ready' to enter tactical screen.", - L"Cannot connect because your version %S is different from the server version %S.", - L"You killed an enemy soldier.", - L"Cannot start the game, because all teams are the same.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Witaj w JAGGED ALLIANCE 2 v1.13 Multiplayer", - L"F1 - pomoc ", - L"Przyciski mutliplayera (ekran strategii)", - L"* Ustaw ja2_mp.ini *", - L"'1' - W. serwer", - // 5 - L"'2' - Pocz z serwerem", - L"'3' - Gdy serwer odblokuje laptopa, ustaw gotw do bitwy", - L"'4' - Opu serwera i klient", - L"'5' - Poka pooenie myszy (ekr. taktyczny)", - L"'7' - Pop-up dla komunikatw serwera", - // 10 - L"'F2' - Wywietl 2. pomoc", - L"Czytaj readme_mp.html po wicej info.", - L"Tip: (gdy ja2_mp.ini jest ustawione)", - L"* Upewnij si e wszyscy maj rne CLIENT_NUM *", - L"* Gra nie zapisuje porzdku w Bobby rays *", - // 15 - L"* Nie ustawiaj przeciwnikw w zasigu ich wzroku *", - L"'F1' - Wywietl 1. pomoc", + L"Nacinij 'Gotowe' aby przej do ekranu taktycznego", + L"Nie mona si poczy poniewa twoja wersja %S rni si od wersji %S na serwerze.", + L"Zabie wrog jednostk", + L"Nie mona doczy do gry. Ta gra ju si rozpocza", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 // TODO.Translate + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; STR16 gszMPEdgesText[] = { - L"N", - L"S", - L"E", - L"W", - L"C", // "C"enter + L"Pn", - Pnoc + L"Pd", - Poudnie + L"W", - Wschd + L"Z", - Zachd + L"C", // "C" - Centralny }; STR16 gszMPTeamNames[] = @@ -4763,237 +5102,266 @@ STR16 gszMPTeamNames[] = L"Bravo", L"Delta", L"Charlie", - L"N/D", // Acronym of Not Applicable + L"N/D", // Acronym of Not Applicable }; STR16 gszMPMapscreenText[] = { - L"Game Type: ", - L"Players: ", + L"Tryb gry: ", + L"Gracze: ", L"Mercs each: ", - L"You cannot change starting edge once Laptop is unlocked.", - L"You cannot change teams once the Laptop is unlocked.", - L"Random Mercs: ", - L"Y", - L"Difficulty:", - L"Server Version:", + L"Nie moesz zmieni pocztkowego wierzchoka dopki laptop jest odblokowany.", + L"Nie moesz zmienia druyn dopki laptop jest odblokowany.", + L"Losowi najemnicy: ", + L"T", //if "Y" means Yes here + L"Poziom trudnoci:", + L"Wersja serwera:", }; STR16 gzMPSScreenText[] = { - L"Scoreboard", - L"Continue", - L"Cancel", - L"Player", - L"Kills", - L"Deaths", - L"Queen's Army", - L"Hits", - L"Misses", - L"Accuracy", - L"Damage Dealt", - L"Damage Taken", - L"Please wait for the server to press 'Continue'." + L"Tabela punktw", + L"Kontynuuj", + L"Anuluj", + L"Gracz", + L"Zabitych", + L"Liczba zgonw", + L"Armia krlowej", + L"Trafienia", + L"Strzay chybione", + L"Celno", + L"Obraenia zadane", + L"Obraenia otrzymane", + L"Czekaj na poczenie z serwerem aby nacisn 'Kontynuuj'", }; STR16 gzMPCScreenText[] = { - L"Cancel", - L"Connecting to Server", - L"Getting Server Settings", - L"Downloading custom files", - L"Press 'ESC' to cancel or 'Y' to chat", - L"Press 'ESC' to cancel", - L"Ready" + L"Anuluj", + L"czenie z serwerem", + L"Pobieranie ustawie serwera", + L"Pobieranie plikw", + L"Nacinij 'ESC' aby anulowa lub 'Y' aby wej na chat", + L"Nacinij 'ESC'aby anuowa", + L"Gotowe", }; STR16 gzMPChatToggleText[] = { - L"Send to All", - L"Send to Allies only", + L"Wylij do wszystkich", + L"Wylij do sprzymierzecw", }; STR16 gzMPChatboxText[] = { L"Multiplayer Chat", - L"Chat: Press 'ENTER' to send of 'ESC' to cancel.", + L"Chat: Nacinij 'ENTER' aby wysa lub 'ESC' by anulowa", }; // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected. To achieve an expert level on a trait, simply choose only that one trait.", - L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels, and if you choose one of them only, you will have only one skill trait.", + // Odnonie starych umiejtnoci + L"Na nastpnej stronie, wybierzesz umiejtnoci dotyczce twojej specjalizacji jako najemnika. Nie mona wybra wicej ni dwch rnych umiejtnoci, albo jednej w stopniu eksperta.", + + //L"Moesz take wybra jedn, albo nawet nie wybra adnej umiejtnoci, co da ci bonus do liczby punktw atrybutw. Zauwa, e elektronika i oburczno nie mog by wybrane w stopniu eksperta.", + + // TODO.Translate (added Camouflage) + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics, Ambidextrous and Camouflage traits cannot be achieved at expert levels.", + + // Odnonie nowych/pomniejszych umiejtnoci + L"Nastpny etap dotyczy wybierania umiejtnoci dotyczcych twojej specjalizacji jako najemnika. Na pierwszej stronie, moesz wybra do dwch gwnych umiejtnoci, ktre reprezentuj twoj rol w zespole. Druga strona to lista pomniejszych cech, ktre reprezentuj twoj osobowo.", + L"Wybranie wicej ni trzech jednoczenie jest niemoliwe. Oznacza to, e jeeli nie wybierzesz adnych gwnych umiejtnoci, moesz wybra trzy pomniejsze cechy. Jeli wybierzesz 2 gwne umiejtnoci (albo jedn zaawansowan), moesz wybra tylko jedn cech dodatkow...", }; STR16 sgAttributeSelectionText[] = { - L"Please adjust your physical attributes as comapred to that of an avarage merc. You cannot raise any score above", - L"I.M.P. Attributes and skills review.", - L"Bonus Pts.:", - L"Starting Level", + L"Prosz, wybierz swoje atrybuty fizyczne zgodnie z twoimi prawdziwymi umiejtnociami. Nie moesz podnie adnego z powyszych wynikw.", + L"Przegld atrybutw i umiejtnoci I.M.P..", + L"Punkty bonusowe.:", + L"Poziom startowy", + // New strings for new traits + L"Na nastpnej stronie wybierzesz swoje atrybuty fizyczne i umiejtnoci. 'Atrybuty' to: zdrowie, zwinno, zrczno, sia oraz inteligencja. Atrybuty nie mog by nisze ni %d.", + L"Reszta to 'umiejtnoci', w przeciwiestwie do atrybutw, mog by ustawione na zero, co oznacza, e nie masz w nich kompletnie adnej wprawy.", + L"Wszystkie punkty s na pocztku ustawione na minimum. Zauwa, e niektre atrybuty s ustawione na wartociach, co ma zwizek z wczeniej wybranymi umiejtnociami. Nie moesz ustawi ich niej.", }; STR16 pCharacterTraitBeginIMPStrings[] = { - L"I.M.P. Character Analysis", - L"The analysis of your character is the next step on your profile creation. On the first page you will be shown a list of attitudes to choose. We imagine you could identify yourself with more of them, but here you will be able to pick only one. Choose the one which you feel aligned with mostly. ", - L"The second page enlists possible disabilities you might have. If you suffer from any of these disabilities, choose which one (we believe that everyone has only one such disablement). Be honest, as it is important to inform potential employers of your true condition.", + L"Analiza charakteru I.M.P.", + L"Analiza charakteru to nastpny krok w tworzeniu twojego profile. Na pierwszej stronie zostanie ci przedstawiona lista cech charakteru do wybrania. Domylamy si, e moesz identyfikowa si z wiksz ich iloci, jednak bdziesz mg wybra tylko jedn. Wybierz tak, z ktr czujesz si najbardziej zwizany.", + L"Druga strona przedstawia list niepenosprawnoci, na ktre moesz cierpie. Jeli cierpisz na jedn z nich, wybierz j (wierzymy, e kady ma tylko jedn tak niepenosprawno). Bd szczery, poniewa to wane, by poinformowa potencjalnych pracodawcw o twoim faktycznym stanie zdrowia.", +}; + +STR16 gzIMPAttitudesText[]= +{ + L"Normalny", + L"Przyjazny", + L"Samotnik", + L"Optymista", + L"Pesymista", + L"Agresywny", + L"Arogancki", + L"Gruba ryba", + L"Dupek", + L"Tchrz", + L"Nastawienie I.M.P.-a", }; STR16 gzIMPCharacterTraitText[]= { - L"Normal", - L"Friendly", - L"Loner", - L"Optimist", - L"Pessimist", - L"Aggressive", - L"Arrogant", - L"Big Shot", - L"Asshole", - L"Coward", - L"I.M.P. Character Traits", + L"Normalny", + L"Towarzyski", + L"Samotnik", + L"Optymista", + L"Asertywny", + L"Intelektualista", + L"Prymityw", + L"Agresywny", + L"Flegmatyk", + L"Nieustraszony", + L"Pacyfista", + L"Podstpny", + L"Gwiazdor", + L"Cechy charakteru I.M.P.-a", }; STR16 gzIMPColorChoosingText[] = { - L"I.M.P. Colors and Body Type", - L"I.M.P. Colors", - L"Please select the respective colors of your skin, hair and clothing. And select what body type you have.", - L"Please select the respective colors of your skin, hair and clothing.", - L"Toggle this to use alternative rifle holding.", + L"Kolory i sylwetka ciaa I.M.P.-a", + L"Kolory I.M.P.", + L"Prosz wybra odpowiednie kolory skry, wosw i ubra oraz swoj sylwetk ciaa.", + L" Prosz wybra odpowiednie kolory skry, wosw i ubra.", + L"Zaznacz, by uywa alternatywnego sposobu trzymania broni.", + L"\n(Uwaga: bdziesz potrzebowa do tego duej siy.)", }; STR16 sColorChoiceExplanationTexts[]= { - L"Hair Color", - L"Skin Color", - L"Shirt Color", - L"Pants Color", - L"Normal Body", - L"Big Body", + L"Kolor wosw", + L"Kolor skry", + L"Kolor koszulki", + L"Kolor spodni", + L"Normalne ciao", + L"Due ciao", }; STR16 gzIMPDisabilityTraitText[]= { - L"No Disability", - L"Heat Intolerant", - L"Nervous", - L"Claustrophobic", - L"Nonswimmer", - L"Fear of Insects", - L"Forgetful", - L"Psychotic", - L"I.M.P. Disabilities", + L"Bez niepenosprawnoci", + L"Nie lubi ciepa", + L"Nerwowy", + L"Klaustrofobik", + L"Nie umie pywa", + L"Boi si owadw", + L"Zapominalski", + L"Psychol", + L"Niepenosprawnoci I.M.P.-a", }; -// TODO.Translate // HEADROCK HAM 3.6: Error strings for assigning a merc to a facility STR16 gzFacilityErrorMessage[]= { - L"%s lacks sufficient Strength to perform this task.", - L"%s lacks sufficient Dexterity to perform this task.", - L"%s lacks sufficient Agility to perform this task.", - L"%s is not Healthy enough to perform this task.", - L"%s lacks sufficient Wisdom to perform this task.", - L"%s lacks sufficient Marksmanship to perform this task.", + L"%s nie ma wystarczajcej siy, by tego dokona", + L"%s nie ma wystarczajcej zrcznoci, by tego dokona", + L"%s nie ma wystarczajcej zwinnoci, by tego dokona", + L"%s nie ma do zdrowia, by tego dokona", + L"%s nie ma wystarczajcej inteligencji, by tego dokona", + L"%s nie ma wystarczajcej celnoci, by tego dokona", // 6 - 10 - L"%s lacks sufficient Medical Skill to perform this task.", - L"%s lacks sufficient Mechanical Skill to perform this task.", - L"%s lacks sufficient Leadership to perform this task.", - L"%s lacks sufficient Explosives Skill to perform this task.", - L"%s lacks sufficient Experience to perform this task.", + L"%s nie ma wystarczajcych um. medycznych, by tego dokona.", + L"%s nie ma wystarczajcych um. mechaniki, by tego dokona.", + L"%s nie ma wystarczajcych um. dowodzenia, by tego dokona.", + L"%s nie ma wystarczajcych um. mat. wyb., by tego dokona.", + L"%s nie ma wystarczajcego dowiadczenia, by tego dokona.", // 11 - 15 - L"%s lacks sufficient Morale to perform this task.", - L"%s is too exhausted to perform this task.", - L"Insufficient loyalty in %s. The locals refuse to allow you to perform this task.", - L"Too many people are already working at the %s.", - L"Too many people are already performing this task at the %s.", + L"%s ma za mae morale, by tego dokona", + L"%s nie ma wystarczajco duo energii, by tego dokona", + L"W %s jest zbyt maa lojalno. Mieszkacy nie pozwol ci tego zrobi.", + L"W %s pracuje ju zbyt wiele osb.", + L"W %s zbyt wiele osb wykonuje ju to polecenie.", // 16 - 20 - L"%s can find no items to repair.", - L"%s has lost some %s while working in sector %s!", - L"%s has lost some %s while working at the %s in %s!", - L"%s was injured while working in sector %s, and requires immediate medical attention!", - L"%s was injured while working at the %s in %s, and requires immediate medical attention!", + L"%s nie znajduje przedmiotw do naprawy.", + L"%s traci nieco %s, pracujc w sektorze %s", + L"%s traci nieco %s, pracujc w %s w sektorze %s", + L"%s odnosi rany, pracujc w sektorze %s i wymaga natychmiastowej pomocy medycznej!", + L"%s odnosi rany, pracujc w %s w sektorze %s i wymaga natychmiastowej pomocy medycznej!", // 21 - 25 - L"%s was injured while working in sector %s. It doesn't seem too bad though.", - L"%s was injured while working at the %s in %s. It doesn't seem too bad though.", - L"The residents of %s seem upset about %s's presence.", - L"The residents of %s seem upset about %s's work at the %s.", - L"%s's actions in sector %s have caused loyalty loss throughout the region!", + L"%s odnosi rany, pracujc w sektorze %s. Nie wyglda to jednak bardzo powanie.", + L"%s odnosi rany, pracujc w %s w sektorze %s. Nie wyglda to jednak bardzo powanie.", + L"Mieszkacy miasta %s wydaj si poirytowani tym, e %s przebywa w ich okolicy.", + L"Mieszkacy miasta %s wydaj si poirytowani tym, e %s pracuje w %s.", + L"%s po swych dziaaniach w sektorze %s powoduje spadek poparcia w regionie.", // 26 - 30 - L"%s's actions at the %s in %s have caused loyalty loss throughout the region!", - L"%s is drunk.", // <--- This is a log message string. - L"%s has become severely ill in sector %s, and has been taken off duty.", - L"%s has become severely ill and cannot continue his work at the %s in %s.", - L"%s was injured in sector %s.", // <--- This is a log message string. + L"%s swymi dziaaniami w %s w %s powoduje spadek poparcia w regionie.", + L"%s jest w stanie upojenia alkoholowego", + L"%s ciko choruje w sektorze %s i przechodzi w stan spoczynku", + L"%s cizko choruje i nie moe dalej pracowa w %s w %s", + L"%s doznaje cikich obrae w sektorze %s", // %s was injured in sector %s. // <--- This is a log message string. // 31 - 35 - L"%s was severely injured in sector %s.", //<--- This is a log message string. + L"%s doznaje cikich obrae w sektorze %s", //<--- This is a log message string. }; -// TODO.Translate STR16 gzFacilityRiskResultStrings[]= { - L"Strength", - L"Agility", - L"Dexterity", - L"Wisdom", - L"Health", - L"Marksmanship", + L"Sia", + L"Zwinno", + L"Zrczno", + L"Inteligencja", + L"Zdrowie", + L"Umiejtnoci strzeleckie", //short: "Um. strzeleckie" // 5-10 - L"Leadership", - L"Mechanical skill", - L"Medical skill", - L"Explosives skill", + L"Umiejtno dowodzenia", //short: "Um. dowodzenia" + L"Znajomo mechaniki", //short: "Zn. mechaniki" + L"Wiedza medyczna", + L"Znajomo materiaw wybuchowych", //short: "Zn. mat. wybuchowych" }; -// TODO.Translate STR16 gzFacilityAssignmentStrings[]= { L"AMBIENT", L"Staff", - L"Rest", - L"Repair Items", - L"Repair %s", // Vehicle name inserted here - L"Repair Robot", + L"Odpoczywa" + L"Naprawa ekwipunku", + L"Naprawa %s", + L"Naprawa Robota", // 6-10 - L"Doctor", - L"Patient", - L"Practice Strength", - L"Practice Dexterity", - L"Practice Agility", - L"Practice Health", + L"Lekarz", + L"Pacjent", + L"Trening siy", + L"Trening zrcznoci", + L"Trening zwinnoci", + L"Trening zdrowia", // 11-15 - L"Practice Marksmanship", - L"Practice Medical", - L"Practice Mechanical", - L"Practice Leadership", - L"Practice Explosives", + L"Trening um. strzeleckich", + L"Trening wiedzy medycznej", + L"Trening zn. mechaniki", + L"Trening dowodzenia", + L"Trening zn. mat. wybuchowych", // 16-20 - L"Student Strength", - L"Student Dexterity", - L"Student Agility", - L"Student Health", - L"Student Marksmanship", + L"Ucze sia", + L"Ucze zrczno", + L"Ucze zwinno", + L"Ucze zdrowie", + L"Ucze um. strzeleckie", // 21-25 - L"Student Medical", - L"Student Mechanical", - L"Student Leadership", - L"Student Explosives", - L"Trainer Strength", + L"Ucze wiedza medyczna", + L"Ucze zn. mechaniki", + L"Ucze um. dowodzenia", + L"Ucze zn. mat. wybuchowych", + L"Instruktor sia", // 26-30 - L"Trainer Dexterity", - L"Trainer Agility", - L"Trainer Health", - L"Trainer Marksmanship", - L"Trainer Medical", + L"Instruktor zrczno", + L"Instruktor zwinno", + L"Instruktor zdrowie", + L"Instruktor um. strzeleckie", + L"Instruktor wiedza medyczna", // 30-35 - L"Trainer Mechanical", - L"Trainer Leadership", - L"Trainer Explosives", + L"Instruktor zn. mechaniki", + L"Instruktor um. dowodzenia", + L"Instruktor zn. mat. wybuchowych", }; STR16 Additional113Text[]= @@ -5001,4 +5369,498 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 trybie okienkowym wymaga gbi koloru 16-bitowego lub mniej.", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Masz cwelu!", + L"A masz!", + L"Naryj si!", + L"Jestecie moi!", + L"Zdychaj!", + L"Boisz si kurwo?", + L"To dopiero zaboli!", + L"Dawaj skurwielu!", + L"Dawaj! Nie mam caego dnia!", + L"Chod do tatusia!", + L"Zaraz pjdziesz do piachu!", + L"Wracasz do domu w dbowej jesionce frajerze!", + L"Chcesz si zabawi?" + L"Trzeba byo zosta w domu kurwo." + L"Ciota!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"Urzdzamy grilla.", + L"Mam dla ciebie prezent.", + L"Bum!", + L"Umiech!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"ap!", + L"A masz!", + L"Przysza kryska na Matyska!", + L"To dla ciebie!", + L"Hahahaha!", + L"ap winio!", + L"Uwielbiam to.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"Zedr ci skalp!", + L"Chod do tatusia.", + L"Pochwal si flakami!", + L"Porn ci na kawaki!", + L"Skurwysyny!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"Jestemy po uszy w gwnie...", + L"Id do wojska -mwili. Nie ma chuja, nie po to!", + L"Mam ju do.", + L"O mj Boe.", + L"Za to mi nie pac.", + L"Nie wytrzymam tego!", + L"Wrc z kumplami.", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"Syszaem to!", + L"Kto tam?", + L"Co to byo?", + L"Hej! Co do...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"S tutaj!", + L"Czas zacz zabaw." + L"Liczyem na to, e to si nie stanie.", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Au!", + L"U...", + L"To... boli!", + L"Skurwysyny!", + L"Poaujecie... tego.", + L"Co do..!", + L"Teraz si... wkurwiem.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //POLISH diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 8cfede8d..116c4015 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -1,11 +1,13 @@ -#pragma setlocale("RUSSIAN") +//#pragma setlocale("RUSSIAN") #ifdef PRECOMPILEDHEADERS -#include "Utils All.h" + #include "Utils All.h" #else + #include "Language Defines.h" + #if defined( RUSSIAN ) + #include "text.h" + #include "Fileman.h" + #endif #endif -#include "Language Defines.h" -#include "text.h" -#include "Fileman.h" //suppress : warning LNK4221: no public symbols found; archive member will be inaccessible void this_is_the_RussianText_public_symbol(void){;} @@ -107,6 +109,23 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. SirTech uses the "@@@" notation. */ +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Cp. 1/2", //0 + L"Cp. 2/2", + + L"Cp. 1/3", + L"Cp. 2/3", + L"Cp. 3/3", + + L"Cp. 1/1", //5 +}; + +// by Jazz +CHAR16 zGrod[][500] = +{ + L"", //0 // Robot +}; STR16 pCreditsJA2113[] = { @@ -318,6 +337,20 @@ CHAR16 Message[][STRING_LENGTH] = L" ", //no semi auto L" !", L" !", + + L"%s: .", + L"%s: .", + + L"%s: .", + L"%s: .", + + L"%s: .", + L"%s: .", + + L"%s: .", + L"%s: .", + + L" %s .", }; @@ -386,7 +419,7 @@ STR16 pAssignmentStrings[] = L" ", // in transit - abbreviated form L"", // repairing L"", // training themselves - L"", // training a town to revolt + L"", // training a town to revolt L"..", //training moving militia units //M.Militia L"", // training a teammate L"", // being trained by someone else @@ -470,9 +503,12 @@ STR16 pPersonnelAssignmentStrings[] = L" ", L"", L"", - L"", + L"", + L" ", //Training Mobile Militia L"", - L"", + L"", + L" ", //Facility Staff + L"", //Resting at Facility L"", L".", L" ", @@ -513,9 +549,12 @@ STR16 pLongAssignmentStrings[] = L"", L"", L" ", + L" ", //Train Mobiles L"", L"", - L"̸", + L" ", //Staff Facility + L" ", //Resting at Facility + L"", L"", L" ", L" ", // patient in a hospital @@ -758,6 +797,63 @@ STR16 pPersonnelScreenStrings[] = L":", // number of times merc has been wounded L":", L" ", + L":", //Achievements +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L": %d\n", + L": %d\n", + L": %d\n", + L" : %d\n", + L": %d\n", + L": %d\n", + L" : %d\n", + + L": %d\n", + L": %d\n", + L": %d\n", + + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", + L": %d\n", + L" : %d\n", + L" : %d\n", + L" : %d\n", //Ambushes Prevented + L" : %d\n", + + L" : %d\n", + L": %d\n", + L" : %d\n", + L" : %d\n", + L" : %d \n", + + L" : %d\n", + L" : %d\n", + L" : %d\n", + L": %d\n", + L" : %d\n", + L" . : %d\n", //Surgeries Undergoed + L" : %d\n", //Facility Accidents + + L":", + L":", }; @@ -774,18 +870,58 @@ STR16 gzMercSkillText[] = L" ", L" ", L"", - L" ", + L"", L"", L" ", L" ", L"", L"", - L" ()", - L" ()", - L" ()", + //L" ()", + //L" ()", + //L" ()", L"()", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L" ", //No Skill + L"", //Auto Weapons + L"", //Heavy Weapons + L"", //Marksman + L"", //Hunter + L"", //Gunslinger + L"", //Hand to Hand + L"", //Deputy + L"-", //Technician + L"", //Paramedic + // Minor traits + L"", //Ambidextrous + L" ", //Melee + L" ", //Throwing + L" ", //Night Ops + L" ", //Stealthy + L"", //Athletics + L"", //Bodybuilding + L"", //Demolitions + L"", //Teaching + L"", //Scouting + // second names for major skills + L"", //Machinegunner + L"", //Bombardier + L"", //Sniper + L"", //Ranger + L"", //Gunfighter + L" ", //Martial Arts + L"", //Squadleader + L"", //Engineer + L"", //Doctor + L"...", +}; +////////////////////////////////////////////////////////// + // This is pop up help text for the options that are available to the merc @@ -933,7 +1069,7 @@ STR16 pLandTypeStrings[] = L" ", //Any mine sector with creatures in it L" ", //The basement of Orta (K4) L"", //The tunnel access from the maze garden in Meduna - //leading to the secret shelter underneath the palace + //leading to the secret shelter underneath the palace L"", //The shelter underneath the queen's palace L"", //Unused }; @@ -1092,11 +1228,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L":", - L" (%s):", + L":", L" ", L":", // Range L":", // Damage @@ -1113,35 +1249,40 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L":", //14 //Attachments L"AUTO/5:", //15 - L":", //16 + L" :", //16 //Remaining ammo + + L":", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"", //Range - L"", //Damage - L" \n \n(c /) ( , )", //Burst/Auto Penalty - L" \n 5 ", //Autofire shots per 5 AP L"", //Accuracy + L"", //Damage + L"", //Range + L" ", //Aiming Levels + L" ", //Aiming Modifier + L" \n ", //Average Best Laser Range + L"", //Flash Suppression + L" ( , )", //Loudness (Lower is better) L"", //Reliability L" ", //Repair Ease + L" ", //Min. Range for Aiming Bonus + L" ", //To-Hit Modifier + L"", //12 L" ", //APs to ready L" 1 ", //APs to fire Single L" ", //APs to fire Burst L" ", //APs to fire Auto L" ", //APs to Reload L" ", //APs to Reload Manually - L"", //Flash Suppression - L" ( , )", //Loudness (Lower is better) - L" ", //To-Hit Modifier - L" \n ", //Average Best Laser Range - L" ", //Aiming Modifier - L" ", //Min. Range for Aiming Bonus + L"", //19 L" \n( )", //Bipod Modifier + L" \n 5 ", //Autofire shots per 5 AP + L" \n \n(c /) ( , )", //Burst/Auto Penalty //22 L" ", //APs to Throw L" ", //APs to Launch L" ", //APs to Stab @@ -1153,37 +1294,40 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L" \n c \n( , )", //Burst Penalty (Lower is better) }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"", - L"", - L" \n \n(c /) ( , )", - L" \n 5 ", - L"", - L"", - L" ", - L" ", - L" 1 ", - L" ", - L" ", - L" ", - L" ", - L" ", - L" \n ", - L" ", - L" ", - L"", - L"\n( , )", - L" \n( )", - L" ", - L" ", - L" ", - L" !", - L" !", - L" !", - L" ", - L" \n \n( , )", - L" \n c \n( , )", + L"", //Accuracy + L"", //Damage + L"", //Range + L" ", + L" ", //Aiming Modifier + L" \n ", //Average Best Laser Range + L"", //Flash Suppression + L" ( , )", //Loudness (Lower is better) + L"", //Reliability + L" ", //Repair Ease + L" ", //Min. Range for Aiming Bonus + L" ", //To-Hit Modifier + L"", //12 + L" ", //APs to ready + L" 1 ", //APs to fire Single + L" ", //APs to fire Burst + L" ", //APs to fire Auto + L" ", //APs to Reload + L" ", //APs to Reload Manually + L"", //19 + L" \n( )", //Bipod Modifier + L" \n 5 ", //Autofire shots per 5 AP + L" \n \n(c /) ( , )", //Burst/Auto Penalty //22 + L" ", //APs to Throw + L" ", //APs to Launch + L" ", //APs to Stab + L" !", //No Single Shot! + L" !", //No Burst Mode! + L" !", //No Auto Mode! + L" ", //APs to Bash + L" \n \n( , )", //Autofire Penalty (Lower is better) + L" \n c \n( , )", //Burst Penalty (Lower is better) }; STR16 gzAmmoStatsFasthelp[ 20 ] = @@ -1298,6 +1442,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L" ", //In + L"", + L"", + L"", //GOOD + L"", //FAIR + L"", //POOR + L"", //BAD + L"", + L" ." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1324,7 +1482,7 @@ CHAR16 zHealthStr[][13] = L"", // >= 45 L"", // >= 60 L"", // >= 75 - L"", // >= 90 + L"", // >= 90 }; STR16 gzMoneyAmounts[6] = @@ -1759,17 +1917,17 @@ STR16 pMapPopUpInventoryText[] = STR16 pwTownInfoStrings[] = { - L"", // size of the town in sectors + L"", // 0 // size of the town in sectors L"", // blank line, required L"", // how much of town is controlled L"", // none of this town L" ", // mine associated with this town - L"", // the loyalty level of this town + L"", // 5 // the loyalty level of this town L"", // the forces in the town trained by the player L"", L" ", // main facilities in this town L"", // the training level of civilians in this town - L" ", // state of civilian training in town + L" ", // 10 // state of civilian training in town L"", // the state of the trained civilians in the town L" ", // HEADROCK HAM 3.6: The stat of Mobile militia training in town //Mobile Training }; @@ -1875,6 +2033,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L" (|A)", L" (|I)", L" (|Z)", + L" ", //HAM 4: Show Mobile Militia Restrictions }; @@ -1908,7 +2067,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"", L"Psych Pro Inc.", @@ -1963,7 +2126,7 @@ STR16 pSenderNameList[] = L" ", L".I..", }; - +*/ // next/prev strings @@ -2034,13 +2197,13 @@ STR16 pFinanceSummary[] = STR16 pFinanceHeaders[] = { - L"", // the day column - L"", // the credits column - L"", // the debits column - L"", // transaction type - see TransactionText below - L"", // balance at this point in time - L".", // page number - L"", // the day(s) of transactions this page displays + L"", // the day column + L"", // the credits column + L"", // the debits column + L"", // transaction type - see TransactionText below + L"", // balance at this point in time + L".", // page number + L"", // the day(s) of transactions this page displays }; @@ -2136,7 +2299,7 @@ STR16 pMapScreenStatusStrings[] = STR16 pMapScreenPrevNextCharButtonHelpText[] = { L" \n(||||||| |||||)", // previous merc in the list - L" \n(||||||| ||||||)", // next merc in the list + L" \n(||||||| ||||||)", // next merc in the list }; @@ -2165,7 +2328,7 @@ STR16 pMapErrorString[] = //6-10 L" . - .", // merc can't move unescorted .. for a male L" . - .", // for a female - L" !", + L" !", L", .", L" ? !", // Cannot give a movement order. Air raid is going on. //11-15 @@ -2504,11 +2667,11 @@ STR16 pBookMarkStrings[] = L"A.I.M.", L" ", L"I.M.P.", - L"..R..", + L"M.E.R.C.", L"", L"", L"", - L"", + L"Oea", }; STR16 pBookmarkTitle[] = @@ -2601,7 +2764,7 @@ STR16 pWebPagesTitles[] = L" - ", L" - ", L" - ", - L" - ", //misc is an abbreviation for miscellaneous + L" - ", //misc is an abbreviation for miscellaneous L" - /.", L" - ", L"I.M.P.", @@ -2798,7 +2961,7 @@ STR16 MercAccountText[] = L" :", L"", L"", - L"", //5 + L"", L"", L":", L" %s?", //the %s is a string that contains the dollar amount ( ex. "$150" ) @@ -2809,7 +2972,7 @@ STR16 MercAccountPageText[] = { // Text on the buttons on the bottom of the screen L"", - L"", + L"", }; //For use at the M.E.R.C. web site. Text relating a MERC mercenary @@ -2840,7 +3003,7 @@ STR16 MercInfo[] = L"", L", 18 , .", - L"", + L"", }; @@ -2856,7 +3019,6 @@ STR16 MercNoAccountText[] = }; - // For use at the M.E.R.C. web site. MERC Homepage STR16 MercHomePageText[] = @@ -2872,7 +3034,7 @@ STR16 MercHomePageText[] = // For use at MiGillicutty's Web Page. -STR16 sFuneralString[] = +STR16 sFuneralString[] = { L" : 1983.", L" .I.. - \"\", .", @@ -2934,23 +3096,23 @@ STR16 sOrderFormText[] = L"", L" :", - L":", //5 + L":", L" :", L"", L"", L" ", - L" ", //10 + L" ", L"", L" ($10)", L" ($20)", L" ($10)", - L" ( ) ($10)", //15 + L" ( ) ($10)", L" :", L" , 75 .", L"... ", - L" ", - L" ",//20 + L" ", + L" ", //The text that goes beside the area where the user can enter their name @@ -2991,32 +3153,32 @@ STR16 sFloristCards[] = STR16 BobbyROrderFormText[] = { - L" ", //Title of the page + L" ", //Title of the page L"", // The number of items ordered L" (%s)", // The weight of the item - L"", // The name of the item - L" 1 ", // the item's weight - L"", //5 // The total price of all of items of the same type - L"", // The sub total of all the item totals added + L"", // The name of the item + L" 1 ", // the item's weight + L"", // The total price of all of items of the same type + L"", // The sub total of all the item totals added L" (. )", // S&H is an acronym for Shipping and Handling - L"", // The grand total of all item totals + the shipping and handling - L" ", - L" ", //10 // See below - L" ( %s.)", // The cost to ship the items - L"-", // Gets deliverd the next day - L"2 ", // Gets delivered in 2 days - L" ", // Gets delivered in 3 days + L"", // The grand total of all item totals + the shipping and handling + L" ", + L" ", // See below + L" ( %s.)", // The cost to ship the items + L"-", // Gets deliverd the next day + L"2 ", // Gets delivered in 2 days + L" ", // Gets delivered in 3 days L"",//15 // Clears the order page L"", // Accept the order L"", // text on the button that returns to the previous page - L" ", // Text on the button that returns to the home page + L" ", // Text on the button that returns to the home page L"* - , ", // Disclaimer stating that the item is used L" .", //20 // A popup message that to warn of not enough money - L"< >", // Gets displayed when there is no valid city selected + L"< >", // Gets displayed when there is no valid city selected L" %s?", // A popup that asks if the city selected is the correct one L" **", // Displays the weight of the package - L"** . ", // Disclaimer states that there is a minimum weight for the package - L"", + L"** . ", // Disclaimer states that there is a minimum weight for the package + L"", }; @@ -3073,44 +3235,44 @@ STR16 BobbyRFilter[] = STR16 BobbyRText[] = { - L"", // Title + L"", // Title // instructions on how to order - L" . - , - . , .", + L" . - , - . , .", //Text on the buttons to go the various links - L"", // - L"", //3 - L"", //4 - L"", //5 - L"", //6 //misc is an abbreviation for miscellaneous - L"/", //7 + L"", + L"", + L"", + L"", + L"", //misc is an abbreviation for miscellaneous + L"/", L"", L" ", - L" ", //10 + L" ", //The following 2 lines are used on the Ammunition page. //They are used for help text to display how many items the player's merc has //that can use this type of ammo - L" ",//11 - L"., ", //12 + L" ", + L", ", //The following lines provide information on the items - L":", // Weight of all the items of the same type + L":", // Weight of all the items of the same type L".:", // the caliber of the gun L":", // number of rounds of ammo the Magazine can hold L":", // The range of the gun - L":", // Damage of the weapon + L":", // Damage of the weapon L":", // Weapon's Rate Of Fire, acronym ROF L":", // Cost of the item L":", // The number of items still in the store's inventory - L" :", // The number of items on order + L" :", // The number of items on order L":", // If the item is damaged L":", // the Weight of the item L":", // The total cost of all items on order - L"* %% ", // if the item is damaged, displays the percent function of the item + L"* %% ", // if the item is damaged, displays the percent function of the item //Popup that tells the player that they can only order 10 items at a time @@ -3141,7 +3303,7 @@ STR16 BobbyRaysFrontText[] = L"", L"", - L"", //5 + L"", L"", //Details on the web site @@ -3157,13 +3319,13 @@ STR16 BobbyRaysFrontText[] = STR16 AimSortText[] = { - L".I.M. ", // Title + L".I.M. ", // Title // Title for the way to sort - L":", + L":", // sort by... - L"", + L"", L"", L"", L"", @@ -3207,11 +3369,11 @@ STR16 AimPolicyText[] = STR16 AimMemberText[] = { - L" ", - L" .", - L" ", + L" ", + L" .", + L" - ", L" .", -}; +}; //Aim Member.c //The page in which the players hires AIM mercenaries @@ -3220,9 +3382,9 @@ STR16 CharacterInfo[] = { // The various attributes of the merc - L"", - L"", - L"", + L"", + L"", + L"", L"", L"", L"", @@ -3230,13 +3392,13 @@ STR16 CharacterInfo[] = L"", L"", L"", - L"", //10 + L"", // the contract expenses' area - L"", - L"", - L"1 ", + L"", + L"", + L"1 ", L"7 ", L"14 ", @@ -3247,10 +3409,16 @@ STR16 CharacterInfo[] = L"", L">>", - L" ", // Title for the additional info for the merc's bio - L" ", //20 // Title of the page - L":", // Displays the optional gear cost + L" ", // Title for the additional info for the merc's bio + L" ", // Title of the page + L":", // Displays the optional gear cost + L".", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L" . ", // If the merc required a medical deposit, this is displayed + L" 1", // Text on Starting Gear Selection Button 1 + L" 2", // Text on Starting Gear Selection Button 2 + L" 3", // Text on Starting Gear Selection Button 3 + L" 4", // Text on Starting Gear Selection Button 4 + L" 5", // Text on Starting Gear Selection Button 5 }; @@ -3265,7 +3433,7 @@ STR16 VideoConfercingText[] = //Text on the buttons to select the length of time the merc can be hired - L"1 ", + L"1 ", L"7 ", L"14 ", @@ -3280,12 +3448,12 @@ STR16 VideoConfercingText[] = L"", // go back to the previous menu L"", // go to menu in which you can hire the merc L"", // stops talking with the merc - L"", + L"", L"", // if the merc is not there, you can leave a message //Text on the top of the video conference popup - L" ", + L" ", L". . .", L"+ " // Displays if you are hiring the merc with the medical deposit @@ -3306,7 +3474,7 @@ STR16 AimPopUpText[] = // if the merc is not available, one of the following is displayed over the merc's face - L" ", + L" ", L", ", L"", @@ -3334,7 +3502,7 @@ STR16 AimLinkText[] = STR16 AimHistoryText[] = { - L"A.I.M. ", //Title + L"A.I.M. ", //Title // Text on the buttons at the bottom of the page @@ -3362,20 +3530,20 @@ STR16 AimFiText[] = // The title of the page, the above text gets added at the end of this text - L" A.I.M. , - %s", - L" A.I.M. , - %s", + L" A.I.M. , - %s", + L" A.I.M. , - %s", // Instructions to the players on what to do L" ", - L" ", //10 + L" ", L" ", L" ", // Gets displayed on top of the merc's portrait if they are... L"", - L"", //14 + L"", L" ", }; @@ -3397,11 +3565,6 @@ STR16 AimAlumniText[] = L"" // Stops displaying information on selected merc }; - - - - - //AIM Home Page STR16 AimScreenText[] = @@ -3415,7 +3578,7 @@ STR16 AimScreenText[] = //Text for an advertisement that gets displayed on the AIM page L"\" \"", - L"\" !\"", //10 + L"\" !\"", L" ", L"... ", L" , .", @@ -3443,19 +3606,19 @@ STR16 AimBottomMenuText[] = STR16 SKI_Text[ ] = { - L" ", //Header for the merchandise available + L" ", //Header for the merchandise available L".", //The current store inventory page being displayed - L" ", //The total cost of the the items in the Dealer inventory area - L" ", //The total value of items player wishes to sell + L" ", //The total cost of the the items in the Dealer inventory area + L" ", //The total value of items player wishes to sell L"", //Button text for dealer to evaluate items the player wants to sell - L"", //Button text which completes the deal. Makes the transaction. + L"", //Button text which completes the deal. Makes the transaction. L"", //Text for the button which will leave the shopkeeper interface. - L" ", //The amount the dealer will charge to repair the merc's goods - L"1 ", // SINGULAR! The text underneath the inventory slot when an item is given to the dealer to be repaired - L"%d ", // PLURAL! The text underneath the inventory slot when an item is given to the dealer to be repaired - L"", // Text appearing over an item that has just been repaired by a NPC repairman dealer + L" ", //The amount the dealer will charge to repair the merc's goods + L"1 ", // SINGULAR! The text underneath the inventory slot when an item is given to the dealer to be repaired + L"%d ", // PLURAL! The text underneath the inventory slot when an item is given to the dealer to be repaired + L"", // Text appearing over an item that has just been repaired by a NPC repairman dealer L" .", //Message box that tells the user there is no more room to put there stuff - L"%d ", // The text underneath the inventory slot when an item is given to the dealer to be repaired + L"%d ", // The text underneath the inventory slot when an item is given to the dealer to be repaired L" .", }; @@ -3475,11 +3638,11 @@ STR16 SkiAtmText[] = L"7", L"8", L"9", - L"OK", //Transfer the money - L"", //Take money from the player - L"", //Give money to the player - L"", //Cancel the transfer - L"", //Clear the money display + L"OK", //Transfer the money + L"", //Take money from the player + L"", //Give money to the player + L"", //Cancel the transfer + L"", //Clear the money display }; @@ -3490,10 +3653,10 @@ STR16 gzSkiAtmText[] = // Text on the bank machine panel that.... L" ", //tells the user to select either to give or take from the merc L" ", //Enter the amount to transfer - L" ", //Giving money to the merc - L" ", //Taking money from the merc - L" ", //Not enough money to transfer - L"", //Display the amount of money the player currently has + L" ", //Giving money to the merc + L" ", //Taking money from the merc + L" ", //Not enough money to transfer + L"", //Display the amount of money the player currently has }; @@ -3574,29 +3737,28 @@ STR16 zSaveLoadText[] = //The first %d is a number that contains the amount of free space on the users hard drive, //the second is the recommended amount of free space. - L" . %d , %d JA.", + L" . %d , %d JA.", - L"...", //When saving a game, a message box with this string appears on the screen + L"...", //When saving a game, a message box with this string appears on the screen L"", L"", - L"", - L"", + L"", + L"", - L" ", - L" ", //Placeholder English + L" ", + L" ", L" ", L"", L"", L"", L" ", - L" ' ', 640480. .", - L" , ' ', . Ja2.ini 'Data-1.13' .", + L" \" \", 640480. .", + L" , \" \", . Ja2.ini 'Data-1.13' .", }; - //MapScreen STR16 zMarksMapScreenText[] = { @@ -3627,8 +3789,11 @@ STR16 zMarksMapScreenText[] = L" .", L" %s .", L" .", - L" ", - L" ", // 24 + L" ", + L" ", + //TODO.Translate HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L" . , .", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3651,10 +3816,10 @@ STR16 pMilitiaConfirmStrings[] = L" $%d, .", L"%s: %d , .", L" %s.", - L" $%d .", // HEADROCK HAM 3.6: Mobile Militia //You cannot afford the $%d to train mobile militia here. - L" %s (%s %d)?", // HEADROCK HAM 3.6: Mobile Militia //Continue training mobile militia in %s (%s %d)? - L" %d $ %d. %s", // HEADROCK HAM 3.6: Mobile Militia //Training mobile militia in %d sectors will cost $ %d. %s - L" $", // HEADROCK HAM 3.6: Mobile Militia //Training a squad of mobile militia will cost $ + L" $%d .", + L" %s (%s %d)?", + L" %d $ %d. %s", + L" $", }; //Strings used in the popup box when withdrawing, or depositing money from the $ sign at the bottom of the single merc panel @@ -3694,9 +3859,9 @@ STR16 zOptionsToggleText[] = L" ", L" ", L" ", - L" ", + L" ", //Allow Enemy Taunts L" ", - L" ", + L" ", L" . ", L" ", L" ", @@ -3707,18 +3872,21 @@ STR16 zOptionsToggleText[] = L" ", L" ", L" ", - L" ", //Enhanced Description Box + L" ", //Enhanced Description Box L" ", // add forced turn mode - L" ", //Stat Progress Bars // Show progress towards stat increase + L" ", //Stat Progress Bars // Show progress towards stat increase + L" ", //Report Miss Offsets // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L" . ", //Alternate Strategy-Map Colors //Change color scheme of Strategic Map + L" ", // Show alternate bullet graphics (tracers) L"-- --", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L" ", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END L"-- --", // an example options screen options header (pure text) L" ", // failsafe show/hide option to reset all options L" ?", // a do once and reset self option (button like effect) - L" ", //Debug Options in other builds // allow debugging in release or mapeditor - L"DEBUG Render Option group", // an example option that will show/hide other options - L"Render Mouse Regions", // an example of a DEBUG build option + L" ", //Debug Options in other builds // allow debugging in release or mapeditor + L" ", //DEBUG Render Option group // an example option that will show/hide other options + L" Mouse Regions", //Render Mouse Regions // an example of a DEBUG build option L"-----------------", // an example options screen options divider (pure text) // this is THE LAST option that exists (debug the options screen, doesnt do anything, except exist) @@ -3728,13 +3896,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L" \n .", //Mute Confirmation L" \n .", - //Subtitles + //Subtitles L" \n .", //Key to advance speech @@ -3790,22 +3960,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L" , \n .", L" , \n .", - L" , \n .", + L" , .", L" , \n (|Q).", - L" , \n 4- .", + L" , \n ( ). \n - |C|t|r+|X.", //When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X. L" , |||||| .", L" , .", - L" , \n .", - L" , \n .", - L" , .", - L" , .", - L" , |A|l|t \n \n .", //When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy + L" , \n .", + L" , \n .", + L" , .", + L" , .", + L" , |A|l|t \n \n .", L" , \n .", L" , \n .", L" , \n .", - L" , \n .", //EDB description - L" , \n \n (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", //When ON and enemy present, Turn Base mode persists untill sector is free (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T). // add forced turn mode - L" , , \n .", //When ON, shows character progress towards gaining levels + L" , \n .", + L" , \n \n (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode + L" , , \n .", + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L" , \n , .", //When ON, the Strategic Map will be colored differently based on exploration. + L" , .", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L" , \n \n .", //Force all pending Bobby Ray shipments L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3813,7 +3986,7 @@ STR16 zOptionsScreenHelpText[] = L" , \n .", // failsafe show/hide option to reset all options L" .", // a do once and reset self option (button like effect) L" , \n , \n .", // Allows debug options in release or mapeditor builds - L"Toggle to display debugging render options", //Toggle to display debugging render options // an example option that will show/hide other options + L" , \n .", //Toggle to display debugging render options L"Attempts to display slash-rects around mouse regions", // an example of a DEBUG build option L"(text not rendered)TOPTION_DEBUG_MODE_OPTIONS_END", // an example options screen options divider (pure text) @@ -3826,34 +3999,64 @@ STR16 zOptionsScreenHelpText[] = STR16 gzGIOScreenText[] = { L" ", - L" ", - L"", - L"", - L" ", //Placeholder English + L" ", + L"", + L"", + L" ", L" ", - L"", - L"", + L" ", + L" ", L" ", - L"˸", - L"", - L"", - L"", + L"", // + L"", // + L"", // + L"", // L" ", L" ", - L" ", - L" ", - L" ", + L" ", + L" ", + L" ", L" -", L" ", - L"", - L"", - L"", - L" ", - L" ", - L"", - L"", + L"", + L"", + L"", + L" ", + L" / ", //Inventory / Attachments + L"NOT USED", + L"NOT USED", L"", L" ( )", + // Added by SANDRO + L" IMP ", //Skill Traits + L"", + L"", + L" IMP ", //Max IMP Characters + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L" ", + L"", + L"", + L" ", + L"", + L" ", + L" ", //Secret Weapon Caches + L"", + L" ", + L" ", //Progress Speed of Item Choices + L" ", + L"", + L"", + L"", + L" ", + + L" / ", + L" / ", + L" / ", }; STR16 gzMPJScreenText[] = @@ -3871,11 +4074,28 @@ STR16 gzMPJScreenText[] = L"", //Version L" ", //Game Type L"Ping", - L" .", //You must enter a player name - L" IP . \n( 84.114.195.239).", //You must enter a valid server IP address.\n (eg 192.168.0.1) - L" ( 1 65535).", //You must enter a valid Server Port between 1 and 65535 + L" .", + L" IP . \n( 84.114.195.239).", + L" ( 1 65535).", }; +STR16 gzMPJHelpText[] = +{ + L" : http://webchat.quakenet.org/?channels=ja2-multiplayer", + + L" ", + L" '127.0.0.1' IP 60000.", //Enter '127.0.0.1' for the IP and the Port number should be greater than 60000. + L" (UDP, TCP) . : http://portforward.com", + L" IRC ICQ IP (http://www.whatismyip.com).", + L" ' ' .", + + L" ", + L" ( IRC, ICQ ..) IP .", + L" IP .", + L" '' .", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { L" ", //HOST GAME @@ -3884,57 +4104,93 @@ STR16 gzMPHScreenText[] = L" ", //Server Name L" ", //Game Type L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"- ", //Max Players - L" ", //Squad Size + L"Team-Deathmatch", + L"Co-Operative", + L" ", //Max Players + L" ", //Maximum Mercs L"Merc Selection", - L" ", //Random Mercs + L" ", L" ", //Hired by Player - L" ", //Starting Balance - L" ", //Can Hire Same Merc + L" ", //Starting Cash + L" ", //Allow Hiring Same Merc L" ", //Report Hired Mercs - L" ", //Allow Bobby Rays - L" ", //Randomise Starting Edge + L" ", //Bobby Rays + L" ", //Sector Starting Edge L" ", //You must enter a server name - L" 2 4", //Max Players must be between 2 and 4 - L" 1- 6-", //Squad size must be between 1 and 6 - L" ", //Time of Day - L" 24- (:)", //Time of Day must be a 24 hr time (HH:MM)\n\n eg. 13:30 = 1.30pm - L" ", //Starting Cash must be a valid dollar amount ( no cents )\n\n eg. 150000 - L" ", //Damage Multiplier - L" 0 5.", //Damage Multiplier must be a number between 0 and 5 - L" ", //Turn Timer Multiplier - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", - L" CO-OP", //Enable Civilians in CO-OP - L" (NIV)", //Use New Inventory (NIV) - L"Enforce Maximum AI Enemies", - L"Sync. MP Clients Directory", + L"", + L"", + L" ", //Starting Time + L"", + L"", + L" ", //Weapon Damage + L"", + L" ", //Timed Turns + L"", + L" CO-OP", //Enable Civilians in CO-OP + L"", + L" CO-OP", //Maximum Enemies in CO-OP + L" ", //Synchronize Game Directory L"MP Sync. Directory", - L" .", //You must enter a file transfer directory + L" .", L"( '/' '\\'.)", L" .", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"", + L"", + // Starting Time + L"", + L"", + L"", + // Starting Cash + L"", + L"", + L"", + L"", + // Time Turns + L" ", //Never + L"", //Slow + L"", //Medium + L"", //Fast + // Weapon Damage + L" ", //Very low + L"", //Low + L"", //Normal + // Merc Hire + L"", + L"", //Normal + // Sector Edge + L"", + L"", + // Bobby Ray / Hire same merc + L"", + L"", }; STR16 pDeliveryLocationStrings[] = { - L"", //Austin, Texas, USA - L"", //Baghdad, Iraq (Suddam Hussein's home) - L"", //The main place in JA2 that you can receive items. The other towns are dummy names... + L"", //Austin, Texas, USA + L"", //Baghdad, Iraq (Suddam Hussein's home) + L"", //The main place in JA2 that you can receive items. The other towns are dummy names... L"", //Hong Kong, Hong Kong - L"", //Beirut, Lebanon (Middle East) - L"", //London, England - L"-", //Los Angeles, California, USA (SW corner of USA) - L"", //Meduna -- the other airport in JA2 that you can receive items. - L"", //The island of Metavira was the fictional location used by JA1 - L"", //Miami, Florida, USA (SE corner of USA) - L"", //Moscow, USSR - L"-", //New York, New York, USA - L"", //Ottawa, Ontario, Canada -- where JA2 was made! - L"", //Paris, France - L"", //Tripoli, Libya (eastern Mediterranean) - L"", //Tokyo, Japan - L"", //Vancouver, British Columbia, Canada (west coast near US border) + L"", //Beirut, Lebanon (Middle East) + L"", //London, England + L"-",//Los Angeles, California, USA (SW corner of USA) + L"", //Meduna -- the other airport in JA2 that you can receive items. + L"", //The island of Metavira was the fictional location used by JA1 + L"", //Miami, Florida, USA (SE corner of USA) + L"", //Moscow, USSR + L"-", //New York, New York, USA + L"", //Ottawa, Ontario, Canada -- where JA2 was made! + L"", //Paris, France + L"", //Tripoli, Libya (eastern Mediterranean) + L"", //Tokyo, Japan + L"", //Vancouver, British Columbia, Canada (west coast near US border) }; STR16 pSkillAtZeroWarning[] = @@ -4019,13 +4275,13 @@ STR16 pMessageStrings[] = L"/", //Lowercase acronym for not applicable. L" ", //Meanwhile L"%s: %s%s",//30 Name/Squad has arrived in sector A9. Order must not change without notifying - //SirTech +//SirTech L"", L" ", L" , , ALT+S.", L"", L"", - L" . %sM , Jagged Alliance 2 %sM.", + L" . %sM , Jagged Alliance 2 %s M.", L" A.I.M. %s.", L"%s %s.", //'Merc name' has caught 'item' -- let SirTech know if name comes after item. L"%s .", //'Merc name' has taken the drug @@ -4046,8 +4302,7 @@ STR16 pMessageStrings[] = L"", L"", - L"%s %s.", //"Item" passed to "merc". Please try to keep the item %s before the merc %s, otherwise, - //must notify SirTech. + L"%s %s.", //"Item" passed to "merc". Please try to keep the item %s before the merc %s, otherwise, must notify SirTech. L" , %s %s.", //pass "item" to "merc". Same instructions as above. //A list of attachments appear after the items. Ex: Kevlar vest ( Ceramic Plate 'Attached )' @@ -4082,17 +4337,17 @@ STR16 pMessageStrings[] = L"3D .", L" %d- .", L" , %s %s", //first %s is the mercs name, the seconds is a string containing the salary - L"", + L"", //Skip L"%s .", - L" SaveGame99.sav. , SaveGame01 - SaveGame10 , .", + L" SaveGame99.sav. , SaveGame01 - SaveGame10 , .", L"%s: () %s.", L" .", L"%s ( %s) %d , %s.", //first %s is mercs name, next is the sector location and name where they will be arriving in, lastely is the day an the time of arrival L" !", L" ( )", L" ( )", - L" ", - L" ", + L" ", // Changed from Drop All On (Enabled Soldier Tooltips) + L" ", // Changed from Drop All Off (Disabled Soldier Tooltips) L" ", L" ", // forced turn mode strings @@ -4105,6 +4360,7 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved. L"", //Client + L" \"\" \" \".", //You cannot use the Old Inventory and the New Attachment System at the same time. }; @@ -4171,7 +4427,7 @@ STR16 gzLaptopHelpText[] = STR16 gzHelpScreenText[] = { - L" ", + L" ", }; STR16 gzNonPersistantPBIText[] = @@ -4290,21 +4546,21 @@ STR16 gzCreditNameTitle[]= STR16 gzCreditNameFunny[]= { - L"", // Chris Camfield - L"( )", // Shaun Lyng + L"", // Chris Camfield + L"( )", // Shaun Lyng L"(\"! .\")", //Kris \"The Cow Rape Man\" Marnes - L"( )", // Ian Currie - L"( Wizardry 8)", // Linda Currie + L"( )", // Ian Currie + L"( Wizardry 8)", // Linda Currie L"( )", // Eric \"WTF\" Cheng L"( CFSA - ...)", // Lynn Holowka L"", // Norman \"NRG\" Olsen L"", // George Brooks - L"( Dead Head)", // Andrew Stacey - L"( )", // Scot Loving - L"( )", // Andrew \"Big Cheese Doddle\" Emmons - L"( )", // Dave French - L"( Wizardry 8)", // Alex Meduna - L"( !)", // Joey \"Joeker\" Whelan", + L"( Dead Head)", // Andrew Stacey + L"( )", // Scot Loving + L"( )", // Andrew \"Big Cheese Doddle\" Emmons + L"( )", // Dave French + L"( Wizardry 8)", // Alex Meduna + L"( !)", // Joey \"Joeker\" Whelan", }; STR16 sRepairsDoneString[] = @@ -4363,7 +4619,7 @@ STR16 gzLateLocalizedString[] = //14 L"", - L"( )", + L"( )", L": %d/%d", @@ -4373,7 +4629,7 @@ STR16 gzLateLocalizedString[] = L"%s !", //(ex "The ice cream truck is full") - L"%s , / .", + L"%s , / .", //20 //Happens when you get shot in the legs, and you fall down. @@ -4436,7 +4692,7 @@ STR16 gzLateLocalizedString[] = //46-48 L"%s: !", L" %d .", //No more than %d militia trainers are permitted in this sector. - L" ?", + L" ?", //49-50 L" .", @@ -4520,6 +4776,10 @@ STR16 gzTooltipStrings[] = L" ", L" ", L"|: %s\n", + // Added - SANDRO + L"%s| 1: %s\n", //%s|Skill 1: %s\n + L"%s| 2: %s\n", + L"%s| 3: %s\n", }; STR16 New113Message[] = @@ -4530,9 +4790,9 @@ STR16 New113Message[] = L" .", L" ...", L" !", //suppression fire! - L"*", //BRST - - L"***", //AUTO - ( - ) - L"", // + L"*", //BRST - + L"***", //AUTO - + L"", L" *", L" ***", L"!", @@ -4549,6 +4809,21 @@ STR16 New113Message[] = L" .", //Real-time sneaking OFF L" .", //Real-time sneaking ON L" !", // this should be enough - SANDRO + L"%s !", //%s was successful at stealing! + L" %s , .", //%s did not have enough action points to steal all selected items. + L" %s ? ( %i ).", //Do you want to perform surgery on %s before bandaging? (You can heal about %i Health.) + L" %s? ( %i ).", //Do you want to perform surgery on %s? (You can heal about %i Health.) + L" ? (() - %i).", //Do you wish to perform necessary surgeries first? (%i patient(s)) + L" ?", //Do you wish to perform the surgery on this patient first? + L" ?", //Apply first aid automatically with necessary surgeries or without them? + L"%s ().", //Surgery on %s finished. + L"%s () !", //%s is hit in the chest and loses a point of maximum health! + L"%s () %d !", //%s is hit in the chest and loses %d points of maximum health! + L"%s () %s.", //%s has regained one point of lost %s + L"%s () %d %s.", //%s has regained %d points of lost %s + L" .", //Your scouting skills prevented an ambush by the enemy! + L" -!", //Thanks to your scouting skills you have successfuly avoided a pack of bloodcats! + L"%s !", //%s is hit to groin and falls down in pain! }; STR16 New113HAMMessage[] = @@ -4571,7 +4846,7 @@ STR16 New113HAMMessage[] = L" %s .", //The %s is already fully-staffed. L" $%d. ?", //It will cost $%d per hour to staff this facility. Do you wish to continue? L" . $%d , $%d. .", //You have insufficient funds to pay for all Facility work today. $%d have been paid, but you still owe $%d. The locals are not pleased.", - L" . $%d. .", //You have insufficient funds to pay for all Facility work today. You owe $%d. The locals are not pleased. + L" . $%d. .", // 16 - 20 L" $%d , !", //You have an outstanding debt of $%d for Facility Operation, and no money to pay it off! L" $%d . .", //You have an outstanding debt of $%d for Facility Operation. You can't assign this merc to facility duty until you have enough money to pay off the entire debt. @@ -4596,14 +4871,69 @@ STR16 New113MERCMercMailTexts[] = L" , . . . ", }; +// TODO.Translate +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"FW A.I.M.: ", + L". . . , . . ", + + // Brain + L"FW A.I.M.: ", + L" . . ", + + // Scream + L"FW A.I.M.: ", + L" !", + + // Henning + L"FW A.I.M.: ", + L" , . , A.I.M. ! ", + + // Luc + L"FW A.I.M.: ", + L" , ! . , . ", + + // Laura + L"FW A.I.M.: ", + L"! , . . A.I.M. . ! . P.S. , Monk ? ", + + // Grace + L"FW A.I.M.: ", + L" , . . , . . A.I.M. ! ", + + // Rudolf + L"FW A.I.M.: ", + L" , ? , . , .", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = { // Sniper - L": . 100 ! ", + L": . 100 ! ", //Sniper: Eyes of a hawk, you can shoot the wings from a fly at a hundred yards! // Camouflage - L": ! ", + L": ! ", //Camouflage: Beside you, even bushes look synthetic! + // Ranger + L": , ! , , . ", //Ranger: Those amateurs from Texas have nothing on you! + // Gunslinger + L": , - ! ", //Gunslinger: With one handgun or two, you can be as lethal as Billy the Kid! + // Squadleader + L": , ! ", //Squadleader: A natural leader, your squadmates look to you for inspiration! + // Technician + L": ! , - ! ", //Technician: MacGyver's got nothing on you! Mechanical, electronic or explosive, you can fix it! + // Doctor + L": , , - - ! ", //Doctor: From grazes to gutshot, to amputations, you can heal them all! + // Athletics + L": ! ", //Athletics: Your speed and vitality are worthy of an Olympian! + // Bodybuilding + L": ? ! ! ", //Bodybuilding: Arnie? What a wimp! You could beat him with one arm behind your back! + // Demolitions + L": , ; , - 20 ; ... , ! ", //Demolitions: Sowing grenades like seeds, planting bombs, watching the limbs flying.. This is what you live for! + // Scouting + L": ! ", //Scouting: Nothing can escape your notice! }; STR16 NewInvMessage[] = @@ -4670,11 +5000,9 @@ STR16 MPClientMessage[] = L" : %d", //Grid Number L" .", L" : ('1' - / ) ('2' - / ) ('3' - ) ('4' - )", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Timed Turns=%d, Secs/Tic=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", - // 25 - L" - '9' .", + L"", L" : %d - '%S'.", L": %d.",//not used any more L"%s ( %d - '%S') %s ( %d - '%S')", @@ -4698,59 +5026,47 @@ STR16 MPClientMessage[] = L", .", L" %s.", // 45 - L" .", //You cant change the map once purchasing has commenced - L" '%s'", //Map changed to '%s' - L" '%s' , .", //Client '%s' disconnected, removing from game - L" , .", //You were disconnected from the game, returning to the Main Menu - L" . 5 ( %i )", //Connection failed, Retrying in 5 seconds, %i retries left... + L" .", + L" '%s'", + L" '%s' , .", + L" , .", + L" . 5 ( %i )", //50 - L" , ...", //Connection failed, giving up... - L" .", //You cannot start the game until another player has connected + L" , ...", + L" .", L"%s : %s", - L" ", //Send to All - L" ", //Allies only + L" ", + L" ", // 55 - L" . .", //Cannot join game. This game has already started. - L"%s (): %s", //%s (team): %s - L"#%i - '%s'", //Client #%i - '%s' + L" . .", + L"%s (): %s", + L"#%i - '%s'", L"%S - 100/100", L"%S - %i/100", // 60 - L" .", //Received all files from server. - L"'%S' .", //'%S' finished downloading from server. - L"'%S' .", //'%S' started downloading from server. - L" .", //Cannot start the game until all clients have finished receiving files - L" , ?", //This server requires that you download modified files to play, do you wish to continue? + L" .", + L"'%S' .", + L"'%S' .", + L" .", + L" , ?", // 65 - L" '' .", //Press 'Ready' to enter tactical screen. - L" . (%S) (%S).", //Cannot connect because your version %S is different from the server version %S. - L" .", //You killed an enemy soldier - L" .", //Cannot start the game, because all teams are the same. -}; - -STR16 MPHelp[] = -{ - // 0 - L" Jagged Alliance 2", - L" F1 .", - L" ( )", - L"* ja2_mp.ini *", - L"'1' - .", - // 5 - L"'2' - .", - L"'3' - - , - .", - L"'4' - .", - L"'5' - .", - L"'7' - .", - // 10 - L"'F2' - .", - L" readme_mp.html", - L": (, ja2_mp.ini )", - L"* CLIENT_NUM *", - L"* *", - // 15 - L"* - *", - L"'F1' - .", + L" '' .", + L" . (%S) (%S).", + L" .", + L" .", + L" (NIV), NIV.", + // 70 + // TODO.Translate + L" '%S'", + L"%s's &s", + L" . !", // All over red rover + L"Spectator mode disabled", + L" , :", //Choose client number to kick + // 75 + L" #%d .", + L" . .", + L" .", + L" .", }; STR16 gszMPEdgesText[] = @@ -4776,8 +5092,8 @@ STR16 gszMPMapscreenText[] = L" : ", //Game Type: L": ", //Players: L" : ", //Mercs each: - L" .", //You cannot change starting edge once Laptop is unlocked. - L" .", //You cannot change teams once the Laptop is unlocked. + L" .", + L" .", L". : ", //Random Mercs: L"", //Y L":", //Difficulty: @@ -4814,39 +5130,48 @@ STR16 gzMPCScreenText[] = STR16 gzMPChatToggleText[] = { - L" ", //Send to All - L" ", //Send to Allies only + L" ", + L" ", }; STR16 gzMPChatboxText[] = { - L" Jagged Alliance 2 v1.13", //Multiplayer Chat - L": |||| , |||| .", //Chat: press 'ENTER' to send of 'ESC' to cancel + L" Jagged Alliance 2 v1.13", + L": |||| , |||| .", }; -// Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L" . ( ).", - L" . . , , .", + // For old traits + L" . .", + + L" . . : , .", + + // For new major/minor traits + L" - , . , . - , .", + L" . , , . ( ), ...", }; STR16 sgAttributeSelectionText[] = { - L" . ", //Please adjust your physical attributes as compared to that of an average merc. You cannot raise any score above - L"I.M.P. .", //I.M.P. Attributes and skills review. + L" . .", + L"I.M.P.: .", //I.M.P. Attributes and skills review. L":", //Bonus Pts. L" ", //Starting Level + // New strings for new traits + L" . \" \" - , , , . %d.", + L" \"\", , , .", + L" . , , .", }; STR16 pCharacterTraitBeginIMPStrings[] = { - L"I.M.P. ", //I.M.P. Character Analysis + L"I.M.P.: ", //I.M.P. Character Analysis L" - . . , , . .", L" , , , . , . , .", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"", //Normal L"", //Friendly @@ -4861,6 +5186,24 @@ STR16 gzIMPCharacterTraitText[]= L"I.M.P.: ", //I.M.P. Attitudes }; +STR16 gzIMPCharacterTraitText[]= +{ + L"", //Neutral + L"", //Sociable + L"", //Loner + L"", //Optimist + L"", //Assertive + L"", //Intellectual + L"", //Primitive + L"", //Aggressive + L"", //Phlegmatic + L"", //Dauntless + L"", //Pacifist + L"", //Malicious + L"", //Show-off + L"I.M.P.: ", //I.M.P. Character Traits +}; + STR16 gzIMPColorChoosingText[] = { L"I.M.P.: ", @@ -4868,6 +5211,7 @@ STR16 gzIMPColorChoosingText[] = L" , , .", L" , .", L" \n .", + L"\n(: .)", }; STR16 sColorChoiceExplanationTexts[]= @@ -4890,7 +5234,7 @@ STR16 gzIMPDisabilityTraitText[]= L" ", //Fear of Insects L"", //Forgetful L"", //Psychotic - L"I.M.P. ", //I.M.P. Disabilities + L"I.M.P.: ", //I.M.P. Disabilities }; // HEADROCK HAM 3.6: Error strings for assigning a merc to a facility @@ -4932,7 +5276,6 @@ STR16 gzFacilityErrorMessage[]= L"%s () %s, () .", L"%s () %s %s.", L"%s () %s.", - // 31 - 35 L"%s () %s.", @@ -4955,7 +5298,7 @@ STR16 gzFacilityRiskResultStrings[]= STR16 gzFacilityAssignmentStrings[]= { - L"AMBIENT", // TODO.Translate + L"AMBIENT", L"", //Staff L"", L" ", @@ -5000,7 +5343,500 @@ STR16 gzFacilityAssignmentStrings[]= STR16 Additional113Text[]= { - L" Jagged Alliance 2 v1.13 16- ",//Jagged Alliance 2 v1.13 windowed mode requires a color depth of 16bpp or less. + L" Jagged Alliance 2 v1.13 16- ", }; +STR16 sEnemyTauntsFireGun[]= +{ + L" !", + L" !", + L" !", + L" !", + L"!", + L", ?", + L" !", + L", !", + L"! !", + L" !", + L" !", + L" , !", + L", ?", + L" , !", + L"-!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L", ... !", + L" !", + L"!", + L"!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"!", + L"!", + L"-, --! !", + L" .", + L"--!", + L", !", + L" .", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L" , !", + L" .", + L" !", + L", !", + L"!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L", ...", + L" , !", + L" !", + L" !", + L" , ...", + L"!", + L" ! !", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L" !", + L" ?", + L" ?", + L"! ...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L" !", + L" !", + L" , ...", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"----!", + L"--!", + L" ... !", + L" !", + L" ... --... .", + L" !..", + L" ... .", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"", + L"", + L"", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L".", + L".", + L".", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"", //SINGLE + L"", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //RUSSIAN diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index 55fa6169..a022969d 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -2,7 +2,7 @@ #include "Utils All.h" #else #include "Language Defines.h" - #ifdef TAIWANESE + #if defined( TAIWANESE ) #include "text.h" #include "Fileman.h" #endif @@ -109,6 +109,25 @@ FAST HELP TEXT -- Explains how the syntax of fast help text works. */ +// TODO.Translate +CHAR16 gszAimPages[ 6 ][ 20 ] = +{ + L"Page 1/2", //0 + L"Page 2/2", + + L"Page 1/3", + L"Page 2/3", + L"Page 3/3", + + L"Page 1/1", //5 +}; + +// by Jazz: TODO.Translate +CHAR16 zGrod[][500] = +{ + L"Robot", //0 // Robot +}; + STR16 pCreditsJA2113[] = { L"@T,{;JA2 v1.13 Development Team", @@ -319,6 +338,20 @@ CHAR16 Message[][STRING_LENGTH] = L"no semi auto", L"The enemy has no more items to steal!", L"The enemy has no item in its hand!", +// TODO.Translate + L"%s's desert camouflage has worn off.", + L"%s's desert camouflage has washed off.", + + L"%s's wood camouflage has worn off.", + L"%s's wood camouflage has washed off.", + + L"%s's urban camouflage urban has worn off.", + L"%s's urban camouflage urban has washed off.", + + L"%s's snow camouflage snow has worn off.", + L"%s's snow camouflage has washed off.", + + L"You cannot attach %s to this slot.", }; @@ -471,9 +504,12 @@ STR16 pPersonnelAssignmentStrings[] = L"In Transit", L"Repair", L"Practice", - L"Training Militia", + L"Training Militia", + L"Training Mobile Militia", // TODO.Translate L"Trainer", - L"Student", + L"Student", + L"Facility Staff", // TODO.Translate + L"Resting at Facility", // TODO.Translate L"Dead", L"Incap.", L"POW", @@ -513,9 +549,12 @@ STR16 pLongAssignmentStrings[] = L"In Transit", L"Repair", L"Practice", - L"Train Militia", + L"Train Militia", + L"Train Mobiles", // TODO.Translate L"Train Teammate", - L"Student", + L"Student", + L"Staff Facility", // TODO.Translate + L"Rest at Facility", // TODO.Translate L"Dead", L"Incap.", L"POW", @@ -759,6 +798,63 @@ STR16 pPersonnelScreenStrings[] = L"Times Wounded:", // number of times merc has been wounded L"Skills:", L"No Skills", + L"Achievements:", // added by SANDRO +}; + +// SANDRO - helptexts for merc records +STR16 pPersonnelRecordsHelpTexts[] = +{ + L"Elite soldiers: %d\n", + L"Regular soldiers: %d\n", + L"Admin soldiers: %d\n", + L"Hostile groups: %d\n", + L"Creatures: %d\n", + L"Tanks: %d\n", + L"Others: %d\n", + + L"Mercs: %d\n", + L"Militia: %d\n", + L"Others: %d\n", + + L"Shots fired: %d\n", + L"Missiles fired: %d\n", + L"Grenades thrown: %d\n", + L"Knives thrown: %d\n", + L"Blade attacks: %d\n", + L"Hand to hand attacks: %d\n", + L"Successful hits: %d\n", + + L"Locks picked: %d\n", + L"Locks breached: %d\n", + L"Traps removed: %d\n", + L"Explosives detonated: %d\n", + L"Items repaired: %d\n", + L"Items combined: %d\n", + L"Items stolen: %d\n", + L"Militia trained: %d\n", + L"Mercs bandaged: %d\n", + L"Surgeries made: %d\n", + L"Persons met: %d\n", + L"Sectors discovered: %d\n", + L"Ambushes prevented: %d\n", + L"Quests handled: %d\n", + + L"Tactical battles: %d\n", + L"Autoresolve battles: %d\n", + L"Times retreated: %d\n", + L"Ambushes experienced: %d\n", + L"Hardes battle: %d Enemies\n", + + L"Shot: %d\n", + L"Stabbed: %d\n", + L"Punched: %d\n", + L"Blasted: %d\n", + L"Suffered damages in facilities: %d\n", + L"Surgeries undergoed: %d\n", + L"Facility accidents: %d\n", + + L"Character:", + L"Weakening:", }; @@ -781,12 +877,53 @@ STR16 gzMercSkillText[] = L"Knifing", L"Sniper", L"Camouflage", //JA25: modified - L"Camouflage (Urban)", - L"Camouflage (Desert)", - L"Camouflage (Snow)", + // SANDRO - removed this + //L"Camouflage (Urban)", + //L"Camouflage (Desert)", + //L"Camouflage (Snow)", L"(Expert)", }; +////////////////////////////////////////////////////////// +// SANDRO - added this +STR16 gzMercSkillTextNew[] = +{ + // Major traits + L"No Skill", + L"Auto Weapons", + L"Heavy Weapons", + L"Marksman", + L"Hunter", + L"Gunslinger", + L"Hand to Hand", + L"Deputy", + L"Technician", + L"Paramedic", + // Minor traits + L"Ambidextrous", + L"Melee", + L"Throwing", + L"Night Ops", + L"Stealthy", + L"Athletics", + L"Bodybuilding", + L"Demolitions", + L"Teaching", + L"Scouting", + // second names for major skills + L"Machinegunner", + L"Bombardier", + L"Sniper", + L"Ranger", + L"Gunfighter", + L"Martial Arts", + L"Squadleader", + L"Engineer", + L"Doctor", + L"More...", +}; +////////////////////////////////////////////////////////// + // This is pop up help text for the options that are available to the merc @@ -1093,11 +1230,11 @@ STR16 sKeyDescriptionStrings[2] = //The headers used to describe various weapon statistics. -CHAR16 gWeaponStatsDesc[][ 16 ] = +CHAR16 gWeaponStatsDesc[][ 17 ] = { // HEADROCK: Changed this for Extended Description project L"Status:", - L"Weight (%s):", + L"Weight:", L"AP Costs", L"Rng:", // Range L"Dam:", // Damage @@ -1114,35 +1251,41 @@ CHAR16 gWeaponStatsDesc[][ 16 ] = // HEADROCK: Added new strings for extended description ** REDUNDANT ** L"Attachments:", //14 // TODO.Translate L"AUTO/5:", //15 - L"Amount:", //16 + L"Remaining ammo:", //16 // TODO.Translate + + // TODO.Translate + L"Default:", //17 //WarmSteel - So we can also display default attachments }; // HEADROCK: Several arrays of tooltip text for new Extended Description Box // Please note, several of these are artificially inflated to 19 entries to help fix a complication with // changing item type while watching its description box -STR16 gzWeaponStatsFasthelp[ 29 ] = +STR16 gzWeaponStatsFasthelp[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (Lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"Flash Suppression", - L"Loudness (Lower is better)", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", + L"", //19 L"Bipod Modifier", + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 L"APs to Throw", L"APs to Launch", L"APs to Stab", @@ -1154,28 +1297,31 @@ STR16 gzWeaponStatsFasthelp[ 29 ] = L"Burst Penalty (Lower is better)", }; -STR16 gzWeaponStatsFasthelpTactical[ 29 ] = +STR16 gzWeaponStatsFasthelpTactical[ 32 ] = { - L"Range", - L"Damage", - L"Burst/Auto Penalty (Lower is better)", - L"Autofire shots per 5 AP", L"Accuracy", + L"Damage", + L"Range", + L"Aiming Levels", + L"Aiming Modifier", + L"Average Best Laser Range", + L"Flash Suppression", + L"Loudness (Lower is better)", L"Reliability", L"Repair Ease", + L"Min. Range for Aiming Bonus", + L"To-Hit Modifier", + L"", //12 L"APs to ready", L"APs to fire Single", L"APs to fire Burst", L"APs to fire Auto", L"APs to Reload", L"APs to Reload Manually", - L"To-Hit Modifier", - L"Average Best Laser Range", - L"Aiming Modifier", - L"Min. Range for Aiming Bonus", - L"Flash Suppression", - L"Loudness (Lower is better)", + L"", //19 L"Bipod Modifier", + L"Autofire shots per 5 AP", + L"Burst/Auto Penalty (Lower is better)", //22 L"APs to Throw", L"APs to Launch", L"APs to Stab", @@ -1299,6 +1445,20 @@ STR16 gzMiscItemStatsFasthelp[ 34 ] = // HEADROCK: End new tooltip text +// HEADROCK HAM 4: New condition-based text similar to JA1. +STR16 gConditionDesc[] = +{ + L"In ", + L"PERFECT", + L"EXCELLENT", + L"GOOD", + L"FAIR", + L"POOR", + L"BAD", + L"TERRIBLE", + L" condition." +}; + //The headers used for the merc's money. CHAR16 gMoneyStatsDesc[][ 13 ] = @@ -1876,6 +2036,7 @@ STR16 pMapScreenBorderButtonHelpText[] = L"Show |Airspace", L"Show |Items", L"Show Militia & Enemies (|Z)", + L"Show Mobile Militia Restrictions", // HEADROCK HAM 4: Mobile Restrictions Button }; @@ -1909,7 +2070,11 @@ STR16 pDayStrings[] = // the list of email sender names -STR16 pSenderNameList[] = +CHAR16 pSenderNameList[500][128] = +{ + L"", +}; +/* { L"Enrico", L"Psych Pro Inc", @@ -1964,7 +2129,7 @@ STR16 pSenderNameList[] = L"John Kulba", L"A.I.M.", }; - +*/ // next/prev strings @@ -2312,7 +2477,7 @@ STR16 pImpButtonText[] = L"BEGIN", // begin profiling L"Skills", // personality section L"Attributes", // personal stats/attributes section - L"Appearance", // changed from portrait - SANDRO + L"Appearance", // changed from portrait L"Voice %d", // the voice selection L"Done", // done profiling L"Start Over", // start over profiling @@ -2333,12 +2498,12 @@ STR16 pImpButtonText[] = L"Registry", // the IMP site registry..when name and gender is selected L"Analyzing", // analyzing your profile results L"OK", - L"Character", // Change from "Voice" - SANDRO + L"Character", // Change from "Voice" }; STR16 pExtraIMPStrings[] = { - // These texts have been also slightly changed - SANDRO + // These texts have been also slightly changed L"With your character traits chosen, it is time to select your skills.", L"To complete the process, select your attributes.", L"To commence actual profiling, select portrait, voice and colors.", @@ -3253,7 +3418,13 @@ STR16 CharacterInfo[] = L"Additional Info", // Title for the additional info for the merc's bio L"Active Members", //20 // Title of the page L"Optional Gear:", // Displays the optional gear cost + L"gear", //"gear", //tais: Displays the optional gear cost in nsgi, this moved and can have only a small room, so just make it "gear" without extra's L"MEDICAL deposit required", // If the merc required a medical deposit, this is displayed + L"Kit 1", // Text on Starting Gear Selection Button 1 // TODO.Translate + L"Kit 2", // Text on Starting Gear Selection Button 2 + L"Kit 3", // Text on Starting Gear Selection Button 3 + L"Kit 4", // Text on Starting Gear Selection Button 4 + L"Kit 5", // Text on Starting Gear Selection Button 5 }; @@ -3631,8 +3802,11 @@ STR16 zMarksMapScreenText[] = L"There aren't enough people willing to be trained right now.", L"%s is full of militia.", L"Merc has a finite contract.", - L"Merc's contract is not insured", + L"Merc's contract is not insured", L"Map Overview", // 24 + // HEADROCK HAM 4: Prompt messages when turning on Mobile Militia Restrictions view. + L"You currently have no Mobile Militia. Return to this view mode once you've recruited some.", + L"This view shows where your Mobile Militia can and cannot go. GREY = Mobile Militia refuse to go here. RED = Mobile Militia can go here, but you've told them not to. YELLOW = Mobile Militia can enter this sector, but not leave. GREEN = Mobile Militia can go here freely. Right click a Green/Yellow sector to cycle its behavior.", }; @@ -3698,22 +3872,25 @@ STR16 zOptionsToggleText[] = L"Show 3D Cursor", L"Show Chance to Hit on cursor", L"GL Burst uses Burst cursor", - L"Enemies Drop all Items", + L"Allow Enemy Taunts", // Changed from "Enemies Drop all Items" - SANDRO L"High angle Grenade launching", - L"Restrict extra Aim Levels", + L"Allow Real Time Sneaking", // Changed from "Restrict extra Aim Levels" - SANDRO L"Space selects next Squad", L"Show Item Shadow", L"Show Weapon Ranges in Tiles", L"Tracer effect for single shot", L"Rain noises", L"Allow crows", - L"Show Soldier Tooltips", // Changed from "Random I.M.P personality" - SANDRO + L"Show Soldier Tooltips", L"Auto save", L"Silent Skyrider", L"Low CPU usage", L"Enhanced Description Box", L"Forced Turn Mode", // add forced turn mode L"Stat Progress Bars", // Show progress towards stat increase // TODO.Translate + L"Report Miss Offsets", // Screen messages showing amount and direction of shot deviation. // TODO.Translate + L"Alternate Strategy-Map Colors", // Change color scheme of Strategic Map + L"Alternate bullet graphics", // Show alternate bullet graphics (tracers) // TODO.Translate L"--Cheat Mode Options--", // TOPTION_CHEAT_MODE_OPTIONS_HEADER, L"Force Bobby Ray shipments", // force all pending Bobby Ray shipments L"-----------------", // TOPTION_CHEAT_MODE_OPTIONS_END @@ -3732,13 +3909,15 @@ STR16 zOptionsToggleText[] = //This is the help text associated with the above toggles. STR16 zOptionsScreenHelpText[] = { + // HEADROCK HAM 4: Added more tooltip text to some toggles, in order to explain them better. + //speech L"Keep this option ON if you want to hear character dialogue.", //Mute Confirmation L"Turns characters' verbal confirmations on or off.", - //Subtitles + //Subtitles L"Controls whether on-screen text is displayed for dialogue.", //Key to advance speech @@ -3794,22 +3973,25 @@ STR16 zOptionsScreenHelpText[] = // Options for 1.13 L"When ON, the chance to hit is shown on the cursor.", L"When ON, GL burst uses burst cursor.", - L"When ON, dead enemies drop all items.", + L"When ON, enemies will occasionally comment certain actions.", // Changed from Enemies Drop All Items - SANDRO L"When ON, grenade launchers fire grenades at higher angles (|Q).", - L"When ON, aim levels beyond 4 are restricted to rifles and sniper rifles.", + L"When ON, the turn based mode will not be entered when sneaking unnoticed and seeing an enemy unless pressing |C|t|r+|X.", // Changed from Restrict Extra Aim Levels - SANDRO L"When ON, |S|p|a|c|e selects next squad automatically.", L"When ON, item shadows will be shown.", L"When ON, weapon ranges will be shown in tiles.", L"When ON, tracer effect will be shown for single shots.", L"When ON, you will hear rain noises when it is raining.", L"When ON, the crows are present in game.", - L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", // - Changed from random IMP personality - SANDRO + L"When ON, a tooltip window is shown when pressing |A|l|t and hovering cursor over an enemy.", L"When ON, game will be saved after each players turn.", L"When ON, Skyrider will not talk anymore.", L"When ON, game will run with much lower CPU usage.", L"When ON, enhanced descriptions will be shown for items and weapons.", L"When ON and enemy present, Turn Base mode persists untill sector is free (|C|T|R|L+|S|H|I|F|T+|A|L|T+|T).", // add forced turn mode L"When ON, shows character progress towards gaining levels.", // TODO.Translate + L"|H|A|M |4 |D|e|b|u|g: When ON, will report the distance each bullet deviates from the\ncenter of the target, taking all NCTH factors into account.", + L"When ON, the Strategic Map will be colored differently based on exploration.", + L"When ON, alternate bullet graphics will be shown when you shoot.", // TODO.Translate L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_HEADER", L"Force all pending Bobby Ray shipments", L"(text not rendered)TOPTION_CHEAT_MODE_OPTIONS_END", @@ -3834,15 +4016,15 @@ STR16 gzGIOScreenText[] = L"Realistic", L"Sci Fi", L"Platinum", - L"Items", + L"Available Arsenal", // changed by SANDRO L"Tons of Guns", - L"Normal Guns", + L"Reduced", // changed by SANDRO L"Difficulty Level", L"Novice", L"Experienced", L"Expert", L"INSANE", - L"Ok", + L"Start", // TODO.Translate L"Cancel", L"Extra Difficulty", L"Save Anytime", @@ -3854,11 +4036,42 @@ STR16 gzGIOScreenText[] = L"Great", L"Excellent", L"Awesome", - L"Inventory System", - L"Old", - L"New", + L"Inventory / Attachments", // TODO.Translate + L"NOT USED", + L"NOT USED", L"Load MP Game", L"INITIAL GAME SETTINGS (Only the server settings take effect)", + // Added by SANDRO + L"Skill Traits", + L"Old", + L"New", + L"Max IMP Characters", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + L"Enemies Drop All Items", + L"Off", + L"On", + L"Number of Terrorists", + L"Random", + L"All", + L"Secret Weapon Caches", + L"Random", + L"All", + L"Progress Speed of Item Choices", + L"Very Slow", + L"Slow", + L"Normal", + L"Fast", + L"Very Fast", + + // TODO.Translate + L"Old / Old", + L"New / Old", + L"New / New", }; STR16 gzMPJScreenText[] = @@ -3881,6 +4094,24 @@ STR16 gzMPJScreenText[] = L"You must enter a valid Server Port between 1 and 65535.", }; +// TODO.Translate +STR16 gzMPJHelpText[] = +{ + L"Visit http://webchat.quakenet.org/?channels=ja2-multiplayer to find other players.", + + L"HOST", + L"Enter '127.0.0.1' for the IP and the Port number should be greater than 60000.", + L"Be sure that the Port (UDP, TCP) is forwarded on your Router. For more information see: http://portforward.com", + L"You have to send (via IRC, ICQ, etc) your external IP (http://www.whatismyip.com) and the Port number to the other players.", + L"Click on 'Host' to host a new Multiplayer Game.", + + L"JOIN", + L"The host has to send (via IRC, ICQ, etc) you the external IP and the Port number.", + L"Enter the external IP and the Port number from the host.", + L"Click on 'Join' to join an already hosted Multiplayer Game.", +}; + +// TODO.Translate STR16 gzMPHScreenText[] = { L"HOST GAME", @@ -3889,35 +4120,72 @@ STR16 gzMPHScreenText[] = L"Server Name", L"Game Type", L"Deathmatch", - L"Team Deathmatch", - L"Co-operative", - L"Max Players", - L"Squad Size", + L"Team-Deathmatch", + L"Co-Operative", + L"Maximum Players", + L"Maximum Mercs", L"Merc Selection", - L"Random Mercs", + L"Merc Hiring", L"Hired by Player", - L"Starting Balance", - L"Can Hire Same Merc", + L"Starting Cash", + L"Allow Hiring Same Merc", L"Report Hired Mercs", - L"Allow Bobby Rays", - L"Randomise Starting Edge", + L"Bobby Rays", + L"Sector Starting Edge", L"You must enter a server name", - L"Max Players must be between 2 and 4", - L"Squad size must be between 1 and 6", - L"Time of Day", - L"Time of Day must be a 24 hour time (HH:MM)", - L"Starting Cash must be a valid dollar amount (no cents)" , - L"Damage Multiplier", - L"Damage Multiplier must be a number between 0 and 5", - L"Turn Timer Multiplier", - L"Turn Timer multiplier must be a number between 0 (no timed turns) and 200 (short timed turns)", + L"", + L"", + L"Starting Time", + L"", + L"", + L"Weapon Damage", + L"", + L"Timed Turns", + L"", L"Enable Civilians in CO-OP", - L"Use New Inventory (NIV)", - L"Sync. MP Clients Directory", + L"", + L"Maximum Enemies in CO-OP", + L"Synchronize Game Directory", L"MP Sync. Directory", L"You must enter a file transfer directory.", L"(Use '/' instead of '\\' for directory delimiters.)", L"The specified synchronisation directory does not exist.", + L"1", + L"2", + L"3", + L"4", + L"5", + L"6", + // Max. Enemies / Report Hired Merc / Enable Civs in CO-OP + L"Yes", + L"No", + // Starting Time + L"Morning", + L"Afternoon", + L"Night", + // Starting Cash + L"Low", + L"Medium", + L"Heigh", + L"Unlimited", + // Time Turns + L"Never", + L"Slow", + L"Medium", + L"Fast", + // Weapon Damage + L"Very low", + L"Low", + L"Normal", + // Merc Hire + L"Random", + L"Normal", + // Sector Edge + L"Random", + L"Selectable", + // Bobby Ray / Hire same merc + L"Disable", + L"Allow", }; STR16 pDeliveryLocationStrings[] = @@ -4095,8 +4363,8 @@ STR16 pMessageStrings[] = L"History log updated.", L"Grenade Bursts use Targeting Cursor (Spread fire enabled)", L"Grenade Bursts use Trajectory Cursor (Spread fire disabled)", - L"Drop All Enabled", - L"Drop All Disabled", + L"Enabled Soldier Tooltips", // Changed from Drop All On - SANDRO + L"Disabled Soldier Tooltips", // Changed from Drop All Off - SANDRO L"Grenade Launchers fire at standard angles", L"Grenade Launchers fire at higher angles", // forced turn mode strings @@ -4109,6 +4377,9 @@ STR16 pMessageStrings[] = #endif L"..\\SavedGames\\MP_SavedGames", //The name of the directory where games are saved. L"Client", + + // TODO.Translate + L"You cannot use the Old Inventory and the New Attachment System at the same time.", }; @@ -4472,7 +4743,7 @@ STR16 gzLateLocalizedString[] = L"%s's armour attachment has been smashed!", L"%s fires %d more rounds than intended!", - L"%s fires %d more round than intended!", + L"%s fires one more round than intended!", }; STR16 gzCWStrings[] = @@ -4523,6 +4794,10 @@ STR16 gzTooltipStrings[] = L"no Vest", L"no Leggings", L"|Armor: %s\n", + // Added - SANDRO + L"%s|Skill 1: %s\n", + L"%s|Skill 2: %s\n", + L"%s|Skill 3: %s\n", }; STR16 New113Message[] = @@ -4551,7 +4826,26 @@ STR16 New113Message[] = L"No enemies in sight", L"Real-time sneaking OFF", L"Real-time sneaking ON", - L"Enemy spotted! (Ctrl + x to enter turn based)", + //L"Enemy spotted! (Ctrl + x to enter turn based)", + L"Enemy spotted!", // this should be enough - SANDRO + ////////////////////////////////////////////////////////////////////////////////////// + // These added by SANDRO + L"%s was successful on stealing!", + L"%s had not enough action points to steal all selected items.", + L"Do you want to make surgery on %s before bandaging? (You can heal about %i Health.)", + L"Do you want to make surgery on %s? (You can heal about %i Health.)", + L"Do you wish to make necessary surgeries first? (%i patient(s))", + L"Do you wish to make the surgery on this patient first?", + L"Apply first aid automatically with necessary surgeries or without them?", + L"Surgery on %s finished.", + L"%s is hit in the chest and loses a point of maximum health!", + L"%s is hit in the chest and loses %d points of maximum health!", + L"%s has regained one point of lost %s", + L"%s has regained %d points of lost %s", + L"Your scouting skills prevented you to be ambushed by the enemy!", + L"Thanks to your scouting skills you have successfuly avoided a pack of bloodcats!", + L"%s is hit to groin and falls down in pain!", + ////////////////////////////////////////////////////////////////////////////////////// }; // TODO.Translate @@ -4600,6 +4894,43 @@ STR16 New113MERCMercMailTexts[] = L"Please take note. Due to the improved performance of Biggens his fees for services rendered have undergone an increase. Speck T. Kline ", }; +// TODO.Translate +// WANNE: This is email text (each 2 line), when we left a message on AIM and now the merc is back +STR16 New113AIMMercMailTexts[] = +{ + // Monk + L"FW from AIM Server: Message from Victor Kolesnikov", + L"You want to talk to me? I have time.", + + // Brain + L"FW from AIM Server: Message from Janno Allik", + L"I am back. Waiting for your call.", + + // Scream + L"FW from AIM Server: Message from Lennart Vilde", + L"Sorry, I was out of office, now I am back.", + + // Henning + L"FW from AIM Server: Message from Henning von Branitz", + L"Back from business. You want my help?", + + // Luc + L"FW from AIM Server: Message from Luc Fabre", + L"Give me a call, if you are interested.", + + // Laura + L"FW from AIM Server: Message from Dr. Laura Colin", + L"I am now available.", + + // Grace + L"FW from AIM Server: Message from Graziella Girelli", + L"Got your message. If you still want me, you know what to do.", + + // Rudolf + L"FW from AIM Server: Message from Rudolf Steiger", + L"Rudolf here. Call me back.", +}; + // WANNE: These are the missing skills from the impass.edt file // INFO: Do not replace the characters. They indicate the (-> Newline) from the edt files STR16 MissingIMPSkillsDescriptions[] = @@ -4608,6 +4939,25 @@ STR16 MissingIMPSkillsDescriptions[] = L"Sniper: Eyes of a hawk, you can shoot the wings from a fly at a hundred yards! ", // Camouflage L"Camouflage: Besides you even bushes look synthetic! ", + // SANDRO - new strings for new traits added + // Ranger + L"Ranger: You are the one from Texas deserts, aren't you! ", + // Gunslinger + L"Gunslinger: With a handgun or two, you can be as lethal as the Billy Kid! ", + // Squadleader + L"Squadleader: Natural leader and boss, you are the big shot no kidding! ", + // Technician + L"Technician: Fixing stuff, removing traps, planting bombs, that's your bussiness! ", + // Doctor + L"Doctor: You can make a quick surgery with pocket-knife and chewing gum anywhere! ", + // Athletics + L"Athletics: Your speed and vitality is on top of possibilities! ", + // Bodybuilding + L"Bodybuilding: That big muscular figure which cannot be overlooked is you actually! ", + // Demolitions + L"Demolitions: You can blow up a whole city just by common home stuff! ", + // Scouting + L"Scouting: Nothing can escape your notice! ", }; STR16 NewInvMessage[] = @@ -4673,11 +5023,10 @@ STR16 MPClientMessage[] = L"X: %d, Y: %d", L"Grid Number: %d", L"Server only feature", - L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", - //L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Enemies=%d, Creatures=%d, Militias=%d, Civilians=%d, Timed Turns=%d, Secs/Tic=%d, Starting Cash=$%d, Tons of Guns=%d, Sci-Fi=%d, Difficulty=%d, Iron-Man=%d, BobbyRays Range=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", + L"Choose server manual override stage: ('1' - Enable laptop/hiring) ('2' - Launch/load level) ('3' - Unlock UI) ('4' - Finish placement)", L"Sector=%s, Max Clients=%d, Max Mercs=%d, Game_Mode=%d, Same Merc=%d, Damage Multiplier=%f, Timed Turns=%d, Secs/Tic=%d, Dis BobbyRay=%d, Dis Aim/Merc Equip=%d, Dis Morale=%d, Testing=%d", // 25 - L"Testing and cheat function '9' is enabled.", + L"", L"New connection: Client #%d - '%S'.", L"Team: %d.",//not used any more L"'%s' (client %d - '%S') was killed by '%s' (client %d - '%S')", @@ -4729,31 +5078,18 @@ STR16 MPClientMessage[] = L"Cannot connect because your version %S is different from the server version %S.", L"You killed an enemy soldier.", L"Cannot start the game, because all teams are the same.", -}; - -STR16 MPHelp[] = -{ - // 0 - L"Welcome to Jagged Alliance 2 v1.13 Multiplayer", - L"Press 'F1' for help", - L"Multiplayer controls (from strategy screen)", - L"* first set up ja2_mp.ini *", - L"'1' - Start server", - // 5 - L"'2' - Connect to server", - L"'3' - If server unlock laptop, set client ready for battle", - L"'4' - Quit server and client", - L"'5' - Display mouse coords (from tactical screen)", - L"'7' - Popup dialog for server override panel", - // 10 - L"'F2' - Display secondary help", - L"See readme_mp.html for further details", - L"Tips: (assuming ja2_mp.ini is set up)", - L"* Make sure all clients have unique CLIENT_NUM *", - L"* Game save doesn't record bobby rays order *", - // 15 - L"* Avoid placing opposed mercs in immediate sight *", - L"'F1' - Display primary help", + L"The server has choosen New Inventory (NIV), but your screen resolution does not support NIV.", + // 70 // TODO.Translate + L"Could not save received file '%S'", + L"%s's bomb was disarmed by &s", + L"You loose, what a shame", // All over red rover + L"Spectator mode disabled", + L"Choose client number to kick:", + // 75 + L"Team #%d is wiped out.", + L"Client failed to start. Terminating.", + L"Client disconnected and shutdown.", + L"Client is not running.", }; STR16 gszMPEdgesText[] = @@ -4830,8 +5166,12 @@ STR16 gzMPChatboxText[] = // Following strings added - SANDRO STR16 pSkillTraitBeginIMPStrings[] = { - L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected. To achieve an expert level on a trait, simply choose only that one trait.", - L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics and Ambidextrous traits cannot be achieved at expert levels, and if you choose one of them only, you will have only one skill trait.", + // For old traits + L"On the next page, you are going to choose your skill traits according to your proffessional specialization as a mercenary. No more than two different traits or one expert trait can be selected.", + L"You can also choose only one or even no traits, which will give you a bonus to your attribute points as a compensation. Note that Electronics, Ambidextrous and Camouflage traits cannot be achieved at expert levels.", + // For new major/minor traits + L"Next stage is about choosing your skill traits according to your proffessional specialization as a mercenary. On first page you can select up to two potential major traits, which mostly represent your main role in a team. While on second page is list of possible minor traits, which represent personal feats.", + L"No more then three choices altogeher are possible. Which means if you choose no major traits, you can then choose three minor traits. If you choose both major traits (or one enhanced), you can then choose only one minor trait...", }; STR16 sgAttributeSelectionText[] = @@ -4840,6 +5180,10 @@ STR16 sgAttributeSelectionText[] = L"I.M.P. Attributes and skills review.", L"Bonus Pts.:", L"Starting Level", + // New strings for new traits + L"On the next page you are going to specify your physical attributes and skills. As 'attributes' are called: health, dexterity, agility, strength and wisdom. Attributes cannot go lower than %d.", + L"The rest are called 'skills' and unlike attributes skills can be set to zero meaning you have absolutely no proficieny in it.", + L"All scores are set to a minimum at the beginning. Note that certain attributes are set to specific values according to skill traits you have selected. You cannot set those attributes lower than that.", }; STR16 pCharacterTraitBeginIMPStrings[] = @@ -4849,7 +5193,7 @@ STR16 pCharacterTraitBeginIMPStrings[] = L"The second page enlists possible disabilities you might have. If you suffer from any of these disabilities, choose which one (we believe that everyone has only one such disablement). Be honest, as it is important to inform potential employers of your true condition.", }; -STR16 gzIMPCharacterTraitText[]= +STR16 gzIMPAttitudesText[]= { L"Normal", L"Friendly", @@ -4861,6 +5205,24 @@ STR16 gzIMPCharacterTraitText[]= L"Big Shot", L"Asshole", L"Coward", + L"I.M.P. Attitudes", +}; + +STR16 gzIMPCharacterTraitText[]= +{ + L"Normal", + L"Sociable", + L"Loner", + L"Optimist", + L"Assertive", + L"Intellectual", + L"Primitive", + L"Aggressive", + L"Phlegmatic", + L"Dauntless", + L"Pacifist", + L"Malicious", + L"Show-off", L"I.M.P. Character Traits", }; @@ -4871,6 +5233,7 @@ STR16 gzIMPColorChoosingText[] = L"Please select the respective colors of your skin, hair and clothing. And select what body type you have.", L"Please select the respective colors of your skin, hair and clothing.", L"Toggle this to use alternative rifle holding.", + L"\n(Caution: you will need a big strength for this.)", }; STR16 sColorChoiceExplanationTexts[]= @@ -5009,4 +5372,498 @@ STR16 Additional113Text[]= L"Jagged Alliance 2 v1.13 windowed mode requires a color depth of 16bpp or less.", }; +// SANDRO - Taunts (here for now, xml for future, I hope) +STR16 sEnemyTauntsFireGun[]= +{ + L"Suck this!", + L"Touch this!", + L"Come get some!", + L"You're mine!", + L"Die!", + L"You scared, motherfucker?", + L"This will hurt!", + L"Come on you bastard!", + L"Come on! I don't got all day!", + L"Come to daddy!", + L"You'll be six feet under in no time!", + L"Will send ya home in a pinebox, loser!", + L"Hey, wanna play?", + L"You should have stayed home, bitch.", + L"Sucker!", +}; + +STR16 sEnemyTauntsFireLauncher[]= +{ + + L"We have a barbecue here.", + L"I got a present for ya.", + L"Bam!", + L"Smile!", +}; + +STR16 sEnemyTauntsThrow[]= +{ + L"Catch!", + L"Here ya go!", + L"Pop goes the weasel.", + L"This one's for you.", + L"Muhehe.", + L"Catch this, swine!", + L"I like this.", +}; + +STR16 sEnemyTauntsChargeKnife[]= +{ + L"I'll get your scalp.", + L"Come to papa.", + L"Show me your guts!", + L"I'll rip you to pieces!", + L"Motherfucker!", +}; + +STR16 sEnemyTauntsRunAway[]= +{ + L"We're in some real shit...", + L"They said join the army. Not for this shit!", + L"I have enough.", + L"Oh my God.", + L"They ain't paying us enough for this.", + L"It's just too much for me.", + L"I'll bring some friends.", + +}; + +STR16 sEnemyTauntsSeekNoise[]= +{ + L"I heard that!", + L"Who's there?", + L"What was that?", + L"Hey! What the...", + +}; + +STR16 sEnemyTauntsAlert[]= +{ + L"They are here!", + L"Now the fun can start.", + L"I hoped this will never happen.", + +}; + +STR16 sEnemyTauntsGotHit[]= +{ + L"Ouch!", + L"Ugh!", + L"This.. hurts!", + L"You fuck!", + L"You will regret.. uhh.. this.", + L"What the..!", + L"Now you have.. pissed me off.", + +}; + +////////////////////////////////////////////////////// +// HEADROCK HAM 4: Begin new UDB texts and tooltips +////////////////////////////////////////////////////// +STR16 gzItemDescTabButtonText[] = +{ + L"Description", + L"General", + L"Advanced", +}; + +STR16 gzItemDescTabButtonShortText[] = +{ + L"Desc", + L"Gen", + L"Adv", +}; + +STR16 gzItemDescGenHeaders[] = +{ + L"Primary", + L"Secondary", + L"AP Costs", + L"Burst / Autofire", +}; + +STR16 gzItemDescGenIndexes[] = +{ + L"Prop.", + L"0", + L"+/-", + L"=", +}; + +STR16 gzUDBButtonTooltipText[]= +{ + L"|D|e|s|c|r|i|p|t|i|o|n |P|a|g|e:\n \nShows basic textual information about this item.", + L"|G|e|n|e|r|a|l |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows specific data about this item.", + L"|A|d|v|a|n|c|e|d| |P|r|o|p|e|r|t|i|e|s |P|a|g|e:\n \nShows bonuses given by this item.", +}; + +STR16 gzUDBHeaderTooltipText[]= +{ + L"|P|r|i|m|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nProperties and data related to this item's class\n(Weapon / Armor / etcetera).", + L"|S|e|c|o|n|d|a|r|y |P|r|o|p|e|r|t|i|e|s:\n \nAdditional features of this item,\nand/or possible secondary abilities.", + L"|A|P |C|o|s|t|s:\n \nVarious Action Point costs to fire\nor manipulate this weapon.", + L"|B|u|r|s|t |/ |A|u|t|o|f|i|r|e |P|r|o|p|e|r|t|i|e|s:\n \nData related to firing this weapon in\nBurst or Autofire modes.", +}; + +STR16 gzUDBGenIndexTooltipText[]= +{ + L"|P|r|o|p|e|r|t|y |i|c|o|n\n \nMouse-over to reveal the property's name.", + L"|B|a|s|i|c |v|a|l|u|e\n \nThe basic value given by this item, excluding any\nbonuses or penalties from attachments or ammo.", + L"|A|t|t|a|c|h|m|e|n|t |B|o|n|u|s|e|s\n \nBonus or penalty given by ammo, any attachments,\nor low item condition.", + L"|F|i|n|a|l |V|a|l|u|e\n \nThe final value given by this item, including any\nbonuses/penalties from attachments or ammo.", +}; + +STR16 gzUDBAdvIndexTooltipText[]= +{ + L"Property icon (mouse-over to reveal name).", + L"Bonus/penalty given while |s|t|a|n|d|i|n|g.", + L"Bonus/penalty given while |c|r|o|u|c|h|i|n|g.", + L"Bonus/penalty given while |p|r|o|n|e.", + L"Bonus/penalty given", +}; + +STR16 szUDBGenWeaponsStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y", + L"|D|a|m|a|g|e", + L"|R|a|n|g|e", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s", + L"|R|e|l|i|a|b|i|l|i|t|y", + L"|R|e|p|a|i|r |E|a|s|e", + L"|M|i|n|. |R|a|n|g|e |f|o|r |A|i|m|i|n|g |B|o|n|u|s", + L"|T|o|-|H|i|t |M|o|d|i|f|i|e|r", + L"", // (12) + L"|A|P|s |t|o |R|e|a|d|y", + L"|A|P|s |t|o |A|t|t|a|c|k", + L"|A|P|s |t|o |B|u|r|s|t", + L"|A|P|s |t|o |A|u|t|o|f|i|r|e", + L"|A|P|s |t|o |R|e|l|o|a|d", + L"|A|P|s |t|o |R|e|c|h|a|m|b|e|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l", + L"|A|u|t|o|f|i|r|e |B|u|l|l|e|t|s |p|e|r |5 |A|P|s", +}; + +STR16 szUDBGenWeaponsStatsExplanationsTooltipText[]= +{ + L"\n \nDetermines whether bullets fired by\nthis gun will stray far from where\nit is pointed.\n \nScale: 0-100.\nHigher is better.", + L"\n \nDetermines the average amount of damage done\nby bullets fired from this weapon, before\ntaking into account armor or armor-penetration.\n \nHigher is better.", + L"\n \nThe maximum distance (in tiles) that\nbullets fired from this gun will travel\nbefore they begin dropping towards the\nground.\n \nHigher is better.", + L"\n \nThis is the number of Extra Aiming\nLevels you can add when aiming this gun.\n \nThe FEWER aiming levels are allowed, the MORE\nbonus each aiming level gives you. Therefore,\nhaving FEWER levels makes the gun faster to aim,\nwithout making it any less accurate.\n \nLower is better.", + L"\n \nWhen greater than 1.0, will proportionally reduce\naiming errors at a distance.\n \nRemember that high scope magnification is detrimental\nwhen the target is too close!\n \nA value of 1.0 means no scope is installed.", + L"\n \nProportionally reduces aiming errors at a distance.\n \nThis effect works up to a given distance,\nthen begins to dissipate and eventually\ndisappears at sufficient range.\n \nHigher is better.", + L"\n \nWhen this property is in effect, the weapon\nproduces no visible flash when firing.\n \nEnemies will not be able to spot you\njust by your muzzle flash (but they\nmight still HEAR you).", + L"\n \nWhen firing this weapon, Loudness is the\ndistance (in tiles) that the sound of\ngunfire will travel.\n \nEnemies within this distance will probably\nhear the shot.\n \nLower is better.", + L"\n \nDetermines how quickly this weapon will degrade\nwith use.\n \nHigher is better.", + L"\n \nDetermines how difficult it is to repair this weapon.\n \nHigher is better.", + L"\n \nThe minimum range at which a scope can provide it's aimBonus.", + L"\n \nTo hit modifier granted by laser sights.", + L"", // (12) + L"\n \nThe number of APs required to bring this\nweapon up to firing stance.\n \nOnce the weapon is raised, you may fire repeatedly\nwithout paying this cost again.\n \nA weapon is automatically 'Unreadied' if its\nwielder performs any action other than\nfiring or turning.\n \nLower is better.", + L"\n \nThe number of APs required to perform\na single attack with this weapon.\n \nFor guns, this is the cost of firing\na single shot without extra aiming.\n \nIf this icon is greyed-out, single-shots\n are not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\na burst.\n \nThe number of bullets fired in each burst is\ndetermined by the weapon itself, and indicated\nby the number of bullets shown on this icon.\n \nIf this icon is greyed-out, burst fire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to fire\nan Autofire Volley of three bullets.\n \nIf you wish to fire more than 3 bullets,\nyou will need to pay extra APs.\n \nIf this icon is greyed-out, autofire\nis not possible with this weapon.\n \nLower is better.", + L"\n \nThe number of APs required to reload\nthis weapon.\n \nLower is better.", + L"\n \nThe number of APs required to rechamber this weapon\nbetween each and every shot fired.\n \nLower is better.", + L"\n \nThe distance this weapon's muzzle will shift\nhorizontally between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting to the right.\nNegative numbers indicate shifting to the left.\n \nCloser to 0 is better.", + L"\n \nThe distance this weapon's muzzle will shift\nvertically between each and every bullet in a\nburst or autofire volley.\n \nPositive numbers indicate shifting upwards.\nNegative numbers indicate shifting downwards.\n \nCloser to 0 is better.", + L"\n \nIndicates the number of bullets that will be added\nto an autofire volley for every extra 5 APs\nyou spend.\n \nHigher is better.", +}; + +STR16 szUDBGenArmorStatsTooltipText[]= +{ + L"|P|r|o|t|e|c|t|i|o|n |V|a|l|u|e", + L"|C|o|v|e|r|a|g|e", + L"|D|e|g|r|a|d|e |R|a|t|e", +}; + +STR16 szUDBGenArmorStatsExplanationsTooltipText[]= +{ + L"\n \nThis primary armor property defines how much\ndamage the armor will absorb from any attack.\n \nRemember that armor-piercing attacks and\nvarious randomal factors may alter the\nfinal damage reduction.\n \nHigher is better.", + L"\n \nDetermines how much of the protected\nbodypart is covered by the armor.\n \nIf coverage is below 100%, attacks have\na certain chance of bypassing the armor\ncompletely, causing maximum damage\nto the protected bodypart.\n \nHigher is better.", + L"\n \nIndicates how quickly this armor's condition\ndrops when it is struck, proportional to\nthe damage caused by the attack.\n \nLower is better.", +}; + +STR16 szUDBGenAmmoStatsTooltipText[]= +{ + L"|A|r|m|o|r |P|i|e|r|c|i|n|g", + L"|B|u|l|l|e|t |T|u|m|b|l|e", + L"|P|r|e|-|I|m|p|a|c|t |E|x|p|l|o|s|i|o|n", +}; + +STR16 szUDBGenAmmoStatsExplanationsTooltipText[]= +{ + L"\n \nThis is the bullet's ability to penetrate\na target's armor.\n \nWhen above 1.0, the bullet proportionally\nreduces the Protection value of any\narmor it hits.\n \nWhen below 1.0, the bullet increases the\nprotection value of the armor instead.\n \nHigher is better.", + L"\n \nDetermines a proportional increase of damage\npotential once the bullet gets through the\ntarget's armor and hits the bodypart behind it.\n \nWhen above 1.0, the bullet's damage\nincreases after penetrating the armor.\n \nWhen below 1.0, the bullet's damage\npotential decreases after passing through armor.\n \nHigher is better.", + L"\n \nA multiplier to the bullet's damage potential\nthat is applied immediately before hitting the\ntarget.\n \nValues above 1.0 indicate an increase in damage,\nvalues below 1.0 indicate a decrease.\n \nHigher is better.", +}; + +STR16 szUDBGenExplosiveStatsTooltipText[]= +{ + L"|D|a|m|a|g|e", + L"|S|t|u|n |D|a|m|a|g|e", + L"|B|l|a|s|t |R|a|d|i|u|s", + L"|S|t|u|n |B|l|a|s|t |R|a|d|i|u|s", + L"|N|o|i|s|e |B|l|a|s|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |S|t|a|r|t |R|a|d|i|u|s", + L"|L|i|g|h|t |S|t|a|r|t |R|a|d|i|u|s", + L"|S|m|o|k|e |S|t|a|r|t |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |S|t|a|r|t |R|a|d|i|u|s", + L"|T|e|a|r|g|a|s |E|n|d |R|a|d|i|u|s", + L"|L|i|g|h|t |E|n|d |R|a|d|i|u|s", + L"|M|u|s|t|a|r|d |G|a|s |E|n|d |R|a|d|i|u|s", + L"|S|m|o|k|e |E|n|d |R|a|d|i|u|s", + L"|I|n|c|e|n|d|i|a|r|y |E|n|d |R|a|d|i|u|s", + L"|E|f|f|e|c|t |D|u|r|a|t|i|o|n", + L"|L|o|u|d|n|e|s|s", + L"|V|o|l|a|t|i|l|i|t|y", +}; + +STR16 szUDBGenExplosiveStatsExplanationsTooltipText[]= +{ + L"\n \nThe amount of damage caused by this explosive.\n \nNote that blast-type explosives deliver this damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of damage every turn until the\neffect dissipates.\n \nHigher is better.", + L"\n \nThe amount of non-lethal (stun) damage caused\nby this explosive.\n \nNote that blast-type explosives deliver their damage\nonly once (when they go off), while prolonged effect\nexplosives deliver this amount of stun damage every\nturn until the effect dissipates.\n \nHigher is better.", + L"\n \nThis is the radius of the explosive blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the explosion.\n \nHigher is better.", + L"\n \nThis is the radius of the stun-blast caused by\nthis explosive item.\n \nTargets will suffer less damage the further they are\nfrom the center of the blast.\n \nHigher is better.", + L"\n \nThis is the distance that the noise from this\ntrap will travel. Soldiers within this distance\nare likely to hear the noise and be alerted.\n \nHigher is better.", + L"\n \nThis is the starting radius of the tear-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the mustard-gas\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the light\nemitted by this explosive item.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the starting radius of the smoke\nreleased by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the end radius and duration\nof the effect (displayed below).\n \nHigher is better.", + L"\n \nThis is the starting radius of the flames\ncaused by this explosive item.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the end radius and duration of the effect\n(displayed below).\n \nHigher is better.", + L"\n \nThis is the final radius of the tear-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the mustard-gas released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn,\nunless wearing a gas mask.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the light emitted\nby this explosive item before it dissipates.\n \nTiles close to the center of the effect will become\nvery bright, while tiles nearer the edge\nwill only be a little brighter than normal.\n \nAlso note the start radius and duration\nof the effect.\n \nAlso remember that unlike other explosives with\ntimed effects, the light effect gets SMALLER\nover time, until it disappears.\n \nHigher is better.", + L"\n \nThis is the final radius of the smoke released\nby this explosive item before it dissipates.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn\n(if any), unless wearing a gas mask. More importantly,\nanyone inside the cloud becomes extremely difficult to spot,\nand also loses a large chunk of sight-range themselves.\n \nAlso note the start radius and duration\nof the effect.\n \nHigher is better.", + L"\n \nThis is the final radius of the flames caused\nby this explosive item before they dissipate.\n \nEnemies caught within the radius will suffer\nthe listed damage and stun-damage each turn.\n \nAlso note the start radius and duration of the effect.\n \nHigher is better.", + L"\n \nThis is the duration of the explosive effect.\n \nEach turn, the radius of the effect will grow by\none tile in every direction, until reaching\nthe listed End Radius.\n \nOnce the duration has been reached, the effect\ndissipates completely.\n \nNote that light-type explosives become SMALLER\nover time, unlike other effects.\n \nHigher is better.", + L"\n \nThis is the distance (in Tiles) within which\nsoldiers and mercs will hear the explosion when\nit goes off.\n \nEnemies hearing the explosion will be alerted to your\npresence.\n \nLower is better.", + L"\n \nThis value represents a chance (out of 100) for this\nexplosive to spontaneously explode whenever it is damaged\n(for instance, when other explosions go off nearby).\n \nCarrying highly-volatile explosives into combat\nis therefore extremely risky and should be avoided.\n \nScale: 0-100.\nLower is better.", +}; + +STR16 szUDBGenSecondaryStatsTooltipText[]= +{ + L"|T|r|a|c|e|r |A|m|m|o", + L"|A|n|t|i|-|T|a|n|k |A|m|m|o", + L"|I|g|n|o|r|e|s |A|r|m|o|r", + L"|A|c|i|d|i|c |A|m|m|o", + L"|L|o|c|k|-|B|u|s|t|i|n|g |A|m|m|o", + L"|R|e|s|i|s|t|a|n|t |t|o |E|x|p|l|o|s|i|v|e|s", + L"|W|a|t|e|r|p|r|o|o|f", + L"|E|l|e|c|t|r|o|n|i|c", + L"|G|a|s |M|a|s|k", + L"|N|e|e|d|s |B|a|t|t|e|r|i|e|s", + L"|C|a|n |P|i|c|k |L|o|c|k|s", + L"|C|a|n |C|u|t |W|i|r|e|s", + L"|C|a|n |S|m|a|s|h |L|o|c|k|s", + L"|M|e|t|a|l |D|e|t|e|c|t|o|r", + L"|R|e|m|o|t|e |T|r|i|g|g|e|r", + L"|R|e|m|o|t|e |D|e|t|o|n|a|t|o|r", + L"|T|i|m|e|r |D|e|t|o|n|a|t|o|r", + L"|C|o|n|t|a|i|n|s |G|a|s|o|l|i|n|e", + L"|T|o|o|l |K|i|t", + L"|T|h|e|r|m|a|l |O|p|t|i|c|s", + L"|X|-|R|a|y |D|e|v|i|c|e", + L"|C|o|n|t|a|i|n|s |D|r|i|n|k|i|n|g |W|a|t|e|r", + L"|C|o|n|t|a|i|n|s |A|l|c|o|h|o|l", + L"|F|i|r|s|t |A|i|d |K|i|t", + L"|M|e|d|i|c|a|l |K|i|t", + L"|L|o|c|k |B|o|m|b", +}; + +STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= +{ + L"\n \nThis ammo creates a tracer effect when firedin\nfull-auto or burst mode.\n \nTracer fire helps keep the volley accurate\nand thus deadly despite the gun's recoil.\n \nAlso, tracer bullets create paths of light that\ncan reveal a target in darkness. However, they\nalso reveal the shooter to the enemy!\n \nTracer Bullets automatically disable any\nMuzzle Flash Suppression items installed on the\nsame weapon.", + L"\n \nThis ammo can damage the armor on a tank.\n \nAmmo WITHOUT this property will do no damage\nat all to tanks.\n \nEven with this property, remember that most guns\ndon't cause enough damage anyway, so don't\nexpect too much.", + L"\n \nThis ammo ignores armor completely.\n \nWhen fired at an armored target, it will behave\nas though the target is completely unarmored,\nand thus transfer all its damage potential to the target!", + L"\n \nWhen this ammo strikes the armor on a target,\n \nit will cause that armor to degrade rapidly.\n \nThis can potentially strip a target of its\narmor!", + L"\n \nThis type of ammo is exceptional at breaking locks.\n \nFire it directly at a locked door or container\nto cause massive damage to the lock.", + L"\n \nThis armor is three times more resistant\nagainst explosives than it should be, given\nits Protection value.\n \nWhen an explosion hits the armor, its Protection\nvalue is considered three times higher than\nthe listed value.", + L"\n \nThis item is imprevious to water. It does not\nreceive damage from being submerged.\n \nItems WITHOUT this property will gradually deteriorate\nif the person carrying them goes for a swim.", + L"\n \nThis item is electronic in nature, and contains\ncomplex circuitry.\n \nElectronic items are inherently more difficult\nto repair, at least without the ELECTRONICS skill.", + L"\n \nWhen this item is worn on a character's face,\nit will protect them from all sorts of noxious gasses.\n \nNote that some gasses are corrosive, and might eat\nright through the mask...", + L"\n \nThis item requires batteries. Without batteries,\nyou cannot activate its primary abilities.\n \nTo use a set of batteries, attach them to\nthis item as you would a scope to a rifle.", + L"\n \nThis item can be used to pick open locked\ndoors or containers.\n \nLockpicking is silent, although it requires\nsubstantial mechanical skill to pick anything\nbut the simplest locks.", + L"\n \nThis item can be used to cut through wire fences.\n \nThis allows a character to rapidly move through\nfenced areas, possibly outflanking the enemy!", + L"\n \nThis item can be used to smash open locked\ndoors or containers.\n \nLock-smashing requires substantial strength,\ngenerates a lot of noise, and can easily\ntire a character out. However, it is a good\nway to get through locks without superior skills or\ncomplicated tools.", + L"\n \nThis item can be used to detect metallic objects\nunder the ground.\n \nNaturally, its primary function is to detect\nmines without the necessary skills to spot them\nwith the naked eye.\n \nMaybe you'll find some buried treasure too.", + L"\n \nThis item can be used to detonate a bomb\nwhich has been set with a remote detonator.\n \nPlant the bomb first, then use the\nRemote Trigger item to set it off when the\ntime is right.", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator can be triggered\nby a (separate) remote device.\n \nRemote Detonators are great for setting traps,\nbecause they only go off when you tell them to.\n \nAlso, you have plenty of time to get away!", + L"\n \nWhen attached to an explosive device and set up\nin the right position, this detonator will count down\nfrom the set amount of time, and explode once the\ntimer expires.\n \nTimer Detonators are cheap and easy to install,\nbut you'll need to time them just right to give\nyourself enough chance to get away!", + L"\n \nThis item contains gasoline (fuel).\n \nIt might come in handy if you ever\nneed to fill up a gas tank...", + L"\n \nThis item contains various tools that can\nbe used to repair other items.\n \nA toolkit item is always required when setting\na character to repair duty.", + L"\n \nWhen worn in a face-slot, this item provides\nthe ability to spot enemies through walls,\nthanks to their heat signature.", + L"\n \nThis powerful device can be used to scan\nfor enemies using X-rays.\n \nIt will reveal all enemies within a certain radius\nfor a short period of time.\n \nKeep away from reproductive organs!", + L"\n \nThis item contains fresh drinking water.\nUse when thirsty.", + L"\n \nThis item contains liquor, alcohol, booze,\nwhatever you fancy calling it.\n \nUse with caution. Do not drink and drive.\nMay cause cirrhosis of the liver.", + L"\n \nThis is a basic field medical kit, containing\nitems required to provide basic medical aid.\n \nIt can be used to bandage wounded characters\nand prevent bleeding.\n \nFor actual healing, use a proper Medical Kit\nand/or plenty of rest.", + L"\n \nThis is a proper medical kit, which can\nbe used in surgery and other serious medicinal\npurposes.\n \nMedical Kits are always required when setting\na character to Doctoring duty.", + L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", +}; + +STR16 szUDBAdvStatsTooltipText[]= +{ + L"|A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|F|l|a|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |S|n|a|p|s|h|o|t |M|o|d|i|f|i|e|r", + L"|F|l|a|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|P|e|r|c|e|n|t |A|i|m|i|n|g |M|o|d|i|f|i|e|r", + L"|A|l|l|o|w|e|d |A|i|m|i|n|g |L|e|v|e|l|s |M|o|d|i|f|i|e|r", + L"|A|i|m|i|n|g |C|a|p |M|o|d|i|f|i|e|r", + L"|G|u|n |H|a|n|d|l|i|n|g |M|o|d|i|f|i|e|r", + L"|D|r|o|p |C|o|m|p|e|n|s|a|t|i|o|n |M|o|d|i|f|i|e|r", + L"|T|a|r|g|e|t |T|r|a|c|k|i|n|g |M|o|d|i|f|i|e|r", + L"|D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|M|e|l|e|e |D|a|m|a|g|e |M|o|d|i|f|i|e|r", + L"|R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|S|c|o|p|e |M|a|g|n|i|f|i|c|a|t|i|o|n |F|a|c|t|o|r", + L"|P|r|o|j|e|c|t|i|o|n |F|a|c|t|o|r", + L"|L|a|t|e|r|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|V|e|r|t|i|c|a|l |R|e|c|o|i|l |M|o|d|i|f|i|e|r", + L"|M|a|x|i|m|u|m |C|o|u|n|t|e|r|-|F|o|r|c|e |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |A|c|c|u|r|a|c|y |M|o|d|i|f|i|e|r", + L"|C|o|u|n|t|e|r|-|F|o|r|c|e |F|r|e|q|u|e|n|c|y |M|o|d|i|f|i|e|r", + L"|T|o|t|a|l |A|P |M|o|d|i|f|i|e|r", + L"|A|P|-|t|o|-|R|e|a|d|y |M|o|d|i|f|i|e|r", + L"|S|i|n|g|l|e|-|a|t|t|a|c|k |A|P |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |A|P |M|o|d|i|f|i|e|r", + L"|A|u|t|o|f|i|r|e |A|P |M|o|d|i|f|i|e|r", + L"|R|e|l|o|a|d |A|P |M|o|d|i|f|i|e|r", + L"|M|a|g|a|z|i|n|e |S|i|z|e |M|o|d|i|f|i|e|r", + L"|B|u|r|s|t |S|i|z|e |M|o|d|i|f|i|e|r", + L"|H|i|d|d|e|n |M|u|z|z|l|e |F|l|a|s|h", + L"|L|o|u|d|n|e|s|s |M|o|d|i|f|i|e|r", + L"|I|t|e|m |S|i|z|e |M|o|d|i|f|i|e|r", + L"|R|e|l|i|a|b|i|l|i|t|y |M|o|d|i|f|i|e|r", + L"|W|o|o|d|l|a|n|d |C|a|m|o|u|f|l|a|g|e", + L"|U|r|b|a|n |C|a|m|o|u|f|l|a|g|e", + L"|D|e|s|e|r|t |C|a|m|o|u|f|l|a|g|e", + L"|S|n|o|w |C|a|m|o|u|f|l|a|g|e", + L"|S|t|e|a|l|t|h |M|o|d|i|f|i|e|r", + L"|H|e|a|r|i|n|g |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|G|e|n|e|r|a|l |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|N|i|g|h|t|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|D|a|y|-|t|i|m|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|B|r|i|g|h|t|-|L|i|g|h|t |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|C|a|v|e |V|i|s|i|o|n |R|a|n|g|e |M|o|d|i|f|i|e|r", + L"|T|u|n|n|e|l |V|i|s|i|o|n", +}; + +// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular. +STR16 szUDBAdvStatsExplanationsTooltipText[]= +{ + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Accuracy value.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the shooter's accuracy\nfor ANY shot with a ranged weapon by the\nlisted percentage, based on their original accuracy.\n \nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis item modifies the accuracy gained from each\nextra aiming level you pay for, when aiming\na ranged weapon, by the\nlisted percentage based on the original value.\n \nHigher is better.", + L"\n \nThis item modifies the number of extra aiming\nlevels this gun can take.\n \nReducing the number of allowed aiming levels\nmeans that each level adds proportionally\nmore accuracy to the shot.\nTherefore, the FEWER aiming levels are allowed,\nthe faster you can aim this gun, without losing\naccuracy!\n \nLower is better.", + L"\n \nThis item modifies the shooter's maximum accuracy\nwhen using ranged weapons, as a percentage\nof their original maximum accuracy.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis item modifies the difficulty of\ncompensating for shots beyond a weapon's range.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis item modifies the difficulty of hitting\na moving target with a ranged weapon.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour weapon, by the listed amount.\n \nHigher is better.", + L"\n \nThis item modifies the damage output of\nyour melee weapon, by the listed amount.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies its maximum effective range.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprovides extra magnification, making shots at a distance\ncomparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nprojects a dot on the target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Horizontal Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Vertical Recoil\nby the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis item modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\naccurately apply counter-force against a gun's\nrecoil, during Burst or Autofire volleys.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis item modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, during Burst\nor Autofire volleys.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nThis item directly modifies the amount of\nAPs the character gets at the start of each turn.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifiest the AP cost to bring the weapon to\n'Ready' mode.\n \nLower is better.", + L"\n \nWhen attached to any weapon, this item\nmodifies the AP cost to make a single attack with\nthat weapon.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nBurst-fire mode, this item modifies the AP cost\nof firing a Burst.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon capable of\nAuto-fire mode, this item modifies the AP cost\nof firing an Autofire Volley.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the AP cost of reloading the weapon.\n \nLower is better.", + L"\n \nWhen attached to a ranged weapon, this item\nchanges the size of magazines that can be loaded\ninto the weapon.\n \nThat weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nWhen attached to a ranged weapon, this item\nmodifies the amount of bullets fired\nby the weapon in Burst mode.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, attaching it to the weapon\nwill enable burst-fire mode.\n \nConversely, if the weapon is initially Burst-Capable,\na high-enough negative modifier here can disable\nburst mode completely.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nWhen attached to a ranged weapon, this item\nwill hide the weapon's muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nWhen attached to a weapon, this item modifies\nthe range at which firing the weapon can be\nheard by both enemies and mercs.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nThis item modifies the size of any item it\nis attached to.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nWhen attached to any weapon, this item modifies\nthat weapon's Reliability value.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nwoodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nurban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\ndesert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's camouflage in\nsnowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's stealth ability by\nmaking it more difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Hearing Range by the\nlisted number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it modifies the wearer's Vision Range by the\nlisted number of tiles.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this item is worn, or attached to a worn\nitem, it changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]= +{ + L"\n \nThis weapon's accuracy is being modified by\nan ammo, attachment, or built-in attributes.\n \nIncreased accuracy allows the gun to hit targets\nat longer ranges more often, assuming it is\nalso well-aimed.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies its shooter's accuracy\nwith ANY shot by the listed percentage\nbased on the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed amount.\n \nScale: -100 to +100.\nHigher is better.", + L"\n \nThis weapon modifies the amount of accuracy\ngained from each extra aiming level you\npay for by the listed percentage, based\non the shooter's original accuracy.\n \nHigher is better.", + L"\n \nThe number of Extra Aiming Levels allowed\nfor this gun has been modified by its ammo,\nattachments, or built-in attributes.\nIf the number of levels is being reduced, the gun is\nfaster to aim without being any less accurate.\n \nConversely, if the number of levels is increased,\nthe gun becomes slower to aim without being\nmore accurate.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's maximum\naccuracy, as a percentage of the shooter's original\nmaximum accuracy.\n \nHigher is better.", + L"\n \nThis weapon's attachments or inherent abilities\nmodify the weapon's Handling difficulty.\n \nBetter handling makes the gun more accurate to fire,\nwith or without extra aiming.\n \nNote that this is based on the gun's original\nGun Handling factor, which is higher for rifles and\nheavy weapons, and lower for pistols and small\nweapons.\n \nLower is better.", + L"\n \nThis weapon's ability to compensate for shots\nbeyond its maximum range is being modified by\nattachments or the weapon's inherent abilities.\n \nA high bonus here can increase a weapon's\nnatural Maximum Range by at least a few tiles.\n \nHigher is better.", + L"\n \nThis weapon's ability to hit moving targets\nat a distance is being modified by attachments\nor the weapon's inherent abilities.\n \nA high bonus here can help hitting\nfast-moving targets, even at a distance.\n \nHigher is better.", + L"\n \nThis weapon's damage output is being modified\nby its ammo, attachments, or inherent abilities.\n \nHigher is better.", + L"\n \nThis weapon's melee-combat damage output is being\nmodified by its ammo, attachments, or inherent abilities.\n \nThis applies only to melee weapons, both sharp\nand blunt.\n \nHigher is better.", + L"\n \nThis weapon's maximum range has been increased\nor decreased thanks to its ammo, attachments,\nor inherent abilities.\n \nMaximum Range mainly dictates how far a bullet\nfired from the weapon can fly before it begins\ndropping sharply towards the ground.\n \nHigher is better.", + L"\n \nThis weapon is equipped with optical magnification,\nmaking shots at a distance comparatively easier to make.\n \nNote that a high Magnification Factor is detrimental\nwhen used at targets CLOSER than the\noptimal distance.\n \nHigher is better.", + L"\n \nThis weapon is equipped with a projection device\n(possibly a laser), which projects a dot on\nthe target, making it easier to hit.\n \nThe projection effect is only useful up to a given\ndistance, beyond which it begins to diminish and\neventually disappears.\n \nHigher is better.", + L"\n \nThis weapon's horizontal recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon's vertical recoil strength is being\nmodified by its ammo, attachments, or inherent\nabilities.\n \nThis has no effect if the weapon lacks both\nBurst and Auto-Fire modes.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", + L"\n \nThis weapon modifies the shooter's ability to\ncope with recoil during Burst or Autofire volleys,\ndue to its attachments, ammo, or inherent abilities.\n \nWhen high, this can help a shooter to control\nguns with powerful recoil, even if the shooter\nhas low Strength.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\naccurately apply counter-force against its\nrecoil, due to its attachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nA high bonus helps the shooter bring the gun's muzzle\nprecisely towards the target, even at longer ranges,\nmaking volleys more accurate as a result.\n \nHigher is better.", + L"\n \nThis weapon modifies the shooter's ability to\nfrequently reasses how much counter-force they\nneed to apply against a gun's recoil, due to its\nattachments, ammo, or inherent abilities.\n \nNaturally, this has no effect if the weapon lacks\nboth Burst and Auto-Fire modes.\n \nHigher frequency makes volleys more accurate on the whole,\nand also makes longer volleys more accurate assuming\nthe shooter can overcome recoil correctly.\n \nHigher is better.", + L"\n \nWhen held in hand, this weapon modifies the amount of\nAPs its user gets at the start of each turn.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to bring this weapon to 'Ready' mode has\nbeen modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to make a single attack with this\nweapon has been modified.\n \nNote that for Burst/Auto-capable weapons, the\ncost of using these modes is directly influenced\nby this modifier as well!\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire a Burst with this weapon has\nbeen modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Burst fire.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost to fire an Autofire Volley with this weapon\nhas been modified.\n \nNaturally, this has no effect if the weapon is not\ncapable of Auto Fire.\n \nNote that it does NOT modify the extra AP\ncost for adding bullets to the volley, only\nthe initial cost for starting the volley.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe AP cost of reloading this weapon has been modified.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe size of magazines that can be loaded into this\nweapon has been modified.\n \nThe weapon will now accept larger or smaller\nmagazines of the same caliber.\n \nHigher is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthe amount of bullets fired by this weapon in Burst mode\nhas been modified.\n \nIf the weapon was not initially Burst-Capable, and the\nmodifier is positive, then this is what\ngives the weapon its burst-fire capability.\n \nConversely, if the weapon was initially Burst-Capable,\na high-enough negative modifier here may have\ndisabled burst mode entirely for this weapon.\n \nHigher is USUALLY better. Of course, part of the\npoint in Burst Mode is to conserve bullets...", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon produces no muzzle flash.\n \nThis makes sure that enemies cannot spot the shooter\nif he is firing while hidden, and is especially\nimportant at night.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's loudness has been modified. The distance\nat which enemies and mercs can hear the weapon being\nused has subsequently changed.\n \nIf this modifier drops the weapon's Loudness value\nto 0, the weapon becomes completely silent.\n \nLower is better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's size category has changed.\n \nSize is important when using the New Inventory system,\nwhere pockets only accept items of specific sizes and shapes.\n \nIncreasing an item's size makes it too big for some pockets\nit used to fit into.\n \nConversely, making an item smaller means it will fit into\nmore pockets, and pockets will be able to contain\nmore of it.\n \nLower is generall better.", + L"\n \nDue to its attachments, ammo or inherent abilities,\nthis weapon's reliability has been modified.\n \nIf positive, the weapon's condition will deteriorate\nslower when used in combat. Otherwise, the\nweapon deteriorates faster.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in woodland backgrounds.\n \nTo make good on a positive Woodland Camo modifier, the\nwearer needs to stay close to trees or tall grass.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in urban backgrounds.\n \nTo make good on a positive Urban Camo modifier, the\nwearer needs to stay close to asphalt or concrete.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in desert backgrounds.\n \nTo make good on a positive Desert Camo modifier, the\nwearer needs to stay close to sand, gravel, or\ndesert vegetation.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's camouflage in snowy backgrounds.\n \nTo make good on a positive Snow Camo modifier, the\nwearer needs to stay close to snowy tiles.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's stealth ability by making it\nmore or less difficult to HEAR the character moving\nwhile in Sneaking mode.\n \nNote that this does NOT change a character's visibility,\nonly the amount of noise they make while sneaking.\n \nHigher is better.", + L"\n \nWhen this weapon is held in hand, it modifies the\nsoldier's Hearing Range by the listed number of tiles.\n \nA positive bonus makes it possible to hear noises\nfrom a greater distance.\n \nConversely, a negative modifier impairs the wearer's hearing.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis General modifier works in all conditions.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Night-Vision modifier works only when light\nlevels are sufficiently low.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Day-Vision modifier works only when light\nlevels are average or higher.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Bright-Vision modifier works only when light\nlevels are very high, for example when looking\ninto tiles lit by Break-Lights or at high noon.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit modifies the wearer's Vision Range by the\nlisted number of tiles, thanks to attachments or\ninherent properties of the weapon.\n \nThis Cave-Vision modifier works only in the dark\nand only underground.\n \nHigher is better.", + L"\n \nWhen this weapon is raised to the shooting position,\nit changes the wearer's field-of-view.\n \nNarrowing the field of view shortens sightrange to\neither side.\n \nLower is better.", +}; + +// HEADROCK HAM 4: Text for the new CTH indicator. +STR16 gzNCTHlabels[]= +{ + L"SINGLE", + L"AP", +}; +////////////////////////////////////////////////////// +// HEADROCK HAM 4: End new UDB texts and tooltips +////////////////////////////////////////////////////// + #endif //TAIWANESE diff --git a/Utils/bink.h b/Utils/bink.h new file mode 100644 index 00000000..0e068621 --- /dev/null +++ b/Utils/bink.h @@ -0,0 +1,694 @@ +#ifndef __BINKH__ +#define __BINKH__ + +#define BINKMAJORVERSION 1 +#define BINKMINORVERSION 5 +#define BINKSUBVERSION 10 +#define BINKVERSION "1.5J" +#define BINKDATE "2002-06-24" + +#ifndef __RADRES__ + +#ifndef __RADBASEH__ +#include "radbase.h" +#endif + +RADDEFSTART + +typedef struct BINK PTR4* HBINK; + +struct BINKIO; +typedef S32 (RADLINK PTR4* BINKIOOPEN) (struct BINKIO PTR4* Bnkio, const char PTR4 *name, U32 flags); +typedef U32 (RADLINK PTR4* BINKIOREADHEADER) (struct BINKIO PTR4* Bnkio, S32 Offset, void PTR4* Dest,U32 Size); +typedef U32 (RADLINK PTR4* BINKIOREADFRAME) (struct BINKIO PTR4* Bnkio, U32 Framenum,S32 origofs,void PTR4* dest,U32 size); +typedef U32 (RADLINK PTR4* BINKIOGETBUFFERSIZE)(struct BINKIO PTR4* Bnkio, U32 Size); +typedef void (RADLINK PTR4* BINKIOSETINFO) (struct BINKIO PTR4* Bnkio, void PTR4* Buf,U32 Size,U32 FileSize,U32 simulate); +typedef U32 (RADLINK PTR4* BINKIOIDLE) (struct BINKIO PTR4* Bnkio); +typedef void (RADLINK PTR4* BINKIOCLOSE) (struct BINKIO PTR4* Bnkio); + +typedef void (RADLINK PTR4* BINKCBSUSPEND) (struct BINKIO PTR4* Bnkio); +typedef S32 (RADLINK PTR4* BINKCBTRYSUSPEND) (struct BINKIO PTR4* Bnkio); +typedef void (RADLINK PTR4* BINKCBRESUME) (struct BINKIO PTR4* Bnkio); +typedef void (RADLINK PTR4* BINKCBIDLE) (struct BINKIO PTR4* Bnkio); + +struct BINKIO +{ + BINKIOREADHEADER ReadHeader; + BINKIOREADFRAME ReadFrame; + BINKIOGETBUFFERSIZE GetBufferSize; + BINKIOSETINFO SetInfo; + BINKIOIDLE Idle; + BINKIOCLOSE Close; + HBINK bink; + volatile U32 ReadError; + volatile U32 DoingARead; + volatile U32 BytesRead; + volatile U32 Working; + volatile U32 TotalTime; + volatile U32 ForegroundTime; + volatile U32 IdleTime; + volatile U32 ThreadTime; + volatile U32 BufSize; + volatile U32 BufHighUsed; + volatile U32 CurBufSize; + volatile U32 CurBufUsed; + volatile U8 iodata[128+32]; + + // filled in by the caller + BINKCBSUSPEND suspend_callback; + BINKCBTRYSUSPEND try_suspend_callback; + BINKCBRESUME resume_callback; + BINKCBIDLE idle_on_callback; + volatile U32 callback_control[16]; // buffer for background IO callback +}; + +struct BINKSND; +typedef S32 (RADLINK PTR4* BINKSNDOPEN) (struct BINKSND PTR4* BnkSnd, U32 freq, S32 bits, S32 chans, U32 flags, HBINK bink); +typedef S32 (RADLINK PTR4* BINKSNDREADY) (struct BINKSND PTR4* BnkSnd); +typedef S32 (RADLINK PTR4* BINKSNDLOCK) (struct BINKSND PTR4* BnkSnd, U8 PTR4* PTR4* addr, U32 PTR4* len); +typedef S32 (RADLINK PTR4* BINKSNDUNLOCK) (struct BINKSND PTR4* BnkSnd, U32 filled); +typedef void (RADLINK PTR4* BINKSNDVOLUME) (struct BINKSND PTR4* BnkSnd, S32 volume); +typedef void (RADLINK PTR4* BINKSNDPAN) (struct BINKSND PTR4* BnkSnd, S32 pan); +typedef void (RADLINK PTR4* BINKSNDMIXBINS) (struct BINKSND PTR4* BnkSnd, U32 PTR4* mix_bins, U32 total); +typedef void (RADLINK PTR4* BINKSNDMIXBINVOLS) (struct BINKSND PTR4* BnkSnd, U32 PTR4* vol_mix_bins, S32 PTR4* volumes, U32 total ); +typedef S32 (RADLINK PTR4* BINKSNDONOFF) (struct BINKSND PTR4* BnkSnd, S32 status); +typedef S32 (RADLINK PTR4* BINKSNDPAUSE) (struct BINKSND PTR4* BnkSnd, S32 status); +typedef void (RADLINK PTR4* BINKSNDCLOSE) (struct BINKSND PTR4* BnkSnd); + +typedef BINKSNDOPEN (RADLINK PTR4* BINKSNDSYSOPEN) (U32 param); + +struct BINKSND +{ + BINKSNDREADY Ready; + BINKSNDLOCK Lock; + BINKSNDUNLOCK Unlock; + BINKSNDVOLUME Volume; + BINKSNDPAN Pan; + BINKSNDPAUSE Pause; + BINKSNDONOFF SetOnOff; + BINKSNDCLOSE Close; + BINKSNDMIXBINS MixBins; + BINKSNDMIXBINVOLS MixBinVols; + + U32 sndbufsize; // sound buffer size + U8 PTR4* sndbuf; // sound buffer + U8 PTR4* sndend; // end of the sound buffer + U8 PTR4* sndwritepos; // current write position + U8 PTR4* sndreadpos; // current read position + U32 sndcomp; // sound compression handle + U32 sndamt; // amount of sound currently in the buffer + U32 sndconvert8; // convert back to 8-bit sound at runtime + U32 sndendframe; // frame number that the sound ends on + U32 sndprime; // amount of data to prime the playahead + U32 sndpad; // padded this much audio + + U32 BestSizeIn16; + U32 BestSizeMask; + U32 SoundDroppedOut; + S32 OnOff; + U32 Latency; + U32 VideoScale; + U32 freq; + S32 bits,chans; + U8 snddata[256]; +}; + +struct BINKRECT +{ + S32 Left,Top,Width,Height; +}; + +#define BINKMAXDIRTYRECTS 8 + +struct BUNDLEPOINTERS +{ + void* typeptr; + void* type16ptr; + void* colorptr; + void* bits2ptr; + void* motionXptr; + void* motionYptr; + void* dctptr; + void* mdctptr; + void* patptr; +}; + + +struct BINK +{ + U32 Width; // Width (1 based, 640 for example) + U32 Height; // Height (1 based, 480 for example) + U32 Frames; // Number of frames (1 based, 100 = 100 frames) + U32 FrameNum; // Frame to *be* displayed (1 based) + U32 LastFrameNum; // Last frame decompressed or skipped (1 based) + + U32 FrameRate; // Frame Rate Numerator + U32 FrameRateDiv; // Frame Rate Divisor (frame rate=numerator/divisor) + + U32 ReadError; // Non-zero if a read error has ocurred + U32 OpenFlags; // flags used on open + U32 BinkType; // Bink flags + + U32 Size; // size of file + U32 FrameSize; // The current frame's size in bytes + U32 SndSize; // The current frame sound tracks' size in bytes + + BINKRECT FrameRects[BINKMAXDIRTYRECTS];// Dirty rects from BinkGetRects + S32 NumRects; + + U32 PlaneNum; // which set of planes is current + void PTR4* YPlane[2]; // pointer to the uncompressed Y (Cr and Cr follow) + void PTR4* APlane[2]; // decompressed alpha plane (if present) + U32 YWidth; // widths and heights of the video planes + U32 YHeight; + U32 UVWidth; + U32 UVHeight; + + void PTR4* MaskPlane; // pointer to the mask plane (Ywidth/16*Yheight/16) + U32 MaskPitch; // Mask Pitch + U32 MaskLength; // total length of the mask plane + + U32 LargestFrameSize; // Largest frame size + U32 InternalFrames; // how many frames were potentially compressed + + S32 NumTracks; // how many tracks + + U32 Highest1SecRate; // Highest 1 sec data rate + U32 Highest1SecFrame; // Highest 1 sec data rate starting frame + + S32 Paused; // is the bink movie paused? + + U32 BackgroundThread; // handle to background thread + + // everything below is for internal Bink use + + void PTR4* compframe; // compressed frame data + void PTR4* preloadptr; // preloaded compressed frame data + U32* frameoffsets; // offsets of each of the frames + + BINKIO bio; // IO structure + U8 PTR4* ioptr; // io buffer ptr + U32 iosize; // io buffer size + U32 decompwidth; // width not include scaling + U32 decompheight; // height not include scaling + + S32 PTR4* trackindexes; // track indexes + U32 PTR4* tracksizes; // largest single frame of track + U32 PTR4* tracktypes; // type of each sound track + S32 PTR4* trackIDs; // external track numbers + + U32 numrects; // number of rects from BinkGetRects + + U32 playedframes; // how many frames have we played + U32 firstframetime; // very first frame start + U32 startframetime; // start frame start + U32 startblittime; // start of blit period + U32 startsynctime; // start of synched time + U32 startsyncframe; // frame of startsynctime + U32 twoframestime; // two frames worth of time + U32 entireframetime; // entire frame time + + U32 slowestframetime; // slowest frame in ms + U32 slowestframe; // slowest frame number + U32 slowest2frametime; // second slowest frame in ms + U32 slowest2frame; // second slowest frame + + U32 soundon; // sound turned on? + U32 videoon; // video turned on? + + U32 totalmem; // total memory used + U32 timevdecomp; // total time decompressing video + U32 timeadecomp; // total time decompressing audio + U32 timeblit; // total time blitting + U32 timeopen; // total open time + + U32 fileframerate; // frame rate originally in the file + U32 fileframeratediv; + + U32 runtimeframes; // max frames for runtime analysis + U32 runtimemoveamt; // bytes to move each frame + U32 PTR4* rtframetimes; // start times for runtime frames + U32 PTR4* rtadecomptimes; // decompress times for runtime frames + U32 PTR4* rtvdecomptimes; // decompress times for runtime frames + U32 PTR4* rtblittimes; // blit times for runtime frames + U32 PTR4* rtreadtimes; // read times for runtime frames + U32 PTR4* rtidlereadtimes; // idle read times for runtime frames + U32 PTR4* rtthreadreadtimes; // thread read times for runtime frames + + U32 lastblitflags; // flags used on last blit + U32 lastdecompframe; // last frame number decompressed + + U32 playingtracks; // how many tracks are playing + U32 soundskips; // number of sound stops + BINKSND PTR4* bsnd; // SND structures + U32 skippedlastblit; // skipped last frame? + U32 skipped_this_frame; // skipped the current frame? + U32 skippedblits; // how many blits were skipped + + BUNDLEPOINTERS bunp; // pointers to internal temporary memory + U32 skipped_in_a_row; // how many frames have we skipped in a row + U32 big_sound_skip_adj; // adjustment for large skips + U32 big_sound_skip_reduce; // amount to reduce large skips by each frame + U32 last_time_almost_empty; // time of last almost empty IO buffer + U32 last_read_count; // counter to keep track of the last bink IO + U32 last_sound_count; // counter to keep track of the last bink sound + U32 snd_callback_buffer[16];// buffer for background sound callback +}; + + +struct BINKSUMMARY +{ + U32 Width; // Width of frames + U32 Height; // Height of frames + U32 TotalTime; // total time (ms) + U32 FileFrameRate; // frame rate + U32 FileFrameRateDiv; // frame rate divisor + U32 FrameRate; // frame rate + U32 FrameRateDiv; // frame rate divisor + U32 TotalOpenTime; // Time to open and prepare for decompression + U32 TotalFrames; // Total Frames + U32 TotalPlayedFrames; // Total Frames played + U32 SkippedFrames; // Total number of skipped frames + U32 SkippedBlits; // Total number of skipped blits + U32 SoundSkips; // Total number of sound skips + U32 TotalBlitTime; // Total time spent blitting + U32 TotalReadTime; // Total time spent reading + U32 TotalVideoDecompTime; // Total time spent decompressing video + U32 TotalAudioDecompTime; // Total time spent decompressing audio + U32 TotalIdleReadTime; // Total time spent reading while idle + U32 TotalBackReadTime; // Total time spent reading in background + U32 TotalReadSpeed; // Total io speed (bytes/second) + U32 SlowestFrameTime; // Slowest single frame time (ms) + U32 Slowest2FrameTime; // Second slowest single frame time (ms) + U32 SlowestFrameNum; // Slowest single frame number + U32 Slowest2FrameNum; // Second slowest single frame number + U32 AverageDataRate; // Average data rate of the movie + U32 AverageFrameSize; // Average size of the frame + U32 HighestMemAmount; // Highest amount of memory allocated + U32 TotalIOMemory; // Total extra memory allocated + U32 HighestIOUsed; // Highest extra memory actually used + U32 Highest1SecRate; // Highest 1 second rate + U32 Highest1SecFrame; // Highest 1 second start frame +}; + + +struct BINKREALTIME +{ + U32 FrameNum; // Current frame number + U32 FrameRate; // frame rate + U32 FrameRateDiv; // frame rate divisor + U32 Frames; // frames in this sample period + U32 FramesTime; // time is ms for these frames + U32 FramesVideoDecompTime; // time decompressing these frames + U32 FramesAudioDecompTime; // time decompressing these frames + U32 FramesReadTime; // time reading these frames + U32 FramesIdleReadTime; // time reading these frames at idle + U32 FramesThreadReadTime; // time reading these frames in background + U32 FramesBlitTime; // time blitting these frames + U32 ReadBufferSize; // size of read buffer + U32 ReadBufferUsed; // amount of read buffer currently used + U32 FramesDataRate; // data rate for these frames +}; + +#define BINKMARKER1 'fKIB' +#define BINKMARKER2 'gKIB' // new Bink files use this tag +#define BINKMARKER3 'hKIB' // newer Bink files use this tag +#define BINKMARKER4 'iKIB' // even newer Bink files use this tag + +struct BINKHDR +{ + U32 Marker; // Bink marker + U32 Size; // size of the file-8 + U32 Frames; // Number of frames (1 based, 100 = 100 frames) + U32 LargestFrameSize; // Size in bytes of largest frame + U32 InternalFrames; // Number of internal frames + + U32 Width; // Width (1 based, 640 for example) + U32 Height; // Height (1 based, 480 for example) + U32 FrameRate; // frame rate + U32 FrameRateDiv; // frame rate divisor (framerate/frameratediv=fps) + + U32 Flags; // height compression options + U32 NumTracks; // number of tracks +}; + + +//======================================================================= +#define BINKFRAMERATE 0x00001000L // Override fr (call BinkFrameRate first) +#define BINKPRELOADALL 0x00002000L // Preload the entire animation +#define BINKSNDTRACK 0x00004000L // Set the track number to play +#define BINKOLDFRAMEFORMAT 0x00008000L // using the old Bink frame format (internal use only) +#define BINKRBINVERT 0x00010000L // use reversed R and B planes (internal use only) +#define BINKGRAYSCALE 0x00020000L // Force Bink to use grayscale +#define BINKNOMMX 0x00040000L // Don't use MMX +#define BINKNOSKIP 0x00080000L // Don't skip frames if falling behind +#define BINKALPHA 0x00100000L // Decompress alpha plane (if present) +#define BINKNOFILLIOBUF 0x00200000L // Fill the IO buffer in SmackOpen +#define BINKSIMULATE 0x00400000L // Simulate the speed (call BinkSim first) +#define BINKFILEHANDLE 0x00800000L // Use when passing in a file handle +#define BINKIOSIZE 0x01000000L // Set an io size (call BinkIOSize first) +#define BINKIOPROCESSOR 0x02000000L // Set an io processor (call BinkIO first) +#define BINKFROMMEMORY 0x04000000L // Use when passing in a pointer to the file +#define BINKNOTHREADEDIO 0x08000000L // Don't use a background thread for IO + +#define BINKSURFACEFAST 0x00000000L +#define BINKSURFACESLOW 0x08000000L +#define BINKSURFACEDIRECT 0x04000000L + +#define BINKCOPYALL 0x80000000L // copy all pixels (not just changed) +#define BINKCOPY2XH 0x10000000L // Force doubling height scaling +#define BINKCOPY2XHI 0x20000000L // Force interleaving height scaling +#define BINKCOPY2XW 0x30000000L // copy the width zoomed by two +#define BINKCOPY2XWH 0x40000000L // copy the width and height zoomed by two +#define BINKCOPY2XWHI 0x50000000L // copy the width and height zoomed by two +#define BINKCOPY1XI 0x60000000L // copy the width and height zoomed by two +#define BINKCOPYNOSCALING 0x70000000L // Force scaling off + +//#define BINKALPHA 0x00100000L // Decompress alpha plane (if present) +//#define BINKNOSKIP 0x00080000L // don't skip the blit if behind in sound +//#define BINKNOMMX 0x00040000L // Don't skip frames if falling behind +//#define BINKGRAYSCALE 0x00020000L // force Bink to use grayscale +//#define BINKRBINVERT 0x00010000L // use reversed R and B planes + +#define BINKSURFACE8P 0 +#define BINKSURFACE24 1 +#define BINKSURFACE24R 2 +#define BINKSURFACE32 3 +#define BINKSURFACE32R 4 +#define BINKSURFACE32A 5 +#define BINKSURFACE32RA 6 +#define BINKSURFACE4444 7 +#define BINKSURFACE5551 8 +#define BINKSURFACE555 9 +#define BINKSURFACE565 10 +#define BINKSURFACE655 11 +#define BINKSURFACE664 12 +#define BINKSURFACEYUY2 13 +#define BINKSURFACEUYVY 14 +#define BINKSURFACEYV12 15 +#define BINKSURFACEMASK 15 + +#ifdef __RADXBOX__ + +#define BINKSURFACESALL 32 +#define BINKCONVERTERSMONO 64 +#define BINKCONVERTERS2X 256 + +#define BINKCONVERTERSALL (BINKSURFACESALL|BINKCONVERTERSMONO|BINKCONVERTERS2X) + +#define BinkLoad() BinkLoadUnload(1) +#define BinkUnload() BinkLoadUnload(0) + +#define BinkLoadConverter(val) BinkLoadUnloadConverter(val,1) +#define BinkUnloadConverter(val) BinkLoadUnloadConverter(val,0) + +RADEXPFUNC void RADEXPLINK BinkLoadUnload( S32 inout ); +RADEXPFUNC void RADEXPLINK BinkLoadUnloadConverter( U32 surfaces, S32 inout ); + +#endif + +#define BINKGOTOQUICK 1 +#define BINKGOTOQUICKSOUND 2 + +#define BINKGETKEYPREVIOUS 0 +#define BINKGETKEYNEXT 1 +#define BINKGETKEYCLOSEST 2 +#define BINKGETKEYNOTEQUAL 128 + +//======================================================================= + +#ifdef __RADMAC__ + #include + + #pragma export on + + RADEXPFUNC HBINK RADEXPLINK BinkMacOpen(FSSpec* fsp,U32 flags); +#endif + +RADEXPFUNC void PTR4* RADEXPLINK BinkLogoAddress(void); + +RADEXPFUNC void RADEXPLINK BinkSetError(const char PTR4* err); +RADEXPFUNC char PTR4* RADEXPLINK BinkGetError(void); + +RADEXPFUNC HBINK RADEXPLINK BinkOpen(const char PTR4* name,U32 flags); + +RADEXPFUNC S32 RADEXPLINK BinkDoFrame(HBINK bnk); +RADEXPFUNC void RADEXPLINK BinkNextFrame(HBINK bnk); +RADEXPFUNC S32 RADEXPLINK BinkWait(HBINK bnk); +RADEXPFUNC void RADEXPLINK BinkClose(HBINK bnk); +RADEXPFUNC S32 RADEXPLINK BinkPause(HBINK bnk,S32 pause); +RADEXPFUNC S32 RADEXPLINK BinkCopyToBuffer(HBINK bnk,void* dest,S32 destpitch,U32 destheight,U32 destx,U32 desty,U32 flags); +RADEXPFUNC S32 RADEXPLINK BinkCopyToBufferRect(HBINK bnk,void* dest,S32 destpitch,U32 destheight,U32 destx,U32 desty,U32 srcx, U32 srcy, U32 srcw, U32 srch, U32 flags); +RADEXPFUNC S32 RADEXPLINK BinkGetRects(HBINK bnk,U32 flags); +RADEXPFUNC void RADEXPLINK BinkGoto(HBINK bnk,U32 frame,S32 flags); // use 1 for the first frame +RADEXPFUNC U32 RADEXPLINK BinkGetKeyFrame(HBINK bnk,U32 frame,S32 flags); + +RADEXPFUNC S32 RADEXPLINK BinkSetVideoOnOff(HBINK bnk,S32 onoff); +RADEXPFUNC S32 RADEXPLINK BinkSetSoundOnOff(HBINK bnk,S32 onoff); +RADEXPFUNC void RADEXPLINK BinkSetVolume(HBINK bnk, U32 trackid, S32 volume); +RADEXPFUNC void RADEXPLINK BinkSetPan(HBINK bnk,U32 trackid, S32 pan); +RADEXPFUNC void RADEXPLINK BinkSetMixBins(HBINK bnk,U32 trackid, U32 PTR4* mix_bins, U32 total); +RADEXPFUNC void RADEXPLINK BinkSetMixBinVolumes(HBINK bnk,U32 trackid, U32 PTR4* vol_mix_bins, S32 PTR4* volumes, U32 total); +RADEXPFUNC void RADEXPLINK BinkService(HBINK bink); + +typedef struct BINKTRACK PTR4* HBINKTRACK; + +typedef struct BINKTRACK +{ + U32 Frequency; + U32 Bits; + U32 Channels; + U32 MaxSize; + + HBINK bink; + U32 sndcomp; + S32 trackindex; +} BINKTRACK; + + +RADEXPFUNC HBINKTRACK RADEXPLINK BinkOpenTrack(HBINK bnk,U32 trackindex); +RADEXPFUNC void RADEXPLINK BinkCloseTrack(HBINKTRACK bnkt); +RADEXPFUNC U32 RADEXPLINK BinkGetTrackData(HBINKTRACK bnkt,void PTR4* dest); + +RADEXPFUNC U32 RADEXPLINK BinkGetTrackType(HBINK bnk,U32 trackindex); +RADEXPFUNC U32 RADEXPLINK BinkGetTrackMaxSize(HBINK bnk,U32 trackindex); +RADEXPFUNC U32 RADEXPLINK BinkGetTrackID(HBINK bnk,U32 trackindex); + +RADEXPFUNC void RADEXPLINK BinkGetSummary(HBINK bnk,BINKSUMMARY PTR4* sum); +RADEXPFUNC void RADEXPLINK BinkGetRealtime(HBINK bink,BINKREALTIME PTR4* run,U32 frames); + +RADEXPFUNC void RADEXPLINK BinkSetSoundTrack(U32 total_tracks, U32 PTR4* tracks); +RADEXPFUNC void RADEXPLINK BinkSetIO(BINKIOOPEN io); +RADEXPFUNC void RADEXPLINK BinkSetFrameRate(U32 forcerate,U32 forceratediv); +RADEXPFUNC void RADEXPLINK BinkSetSimulate(U32 sim); +RADEXPFUNC void RADEXPLINK BinkSetIOSize(U32 iosize); + +RADEXPFUNC S32 RADEXPLINK BinkSetSoundSystem(BINKSNDSYSOPEN open, U32 param); + +#ifdef __RADWIN__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenDirectSound(U32 param); // don't call directly + #define BinkSoundUseDirectSound(lpDS) BinkSetSoundSystem(BinkOpenDirectSound,(U32)lpDS) + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenWaveOut(U32 param); // don't call directly + #define BinkSoundUseWaveOut() BinkSetSoundSystem(BinkOpenWaveOut,0) + +#endif + + +#ifndef __RADMAC__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenMiles(U32 param); // don't call directly + #define BinkSoundUseMiles(hdigdriver) BinkSetSoundSystem(BinkOpenMiles,(U32)hdigdriver) + +#endif + + +#ifdef __RADMAC__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenSoundManager(U32 param); // don't call directly + #define BinkSoundUseSoundManager() BinkSetSoundSystem(BinkOpenSoundManager,0) + +#endif + +#ifdef __RADNGC__ + + #ifdef __RADNGC__ + RADEXPFUNC void RADEXPLINK RADSetAudioMemory(RADMEMALLOC a,RADMEMFREE f); + RADEXPFUNC void PTR4* RADEXPLINK radaudiomalloc(U32 numbytes); + RADEXPFUNC void RADEXPLINK radaudiofree(void PTR4* ptr); + #endif + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenNGCSound(U32 param); // don't call directly + #define BinkSoundUseNGCSound() BinkSetSoundSystem(BinkOpenNGCSound,0) + +#endif + +#if defined(__RADXBOX__) || defined(__RADWIN__) + +RADEXPFUNC S32 RADEXPLINK BinkDX8SurfaceType(void* lpD3Ds); + +#endif + + +// The BinkBuffer API isn't implemented on DOS, Xbox or GameCube +#if !defined(__RADDOS__) && !defined(__RADXBOX__) && !defined(__RADNGC__) + +//========================================================================= +typedef struct BINKBUFFER * HBINKBUFFER; + +#define BINKBUFFERSTRETCHXINT 0x80000000 +#define BINKBUFFERSTRETCHX 0x40000000 +#define BINKBUFFERSHRINKXINT 0x20000000 +#define BINKBUFFERSHRINKX 0x10000000 +#define BINKBUFFERSTRETCHYINT 0x08000000 +#define BINKBUFFERSTRETCHY 0x04000000 +#define BINKBUFFERSHRINKYINT 0x02000000 +#define BINKBUFFERSHRINKY 0x01000000 +#define BINKBUFFERSCALES 0xff000000 +#define BINKBUFFERRESOLUTION 0x00800000 + +#ifdef __RADMAC__ + +#include +#include +#include + +struct BINKBUFFER +{ + U32 Width; + U32 Height; + U32 WindowWidth; + U32 WindowHeight; + U32 SurfaceType; + void* Buffer; + S32 BufferPitch; + U32 ScreenWidth; + U32 ScreenHeight; + U32 ScreenDepth; + U32 ScaleFlags; + + S32 destx,desty; + S32 wndx,wndy; + U32 wnd; + + S32 noclipping; + U32 type; + S32 issoftcur; + U32 cursorcount; +}; + + +#define BINKBUFFERAUTO 0 +#define BINKBUFFERDIRECT 1 +#define BINKBUFFERGWORLD 2 +#define BINKBUFFERTYPEMASK 31 + +RADEXPFUNC HBINKBUFFER RADEXPLINK BinkBufferOpen( WindowPtr wnd, U32 width, U32 height, U32 bufferflags); +RADEXPFUNC S32 RADEXPLINK BinkGDSurfaceType( GDHandle gd ); +RADEXPFUNC S32 RADEXPLINK BinkIsSoftwareCursor(GDHandle gd); +RADEXPFUNC S32 RADEXPLINK BinkCheckCursor(WindowPtr wp,S32 x,S32 y,S32 w,S32 h); + +#else + +struct BINKBUFFER +{ + U32 Width; + U32 Height; + U32 WindowWidth; + U32 WindowHeight; + U32 SurfaceType; + void* Buffer; + S32 BufferPitch; + S32 ClientOffsetX; + S32 ClientOffsetY; + U32 ScreenWidth; + U32 ScreenHeight; + U32 ScreenDepth; + U32 ExtraWindowWidth; + U32 ExtraWindowHeight; + U32 ScaleFlags; + U32 StretchWidth; + U32 StretchHeight; + + S32 surface; + void* ddsurface; + void* ddclipper; + S32 destx,desty; + S32 wndx,wndy; + U32 wnd; + S32 ddoverlay; + S32 ddoffscreen; + S32 lastovershow; + + S32 issoftcur; + U32 cursorcount; + void* buffertop; + U32 type; + S32 noclipping; + + S32 loadeddd; + S32 loadedwin; + + void* dibh; + void* dibbuffer; + S32 dibpitch; + void* dibinfo; + U32 dibdc; + U32 diboldbitmap; +}; + + +#define BINKBUFFERAUTO 0 +#define BINKBUFFERPRIMARY 1 +#define BINKBUFFERDIBSECTION 2 +#define BINKBUFFERYV12OVERLAY 3 +#define BINKBUFFERYUY2OVERLAY 4 +#define BINKBUFFERUYVYOVERLAY 5 +#define BINKBUFFERYV12OFFSCREEN 6 +#define BINKBUFFERYUY2OFFSCREEN 7 +#define BINKBUFFERUYVYOFFSCREEN 8 +#define BINKBUFFERRGBOFFSCREENVIDEO 9 +#define BINKBUFFERRGBOFFSCREENSYSTEM 10 +#define BINKBUFFERLAST 10 +#define BINKBUFFERTYPEMASK 31 + +RADEXPFUNC HBINKBUFFER RADEXPLINK BinkBufferOpen( void* /*HWND*/ wnd, U32 width, U32 height, U32 bufferflags); +RADEXPFUNC S32 RADEXPLINK BinkBufferSetHWND( HBINKBUFFER buf, void* /*HWND*/ newwnd); +RADEXPFUNC S32 RADEXPLINK BinkDDSurfaceType(void PTR4* lpDDS); +RADEXPFUNC S32 RADEXPLINK BinkIsSoftwareCursor(void PTR4* lpDDSP, void* /*HCURSOR*/ cur); +RADEXPFUNC S32 RADEXPLINK BinkCheckCursor(void* /*HWND*/ wnd,S32 x,S32 y,S32 w,S32 h); +RADEXPFUNC S32 RADEXPLINK BinkBufferSetDirectDraw(void PTR4* lpDirectDraw, void PTR4* lpPrimary); + +#endif + +RADEXPFUNC void RADEXPLINK BinkBufferClose( HBINKBUFFER buf); +RADEXPFUNC S32 RADEXPLINK BinkBufferLock( HBINKBUFFER buf); +RADEXPFUNC S32 RADEXPLINK BinkBufferUnlock( HBINKBUFFER buf); +RADEXPFUNC void RADEXPLINK BinkBufferSetResolution( S32 w, S32 h, S32 bits); +RADEXPFUNC void RADEXPLINK BinkBufferCheckWinPos( HBINKBUFFER buf, S32 PTR4* NewWindowX, S32 PTR4* NewWindowY); +RADEXPFUNC S32 RADEXPLINK BinkBufferSetOffset( HBINKBUFFER buf, S32 destx, S32 desty); +RADEXPFUNC void RADEXPLINK BinkBufferBlit( HBINKBUFFER buf, BINKRECT PTR4* rects, U32 numrects ); +RADEXPFUNC S32 RADEXPLINK BinkBufferSetScale( HBINKBUFFER buf, U32 w, U32 h); +RADEXPFUNC char PTR4* RADEXPLINK BinkBufferGetDescription( HBINKBUFFER buf); +RADEXPFUNC char PTR4* RADEXPLINK BinkBufferGetError(); +RADEXPFUNC S32 RADEXPLINK BinkBufferClear(HBINKBUFFER buf, U32 RGB); + +RADEXPFUNC void RADEXPLINK BinkRestoreCursor(S32 checkcount); + +#endif + +#ifdef __RADMAC__ + +#pragma export off + +#endif + +RADDEFEND + +#endif + +// @cdep pre $set(INCs,$INCs -I$clipfilename($file)) $ignore(TakeCPP) + +#endif + diff --git a/Utils/message.cpp b/Utils/message.cpp index 299f0393..2f695ead 100644 --- a/Utils/message.cpp +++ b/Utils/message.cpp @@ -24,11 +24,9 @@ #include #include "Game Clock.h" #include "GameSettings.h" + #include "sgp_logger.h" #endif -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" - typedef struct { UINT32 uiFont; @@ -1515,6 +1513,13 @@ void ClearTacticalMessageQueue( void ) return; } +static struct DebugMessageLog { + sgp::Logger_ID id; + DebugMessageLog() { + id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(id, L"DebugMessage.txt", true, sgp::Logger::FLUSH_ON_ENDL); + } +} s_DebugMessageLog; void WriteMessageToFile( const STR16 pString ) { #ifdef JA2BETAVERSION @@ -1531,8 +1536,7 @@ void WriteMessageToFile( const STR16 pString ) fprintf( fp, "%S\n", pString ); fclose( fp ); #else - static CLog& debugMessage = *CLog::create(L"DebugMessage.txt", true, CLog::FLUSH_IMMEDIATELY); - debugMessage << pString << CLog::ENDL; + SGP_LOG(s_DebugMessageLog.id, pString); #endif #endif } diff --git a/binkw32.lib b/binkw32.lib new file mode 100644 index 00000000..3962a328 Binary files /dev/null and b/binkw32.lib differ diff --git a/builddefines.h b/builddefines.h index a378ad28..ebe4b098 100644 --- a/builddefines.h +++ b/builddefines.h @@ -55,6 +55,7 @@ // but for now, just tell the compiler to shut up so I can see the real errors. #define _CRT_SECURE_NO_WARNINGS #define _CRT_NON_CONFORMING_SWPRINTFS +#define _SCL_SECURE_NO_WARNINGS #include "Profiler.h" diff --git a/ext/libpng/projects/visualc71/libpng_VS2005.vcproj b/ext/libpng/projects/visualc71/libpng_VS2005.vcproj new file mode 100644 index 00000000..2c5d9f6c --- /dev/null +++ b/ext/libpng/projects/visualc71/libpng_VS2005.vcproj @@ -0,0 +1,600 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/libpng/projects/visualc71/libpng_VS2008.vcproj b/ext/libpng/projects/visualc71/libpng_VS2008.vcproj new file mode 100644 index 00000000..67297d2b --- /dev/null +++ b/ext/libpng/projects/visualc71/libpng_VS2008.vcproj @@ -0,0 +1,601 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/libpng/projects/visualc71/libpng_VS2010.vcxproj b/ext/libpng/projects/visualc71/libpng_VS2010.vcxproj new file mode 100644 index 00000000..bc132786 --- /dev/null +++ b/ext/libpng/projects/visualc71/libpng_VS2010.vcxproj @@ -0,0 +1,234 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {735F8DBF-6646-4713-BE36-394F33E69B57} + Win32Proj + libpng + libpng + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + + + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;DEBUG;PNG_NO_MMX_CODE;PNG_DEBUG=1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\..;..\..\..\zlib + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;DEBUG;PNG_NO_MMX_CODE;PNG_DEBUG=1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\..;..\..\..\zlib + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;PNG_NO_MMX_CODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\..;..\..\..\zlib + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;PNG_NO_MMX_CODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\..;..\..\..\zlib + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;PNG_NO_MMX_CODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\..;..\..\..\zlib + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ext/libpng/projects/visualc71/libpng_VS2010.vcxproj.filters b/ext/libpng/projects/visualc71/libpng_VS2010.vcxproj.filters new file mode 100644 index 00000000..a84818e8 --- /dev/null +++ b/ext/libpng/projects/visualc71/libpng_VS2010.vcxproj.filters @@ -0,0 +1,77 @@ + + + + + {f974ac0b-3646-4b90-8e5f-51a46256df06} + + + {31a7bc63-311b-4c58-9584-0f94180249db} + + + {f272cbf7-9683-4e0f-bd9b-90ca48d9ed13} + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/ext/libpng/projects/visualc71/zlib_VS2005.vcproj b/ext/libpng/projects/visualc71/zlib_VS2005.vcproj new file mode 100644 index 00000000..0a43a4bb --- /dev/null +++ b/ext/libpng/projects/visualc71/zlib_VS2005.vcproj @@ -0,0 +1,532 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/libpng/projects/visualc71/zlib_VS2008.vcproj b/ext/libpng/projects/visualc71/zlib_VS2008.vcproj new file mode 100644 index 00000000..882d905c --- /dev/null +++ b/ext/libpng/projects/visualc71/zlib_VS2008.vcproj @@ -0,0 +1,525 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ext/libpng/projects/visualc71/zlib_VS2010.vcxproj b/ext/libpng/projects/visualc71/zlib_VS2010.vcxproj new file mode 100644 index 00000000..70815bbf --- /dev/null +++ b/ext/libpng/projects/visualc71/zlib_VS2010.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {EC27EB68-C428-4B80-8170-D93F988EA34C} + Win32Proj + zlib + zlib + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\..\..\..\lib\VS2010\$(Configuration)\ + ..\..\..\..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ..\..\..\zlib + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + ..\..\..\zlib + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/ext/libpng/projects/visualc71/zlib_VS2010.vcxproj.filters b/ext/libpng/projects/visualc71/zlib_VS2010.vcxproj.filters new file mode 100644 index 00000000..217e7c86 --- /dev/null +++ b/ext/libpng/projects/visualc71/zlib_VS2010.vcxproj.filters @@ -0,0 +1,97 @@ + + + + + {b4b80c3f-19ca-4a99-b246-9d7425950685} + + + {d0147fb0-ff9b-4e8e-94d2-af58b3a7316e} + + + {067a2703-3d08-4172-9b70-3f64cf7f12d2} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/gameloop.cpp b/gameloop.cpp index 01e47cd9..6d5a6442 100644 --- a/gameloop.cpp +++ b/gameloop.cpp @@ -33,8 +33,14 @@ #include "Map Screen Interface Map Inventory.h"//dnl ch51 081009 #endif -#include "Lua Interpreter.h" +#include "SaveLoadScreen.h" +#include "Lua Interpreter.h" +//**ddd direct link libraries +#pragma comment (lib, "user32.lib") +#pragma comment (lib, "gdi32.lib") +#pragma comment (lib, "advapi32.lib") +#pragma comment (lib, "shell32.lib") // rain #include "Rain.h" // end rain @@ -57,6 +63,8 @@ UINT8 gubCheckForFreeSpaceOnHardDriveCount=DONT_CHECK_FOR_FREE_SPACE; extern BOOLEAN DoSkiMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback ); extern void NotEnoughHardDriveSpaceForQuickSaveMessageBoxCallBack( UINT8 bExitValue ); +extern BOOLEAN gfTacticalPlacementGUIActive; +extern BOOLEAN gfTacticalPlacementGUIDirty; extern BOOLEAN gfValidLocationsChanged; extern BOOLEAN gfInMsgBox; extern BOOLEAN gfInChatBox; // OJW - 20090314 - new chatbox @@ -116,6 +124,12 @@ BOOLEAN InitializeGame(void) // Moved this up because some settings are used during other inits LoadGameAPBPConstants(); LoadGameExternalOptions(); + // Load new ini - SANDRO + LoadSkillTraitsExternalSettings(); + + // HEADROCK HAM 4: Read CTH values + LoadCTHConstants(); + InitSightRange(); //lal // Initlaize mouse subsystems @@ -145,22 +159,13 @@ BOOLEAN InitializeGame(void) //Init the help screen system InitHelpScreenSystem(); + + //LoadSavegame Slot + LoadSaveGameOldOrNew(); //Loads the saved (if any) general JA2 game settings LoadGameSettings(); - //Initialize the Game options ( Gun nut, scifi and dif. levels - - // WANNE - MP: Moved InitGameOptions() to MainMenuScreen::MenuButtonCallback() - // because in this function "is_networked" is not set, so it is too early! - //InitGameOptions(); - - // preload mapscreen graphics - // OJW - Temporarily disabliing this as is_networked is not set up yet - // see if there is a better place we can pre-load the gfx if nessesary - // or perhaps just reload the bits that will change - //HandlePreloadOfMapGraphics( ); - guiCurrentScreen = INIT_SCREEN; return TRUE; @@ -209,7 +214,7 @@ void GameLoop(void) InputAtom InputEvent; POINT MousePos; UINT32 uiOldScreen=guiCurrentScreen; - //clock_t startTime = clock(); // decrease CPU load patch from defrog + clock_t startTime = clock(); // decrease CPU load patch from defrog //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"GameLoop: get mouse position"); GetCursorPos(&MousePos); @@ -222,11 +227,20 @@ void GameLoop(void) MusicPoll( FALSE ); //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"GameLoop: check for mouse events"); - while (DequeueSpecificEvent(&InputEvent, LEFT_BUTTON_REPEAT|RIGHT_BUTTON_REPEAT|LEFT_BUTTON_DOWN|LEFT_BUTTON_UP|RIGHT_BUTTON_DOWN|RIGHT_BUTTON_UP ) == TRUE ) + //*** dddd + //while (DequeueSpecificEvent(&InputEvent, LEFT_BUTTON_REPEAT|RIGHT_BUTTON_REPEAT|LEFT_BUTTON_DOWN|LEFT_BUTTON_UP|RIGHT_BUTTON_DOWN|RIGHT_BUTTON_UP ) == TRUE ) + while (DequeueSpecificEvent(&InputEvent, + LEFT_BUTTON_REPEAT|RIGHT_BUTTON_REPEAT| + LEFT_BUTTON_DOWN|LEFT_BUTTON_UP|MIDDLE_BUTTON_UP|X1_BUTTON_UP|X2_BUTTON_UP| + RIGHT_BUTTON_DOWN|RIGHT_BUTTON_UP|MIDDLE_BUTTON_DOWN|X1_BUTTON_DOWN|X2_BUTTON_DOWN| + MOUSE_WHEEL_UP|MOUSE_WHEEL_DOWN) == TRUE ) { // HOOK INTO MOUSE HOOKS //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("GameLoop: mouse event %d", InputEvent.usEvent )); - switch(InputEvent.usEvent) + MouseSystemHook(InputEvent.usEvent, (UINT16)MousePos.x ,(UINT16)MousePos.y ,_LeftButtonDown, _RightButtonDown); + + + /* switch(InputEvent.usEvent) { case LEFT_BUTTON_DOWN: MouseSystemHook(LEFT_BUTTON_DOWN, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown); @@ -246,7 +260,8 @@ void GameLoop(void) case RIGHT_BUTTON_REPEAT: MouseSystemHook(RIGHT_BUTTON_REPEAT, (INT16)MousePos.x, (INT16)MousePos.y,_LeftButtonDown, _RightButtonDown); break; - } + }*/ + } @@ -354,6 +369,7 @@ void GameLoop(void) if( uiOldScreen != guiCurrentScreen ) { HandleNewScreenChange( uiOldScreen, guiCurrentScreen ); + guiPreviousScreen = guiCurrentScreen; guiCurrentScreen = uiOldScreen; } @@ -415,7 +431,6 @@ void GameLoop(void) } #endif -#if 0 if( gGameSettings.fOptions[ TOPTION_LOW_CPU_USAGE ] == TRUE ) { // decrease CPU load patch from MTX (http://www.ja-galaxy-forum.com/board/ubbthreads.php/ubb/showflat/Number/102405/page/1#Post102405) @@ -431,11 +446,11 @@ void GameLoop(void) if( sleeptime > 0 ) Sleep(sleeptime); } -#endif -if ( is_networked ) + + if ( is_networked ) { - client_packet(); - server_packet(); + client_packet(); + server_packet(); } //DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"GameLoop done"); } diff --git a/ja2.props b/ja2.props new file mode 100644 index 00000000..aad6ffbe --- /dev/null +++ b/ja2.props @@ -0,0 +1,15 @@ + + + + + + <_PropertySheetDisplayName>ja2 + + + + ..\.;.\.;.\ext\VFS\include;..\ext\VFS\include;..\Utils;.\Utils;..\TileEngine;.\TileEngine;..\TacticalAI;.\TacticalAI;..\Tactical;.\Tactical;..\Strategic;.\Strategic;..\Standard Gaming Platform;.\Standard Gaming Platform;..\Res;.\Res;..\lua;.\lua;..\Laptop;.\Laptop;..\Multiplayer;.\Multiplayer;..\Multiplayer\raknet;.\Multiplayer\raknet;..\Editor;.\Editor;..\Console;.\Console;.\ext\libpng;..\ext\libpng;.\ext\zlib;..\ext\zlib;;$(NOINHERIT) + JA2;CINTERFACE;XML_STATIC;VFS_STATIC;VFS_WITH_SLF;VFS_WITH_7ZIP;USE_VFS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + + \ No newline at end of file diff --git a/ja2.vsprops b/ja2.vsprops new file mode 100644 index 00000000..a9c0e584 --- /dev/null +++ b/ja2.vsprops @@ -0,0 +1,13 @@ + + + + diff --git a/ja2_Debug.props b/ja2_Debug.props new file mode 100644 index 00000000..e4e2325a --- /dev/null +++ b/ja2_Debug.props @@ -0,0 +1,12 @@ + + + + + + + + JA2BETAVERSION;JA2TESTVERSION;DEBUG_ATTACKBUSY;%(PreprocessorDefinitions) + + + + \ No newline at end of file diff --git a/ja2_Debug.vsprops b/ja2_Debug.vsprops new file mode 100644 index 00000000..90a657fa --- /dev/null +++ b/ja2_Debug.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/ja2_Editor.props b/ja2_Editor.props new file mode 100644 index 00000000..b56ac92c --- /dev/null +++ b/ja2_Editor.props @@ -0,0 +1,14 @@ + + + + + + <_PropertySheetDisplayName>ja2_Editor + + + + JA2BETAVERSION;JA2EDITOR;%(PreprocessorDefinitions) + + + + \ No newline at end of file diff --git a/ja2_Editor.vsprops b/ja2_Editor.vsprops new file mode 100644 index 00000000..8de3b034 --- /dev/null +++ b/ja2_Editor.vsprops @@ -0,0 +1,11 @@ + + + + diff --git a/ja2_Libs.props b/ja2_Libs.props new file mode 100644 index 00000000..b8020cf7 --- /dev/null +++ b/ja2_Libs.props @@ -0,0 +1,13 @@ + + + + + + + + .\.;Standard Gaming Platform + libexpatMT.lib;mss32.lib;SMACKW32.LIB;binkw32.lib;fmodvc.lib;lua51.lib;VtuneApi.lib;ddraw.lib;%(AdditionalDependencies) + + + + \ No newline at end of file diff --git a/ja2_Libs.vsprops b/ja2_Libs.vsprops new file mode 100644 index 00000000..e5079ff9 --- /dev/null +++ b/ja2_Libs.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/ja2_LinkerVS2005.vsprops b/ja2_LinkerVS2005.vsprops new file mode 100644 index 00000000..e538a723 --- /dev/null +++ b/ja2_LinkerVS2005.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/ja2_LinkerVS2008.vsprops b/ja2_LinkerVS2008.vsprops new file mode 100644 index 00000000..6ca9f6f9 --- /dev/null +++ b/ja2_LinkerVS2008.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/ja2_LinkerVS2010.props b/ja2_LinkerVS2010.props new file mode 100644 index 00000000..5b424718 --- /dev/null +++ b/ja2_LinkerVS2010.props @@ -0,0 +1,15 @@ + + + + + + <_PropertySheetDisplayName>ja2_LinkerVS2010 + + + + lib\VS2010\$(Configuration);%(AdditionalLibraryDirectories) + Console.lib;Editor.lib;Laptop.lib;lua.lib;SGP.lib;Strategic.lib;Tactical.lib;TacticalAI.lib;TileEngine.lib;Utils.lib;VFS.lib;7z.lib;libpng.lib;zlib.lib;%(AdditionalDependencies) + + + + \ No newline at end of file diff --git a/ja2_VS2005.sln b/ja2_VS2005.sln new file mode 100644 index 00000000..c2d75f54 --- /dev/null +++ b/ja2_VS2005.sln @@ -0,0 +1,288 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ja2", "ja2_VS2005.vcproj", "{F44669E7-74AC-444B-B75F-F16F4B9F0265}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {A67922A0-0A3F-497F-A724-19B513EFC078} = {A67922A0-0A3F-497F-A724-19B513EFC078} + {C63466D6-49B5-4C54-AA0D-864F6171FD9B} = {C63466D6-49B5-4C54-AA0D-864F6171FD9B} + {4B544F1A-6188-4255-8877-69FC312D0D2C} = {4B544F1A-6188-4255-8877-69FC312D0D2C} + {9AD14886-DB5C-4EFF-AE17-35F9BD684692} = {9AD14886-DB5C-4EFF-AE17-35F9BD684692} + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C} = {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C} + {6283CE93-2960-4596-8E74-7A6FBA8716FF} = {6283CE93-2960-4596-8E74-7A6FBA8716FF} + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096} = {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096} + {27A49DAF-3F5A-4FF2-B943-9559F0B63032} = {27A49DAF-3F5A-4FF2-B943-9559F0B63032} + {A83DA7DA-2C31-45D8-9A69-B4993A885E76} = {A83DA7DA-2C31-45D8-9A69-B4993A885E76} + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4} = {AB8837DB-0435-40C7-916A-0AACF5CFF1C4} + {FC1938E8-9253-49A8-AA99-4639BBB46C1B} = {FC1938E8-9253-49A8-AA99-4639BBB46C1B} + {60D793F2-90B4-43C9-83B5-221EE11B37E6} = {60D793F2-90B4-43C9-83B5-221EE11B37E6} + {F962CFA1-2215-4124-938F-253973A27591} = {F962CFA1-2215-4124-938F-253973A27591} + {5234CD2E-97F1-42FF-828D-CE0A1B46805E} = {5234CD2E-97F1-42FF-828D-CE0A1B46805E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Editor", "Editor\Editor_VS2005.vcproj", "{60D793F2-90B4-43C9-83B5-221EE11B37E6}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Laptop", "Laptop\Laptop_VS2005.vcproj", "{5234CD2E-97F1-42FF-828D-CE0A1B46805E}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua", "lua\lua_VS2005.vcproj", "{A83DA7DA-2C31-45D8-9A69-B4993A885E76}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SGP", "Standard Gaming Platform\SGP_VS2005.vcproj", "{6283CE93-2960-4596-8E74-7A6FBA8716FF}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Strategic", "Strategic\Strategic_VS2005.vcproj", "{AB8837DB-0435-40C7-916A-0AACF5CFF1C4}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tactical", "Tactical\Tactical_VS2005.vcproj", "{D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TacticalAI", "TacticalAI\TacticalAI_VS2005.vcproj", "{27A49DAF-3F5A-4FF2-B943-9559F0B63032}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TileEngine", "TileEngine\TileEngine_VS2005.vcproj", "{FC1938E8-9253-49A8-AA99-4639BBB46C1B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utils", "Utils\Utils_VS2005.vcproj", "{262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "Console\Console_VS2005.vcproj", "{F962CFA1-2215-4124-938F-253973A27591}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "ext\libpng\projects\visualc71\libpng_VS2005.vcproj", "{4B544F1A-6188-4255-8877-69FC312D0D2C}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "ext\libpng\projects\visualc71\zlib_VS2005.vcproj", "{A67922A0-0A3F-497F-A724-19B513EFC078}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VFS", "ext\VFS\build\VFS_VS2005.vcproj", "{C63466D6-49B5-4C54-AA0D-864F6171FD9B}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ja2export", "ext\export\ja2export_VS2005.vcproj", "{3E43B70D-A22F-4240-B00D-32BD14523335}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7z", "ext\VFS\build\7z_VS2005.vcproj", "{9AD14886-DB5C-4EFF-AE17-35F9BD684692}" + ProjectSection(WebsiteProperties) = preProject + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.Debug = "False" + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + MapEditor|Win32 = MapEditor|Win32 + MapEditorD|Win32 = MapEditorD|Win32 + Release_WithDebugInfo|Win32 = Release_WithDebugInfo|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.Debug|Win32.ActiveCfg = Debug|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.Debug|Win32.Build.0 = Debug|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.Release|Win32.ActiveCfg = Release|Win32 + {F44669E7-74AC-444B-B75F-F16F4B9F0265}.Release|Win32.Build.0 = Release|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.Debug|Win32.Build.0 = Debug|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.Release|Win32.ActiveCfg = Release|Win32 + {60D793F2-90B4-43C9-83B5-221EE11B37E6}.Release|Win32.Build.0 = Release|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.Debug|Win32.ActiveCfg = Debug|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.Debug|Win32.Build.0 = Debug|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.Release|Win32.ActiveCfg = Release|Win32 + {5234CD2E-97F1-42FF-828D-CE0A1B46805E}.Release|Win32.Build.0 = Release|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.Debug|Win32.ActiveCfg = Debug|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.Debug|Win32.Build.0 = Debug|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.Release|Win32.ActiveCfg = Release|Win32 + {A83DA7DA-2C31-45D8-9A69-B4993A885E76}.Release|Win32.Build.0 = Release|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.Debug|Win32.ActiveCfg = Debug|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.Debug|Win32.Build.0 = Debug|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.Release|Win32.ActiveCfg = Release|Win32 + {6283CE93-2960-4596-8E74-7A6FBA8716FF}.Release|Win32.Build.0 = Release|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.Debug|Win32.ActiveCfg = Debug|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.Debug|Win32.Build.0 = Debug|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.Release|Win32.ActiveCfg = Release|Win32 + {AB8837DB-0435-40C7-916A-0AACF5CFF1C4}.Release|Win32.Build.0 = Release|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.Debug|Win32.ActiveCfg = Debug|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.Debug|Win32.Build.0 = Debug|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.Release|Win32.ActiveCfg = Release|Win32 + {D4BDA6AD-9B61-4953-892D-DA3F8CC7E096}.Release|Win32.Build.0 = Release|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.Debug|Win32.ActiveCfg = Debug|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.Debug|Win32.Build.0 = Debug|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.Release|Win32.ActiveCfg = Release|Win32 + {27A49DAF-3F5A-4FF2-B943-9559F0B63032}.Release|Win32.Build.0 = Release|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.Debug|Win32.ActiveCfg = Debug|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.Debug|Win32.Build.0 = Debug|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.Release|Win32.ActiveCfg = Release|Win32 + {FC1938E8-9253-49A8-AA99-4639BBB46C1B}.Release|Win32.Build.0 = Release|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.Debug|Win32.ActiveCfg = Debug|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.Debug|Win32.Build.0 = Debug|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.Release|Win32.ActiveCfg = Release|Win32 + {262A5F80-0B99-4E8E-A6C7-74CB1FD0A67C}.Release|Win32.Build.0 = Release|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.Debug|Win32.ActiveCfg = Debug|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.Debug|Win32.Build.0 = Debug|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.Release|Win32.ActiveCfg = Release|Win32 + {F962CFA1-2215-4124-938F-253973A27591}.Release|Win32.Build.0 = Release|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.Debug|Win32.ActiveCfg = Debug|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.Debug|Win32.Build.0 = Debug|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.Release|Win32.ActiveCfg = Release|Win32 + {4B544F1A-6188-4255-8877-69FC312D0D2C}.Release|Win32.Build.0 = Release|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.Debug|Win32.ActiveCfg = Debug|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.Debug|Win32.Build.0 = Debug|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.Release|Win32.ActiveCfg = Release|Win32 + {A67922A0-0A3F-497F-A724-19B513EFC078}.Release|Win32.Build.0 = Release|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Debug|Win32.ActiveCfg = Debug|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Debug|Win32.Build.0 = Debug|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release|Win32.ActiveCfg = Release|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release|Win32.Build.0 = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Debug|Win32.Build.0 = Debug|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.MapEditor|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.MapEditorD|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.MapEditorD|Win32.Build.0 = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release_WithDebugInfo|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release_WithDebugInfo|Win32.Build.0 = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release|Win32.Build.0 = Release|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Debug|Win32.ActiveCfg = Debug|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Debug|Win32.Build.0 = Debug|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Release|Win32.ActiveCfg = Release|Win32 + {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ja2_VS2005.vcproj b/ja2_VS2005.vcproj new file mode 100644 index 00000000..b893a5be --- /dev/null +++ b/ja2_VS2005.vcproj @@ -0,0 +1,947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ja2_VS2005Linker.vsprops b/ja2_VS2005Linker.vsprops new file mode 100644 index 00000000..c3218958 --- /dev/null +++ b/ja2_VS2005Linker.vsprops @@ -0,0 +1,12 @@ + + + + diff --git a/ja2_VS2008.sln b/ja2_VS2008.sln index a1b4a9c1..05065cfa 100644 --- a/ja2_VS2008.sln +++ b/ja2_VS2008.sln @@ -1,5 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ja2", "ja2_VS2008.vcproj", "{B112F6BA-AF32-489C-B405-916C0F182D10}" ProjectSection(ProjectDependencies) = postProject @@ -39,13 +40,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TileEngine", "TileEngine\Ti EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utils", "Utils\Utils_VS2008.vcproj", "{DB40B90D-13F9-4FEC-8F1D-0506CC496586}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VFS", "VFS\VFS_VS2008.vcproj", "{C63466D6-49B5-4C54-AA0D-864F6171FD9B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "ext\libpng\projects\visualc71\libpng_VS2008.vcproj", "{4B544F1A-6188-4255-8877-69FC312D0D2C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "ext\libpng\projects\visualc71\libpng.vcproj", "{4B544F1A-6188-4255-8877-69FC312D0D2C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "ext\libpng\projects\visualc71\zlib_VS2008.vcproj", "{A67922A0-0A3F-497F-A724-19B513EFC078}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "ext\libpng\projects\visualc71\zlib.vcproj", "{A67922A0-0A3F-497F-A724-19B513EFC078}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VFS", "ext\VFS\build\VFS_VS2008.vcproj", "{C63466D6-49B5-4C54-AA0D-864F6171FD9B}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7z", "ext\7z\Archive\7z\7z.vcproj", "{9AD14886-DB5C-4EFF-AE17-35F9BD684692}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ja2export", "ext\export\ja2export_VS2008.vcproj", "{3E43B70D-A22F-4240-B00D-32BD14523335}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7z", "ext\VFS\build\7z_VS2008.vcproj", "{9AD14886-DB5C-4EFF-AE17-35F9BD684692}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -166,16 +169,6 @@ Global {DB40B90D-13F9-4FEC-8F1D-0506CC496586}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 {DB40B90D-13F9-4FEC-8F1D-0506CC496586}.Release|Win32.ActiveCfg = Release|Win32 {DB40B90D-13F9-4FEC-8F1D-0506CC496586}.Release|Win32.Build.0 = Release|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Debug|Win32.ActiveCfg = Debug|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Debug|Win32.Build.0 = Debug|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditor|Win32.Build.0 = MapEditor|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release|Win32.ActiveCfg = Release|Win32 - {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release|Win32.Build.0 = Release|Win32 {4B544F1A-6188-4255-8877-69FC312D0D2C}.Debug|Win32.ActiveCfg = Debug|Win32 {4B544F1A-6188-4255-8877-69FC312D0D2C}.Debug|Win32.Build.0 = Debug|Win32 {4B544F1A-6188-4255-8877-69FC312D0D2C}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 @@ -196,6 +189,24 @@ Global {A67922A0-0A3F-497F-A724-19B513EFC078}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 {A67922A0-0A3F-497F-A724-19B513EFC078}.Release|Win32.ActiveCfg = Release|Win32 {A67922A0-0A3F-497F-A724-19B513EFC078}.Release|Win32.Build.0 = Release|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Debug|Win32.ActiveCfg = Debug|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Debug|Win32.Build.0 = Debug|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release_WithDebugInfo|Win32.ActiveCfg = Release_WithDebugInfo|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release_WithDebugInfo|Win32.Build.0 = Release_WithDebugInfo|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release|Win32.ActiveCfg = Release|Win32 + {C63466D6-49B5-4C54-AA0D-864F6171FD9B}.Release|Win32.Build.0 = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Debug|Win32.ActiveCfg = Debug|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Debug|Win32.Build.0 = Debug|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.MapEditor|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.MapEditorD|Win32.ActiveCfg = Debug|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release_WithDebugInfo|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release_WithDebugInfo|Win32.Build.0 = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release|Win32.ActiveCfg = Release|Win32 + {3E43B70D-A22F-4240-B00D-32BD14523335}.Release|Win32.Build.0 = Release|Win32 {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Debug|Win32.ActiveCfg = Debug|Win32 {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.Debug|Win32.Build.0 = Debug|Win32 {9AD14886-DB5C-4EFF-AE17-35F9BD684692}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 diff --git a/ja2_VS2008.vcproj b/ja2_VS2008.vcproj index c10e61cd..43f51505 100644 --- a/ja2_VS2008.vcproj +++ b/ja2_VS2008.vcproj @@ -18,10 +18,10 @@ @@ -140,8 +140,8 @@ /> @@ -220,8 +220,8 @@ /> @@ -378,8 +378,8 @@ /> @@ -608,7 +608,7 @@ > diff --git a/ja2_VS2010.sln b/ja2_VS2010.sln new file mode 100644 index 00000000..ab75f9be --- /dev/null +++ b/ja2_VS2010.sln @@ -0,0 +1,233 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VFS", "ext\VFS\build\VFS_VS2010.vcxproj", "{463CB476-2798-493F-9CE8-CEAC5ECE5664}" + ProjectSection(ProjectDependencies) = postProject + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} = {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TileEngine", "TileEngine\TileEngine_VS2010.vcxproj", "{D027A0E1-C661-4B8C-8159-4E0BF3D163AA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TacticalAI", "TacticalAI\TacticalAI_VS2010.vcxproj", "{B369A125-E62E-46AE-9285-58003D688301}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utils", "Utils\Utils_VS2010.vcxproj", "{082F6E91-D049-4314-BE9D-D9509E853B01}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Strategic", "Strategic\Strategic_VS2010.vcxproj", "{DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SGP", "Standard Gaming Platform\SGP_VS2010.vcxproj", "{1237FA1E-6E76-4AB5-B569-45B01C691FAB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua", "lua\lua_VS2010.vcxproj", "{9DA9FE0C-B1F2-4E15-9097-A929E203AC28}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "ext\libpng\projects\visualc71\libpng_VS2010.vcxproj", "{735F8DBF-6646-4713-BE36-394F33E69B57}" + ProjectSection(ProjectDependencies) = postProject + {EC27EB68-C428-4B80-8170-D93F988EA34C} = {EC27EB68-C428-4B80-8170-D93F988EA34C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Laptop", "Laptop\Laptop_VS2010.vcxproj", "{6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Editor", "Editor\Editor_VS2010.vcxproj", "{23EA0500-038A-4EB8-B753-0C709B25470D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "Console\Console_VS2010.vcxproj", "{A32479BF-C284-4C40-99A5-4F6B5933D1C0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tactical", "Tactical\Tactical_VS2010.vcxproj", "{433FBCC4-F612-489C-AA28-CCD6CF27D80C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "ext\libpng\projects\visualc71\zlib_VS2010.vcxproj", "{EC27EB68-C428-4B80-8170-D93F988EA34C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ja2", "ja2_VS2010.vcxproj", "{C0E14A90-2BD1-4866-A684-98C6F6B96C2D}" + ProjectSection(ProjectDependencies) = postProject + {23EA0500-038A-4EB8-B753-0C709B25470D} = {23EA0500-038A-4EB8-B753-0C709B25470D} + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28} = {9DA9FE0C-B1F2-4E15-9097-A929E203AC28} + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} = {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} + {1237FA1E-6E76-4AB5-B569-45B01C691FAB} = {1237FA1E-6E76-4AB5-B569-45B01C691FAB} + {B369A125-E62E-46AE-9285-58003D688301} = {B369A125-E62E-46AE-9285-58003D688301} + {EC27EB68-C428-4B80-8170-D93F988EA34C} = {EC27EB68-C428-4B80-8170-D93F988EA34C} + {463CB476-2798-493F-9CE8-CEAC5ECE5664} = {463CB476-2798-493F-9CE8-CEAC5ECE5664} + {082F6E91-D049-4314-BE9D-D9509E853B01} = {082F6E91-D049-4314-BE9D-D9509E853B01} + {A32479BF-C284-4C40-99A5-4F6B5933D1C0} = {A32479BF-C284-4C40-99A5-4F6B5933D1C0} + {735F8DBF-6646-4713-BE36-394F33E69B57} = {735F8DBF-6646-4713-BE36-394F33E69B57} + {433FBCC4-F612-489C-AA28-CCD6CF27D80C} = {433FBCC4-F612-489C-AA28-CCD6CF27D80C} + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} = {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C} + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA} = {D027A0E1-C661-4B8C-8159-4E0BF3D163AA} + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D} = {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ja2export", "ext\export\ja2export_VS2010.vcxproj", "{802552D2-B514-42E5-A169-F1E108527678}" + ProjectSection(ProjectDependencies) = postProject + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} = {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6} + {463CB476-2798-493F-9CE8-CEAC5ECE5664} = {463CB476-2798-493F-9CE8-CEAC5ECE5664} + {735F8DBF-6646-4713-BE36-394F33E69B57} = {735F8DBF-6646-4713-BE36-394F33E69B57} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7z", "ext\VFS\build\7z_VS2010.vcxproj", "{3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + MapEditor|Win32 = MapEditor|Win32 + MapEditorD|Win32 = MapEditorD|Win32 + Release|Win32 = Release|Win32 + Relese_WithDebugInfo|Win32 = Relese_WithDebugInfo|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.Debug|Win32.ActiveCfg = Debug|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.Debug|Win32.Build.0 = Debug|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.Release|Win32.ActiveCfg = Release|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.Release|Win32.Build.0 = Release|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {463CB476-2798-493F-9CE8-CEAC5ECE5664}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.Debug|Win32.ActiveCfg = Debug|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.Debug|Win32.Build.0 = Debug|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.Release|Win32.ActiveCfg = Release|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.Release|Win32.Build.0 = Release|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {D027A0E1-C661-4B8C-8159-4E0BF3D163AA}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.Debug|Win32.ActiveCfg = Debug|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.Debug|Win32.Build.0 = Debug|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.Release|Win32.ActiveCfg = Release|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.Release|Win32.Build.0 = Release|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {B369A125-E62E-46AE-9285-58003D688301}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.Debug|Win32.ActiveCfg = Debug|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.Debug|Win32.Build.0 = Debug|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.Release|Win32.ActiveCfg = Release|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.Release|Win32.Build.0 = Release|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {082F6E91-D049-4314-BE9D-D9509E853B01}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.Debug|Win32.ActiveCfg = Debug|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.Debug|Win32.Build.0 = Debug|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.Release|Win32.ActiveCfg = Release|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.Release|Win32.Build.0 = Release|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {DE9B77CC-7CD5-4951-9B7F-BAC7B4A8169C}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.Debug|Win32.ActiveCfg = Debug|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.Debug|Win32.Build.0 = Debug|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.Release|Win32.ActiveCfg = Release|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.Release|Win32.Build.0 = Release|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {1237FA1E-6E76-4AB5-B569-45B01C691FAB}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.Debug|Win32.ActiveCfg = Debug|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.Debug|Win32.Build.0 = Debug|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.Release|Win32.ActiveCfg = Release|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.Release|Win32.Build.0 = Release|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.Debug|Win32.ActiveCfg = Debug|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.Debug|Win32.Build.0 = Debug|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.Release|Win32.ActiveCfg = Release|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.Release|Win32.Build.0 = Release|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {735F8DBF-6646-4713-BE36-394F33E69B57}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.Debug|Win32.ActiveCfg = Debug|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.Debug|Win32.Build.0 = Debug|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.Release|Win32.ActiveCfg = Release|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.Release|Win32.Build.0 = Release|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {6CFD0AF4-6BB4-4A19-B72E-71768A8D029D}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.Debug|Win32.ActiveCfg = Debug|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.Debug|Win32.Build.0 = Debug|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.Release|Win32.ActiveCfg = Release|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.Release|Win32.Build.0 = Release|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {23EA0500-038A-4EB8-B753-0C709B25470D}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.Debug|Win32.Build.0 = Debug|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.Release|Win32.ActiveCfg = Release|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.Release|Win32.Build.0 = Release|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {A32479BF-C284-4C40-99A5-4F6B5933D1C0}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.Debug|Win32.ActiveCfg = Debug|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.Debug|Win32.Build.0 = Debug|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.Release|Win32.ActiveCfg = Release|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.Release|Win32.Build.0 = Release|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {433FBCC4-F612-489C-AA28-CCD6CF27D80C}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.Debug|Win32.Build.0 = Debug|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.Release|Win32.ActiveCfg = Release|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.Release|Win32.Build.0 = Release|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {EC27EB68-C428-4B80-8170-D93F988EA34C}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.Debug|Win32.Build.0 = Debug|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.Release|Win32.ActiveCfg = Release|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.Release|Win32.Build.0 = Release|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.Debug|Win32.ActiveCfg = Debug|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.MapEditor|Win32.ActiveCfg = Release|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.MapEditorD|Win32.ActiveCfg = Release|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.MapEditorD|Win32.Build.0 = Release|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.Release|Win32.ActiveCfg = Release|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.Release|Win32.Build.0 = Release|Win32 + {802552D2-B514-42E5-A169-F1E108527678}.Relese_WithDebugInfo|Win32.ActiveCfg = Debug|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.Debug|Win32.ActiveCfg = Debug|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.Debug|Win32.Build.0 = Debug|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.MapEditor|Win32.ActiveCfg = MapEditor|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.MapEditor|Win32.Build.0 = MapEditor|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.MapEditorD|Win32.ActiveCfg = MapEditorD|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.MapEditorD|Win32.Build.0 = MapEditorD|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.Release|Win32.ActiveCfg = Release|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.Release|Win32.Build.0 = Release|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.Relese_WithDebugInfo|Win32.ActiveCfg = Relese_WithDebugInfo|Win32 + {3B7B950D-0DC8-4ADD-9FE2-7DE4297C62F6}.Relese_WithDebugInfo|Win32.Build.0 = Relese_WithDebugInfo|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ja2_VS2010.vcxproj b/ja2_VS2010.vcxproj new file mode 100644 index 00000000..30b093aa --- /dev/null +++ b/ja2_VS2010.vcxproj @@ -0,0 +1,321 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + {C0E14A90-2BD1-4866-A684-98C6F6B96C2D} + Win32Proj + ja2 + ja2 + + + + Application + true + NotSet + + + Application + true + NotSet + + + Application + false + false + NotSet + + + Application + false + false + NotSet + + + Application + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + bin\VS2010\$(Configuration)\ + build\VS2010\$(ProjectName)_$(Configuration)\ + JA2_EN_Debug.exe + + + + true + bin\VS2010\$(Configuration)\ + build\VS2010\$(ProjectName)_$(Configuration)\ + + + MapEditor_EN_Debug.exe + + + false + bin\VS2010\$(Configuration)\ + build\VS2010\$(ProjectName)_$(Configuration)\ + JA2_EN_Release.exe + + + + false + bin\VS2010\$(Configuration)\ + build\VS2010\$(ProjectName)_$(Configuration)\ + MapEditor_EN_Release.exe + + + + false + bin\VS2010\$(Configuration)\ + build\VS2010\$(ProjectName)_$(Configuration)\ + JA2_EN_ReleaseDebugInfo.exe + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + Multiplayer\raknet;%(AdditionalLibraryDirectories) + Winmm.lib;RakNetLibStatic.lib;ws2_32.lib;DbgHelp.lib;%(AdditionalDependencies) + $(OutDir)\JA2_EN_Debug.exe + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Windows + true + Multiplayer\raknet;%(AdditionalLibraryDirectories) + Winmm.lib;RakNetLibStatic.lib;ws2_32.lib;DbgHelp.lib;%(AdditionalDependencies) + $(OutDir)\MapEditor_EN_Debug.exe + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + false + true + true + Multiplayer\raknet;%(AdditionalLibraryDirectories) + Winmm.lib;RakNetLibStatic.lib;ws2_32.lib;DbgHelp.lib;%(AdditionalDependencies) + $(OutDir)\JA2_EN_Release.exe + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + + + Windows + false + true + true + Multiplayer\raknet;%(AdditionalLibraryDirectories) + Winmm.lib;RakNetLibStatic.lib;ws2_32.lib;DbgHelp.lib;%(AdditionalDependencies) + $(OutDir)\MapEditor_EN_Release.exe + + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + EditAndContinue + + + Windows + true + true + true + Multiplayer\raknet;%(AdditionalLibraryDirectories) + Winmm.lib;RakNetLibStatic.lib;ws2_32.lib;DbgHelp.lib;%(AdditionalDependencies) + $(OutDir)\JA2_EN_ReleaseDebugInfo.exe + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ja2_VS2010.vcxproj.filters b/ja2_VS2010.vcxproj.filters new file mode 100644 index 00000000..b0742e29 --- /dev/null +++ b/ja2_VS2010.vcxproj.filters @@ -0,0 +1,265 @@ + + + + + {359f3c3e-57b2-40d7-b083-85c85db31e63} + + + {05dccef7-dd96-43de-9b63-9d7c8919e41a} + + + {f3b2a941-8bd5-415f-bf6f-e5f8a0cf1397} + + + {b90d96e4-cddd-48f9-aa85-407f16af8948} + + + {fee7e775-f3f7-4522-83ca-c6a46499a675} + + + {4174d974-f404-4614-9bc3-d6503ec290da} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Multiplayer\Source Files + + + Multiplayer\Source Files + + + Multiplayer\Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Resource Files + + + Multiplayer\Header Files + + + Multiplayer\Header Files + + + Multiplayer\Header Files + + + Multiplayer\Header Files + + + + + Resource Files + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/jascreens.cpp b/jascreens.cpp index 0a39da67..75b4646a 100644 --- a/jascreens.cpp +++ b/jascreens.cpp @@ -61,8 +61,8 @@ #include "IniReader.h" #endif -#include "VFS/vfs.h" -#include "VFS/Tools/Log.h" +#include "sgp_logger.h" + #define _UNICODE // Networking Stuff #ifdef NETWORKED @@ -425,8 +425,9 @@ UINT32 InitScreenHandle(void) // Handle queued .ini file error messages int y = 40; #ifdef USE_VFS - CLog logger(L"ERROR_REPORT.iniErrorMessages.txt"); - //logger.SetAppend(); + sgp::Logger_ID ini_id = sgp::Logger::instance().createLogger(); + sgp::Logger::instance().connectFile(ini_id, L"ERROR_REPORT.iniErrorMessages.txt", false, sgp::Logger::FLUSH_ON_DELETE); + sgp::Logger::LogInstance logger = sgp::Logger::instance().logger(ini_id); #endif while (! iniErrorMessages.empty()) { #ifndef USE_VFS @@ -459,7 +460,7 @@ UINT32 InitScreenHandle(void) fprintf_s (file_pointer , "%S\n" , str ); fclose( file_pointer ); #else - logger << iniErrorMessage << CLog::ENDL; + logger << iniErrorMessage << sgp::endl; #endif DisplayWrappedString( 10, y, 560, 2, FONT12ARIAL, FONT_RED, str, FONT_BLACK, TRUE, LEFT_JUSTIFIED ); iniErrorMessages.pop(); @@ -919,10 +920,15 @@ UINT32 SexScreenHandle(void) // Update frame uiTime = GetJA2Clock( ); + static bool started_sound = false; // if we are animation smile... if ( ubCurrentScreen == 1 ) { - PlayJA2StreamingSampleFromFile( "Sounds\\Sex.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN, NULL ); + if(!started_sound) + { + PlayJA2StreamingSampleFromFile( "Sounds\\Sex.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN, NULL ); + started_sound = true; + } if ( ( uiTime - uiTimeOfLastUpdate ) > SMILY_DELAY ) { uiTimeOfLastUpdate = uiTime; @@ -944,6 +950,7 @@ UINT32 SexScreenHandle(void) uiTimeOfLastUpdate = uiTime; ubCurrentScreen = 0; + started_sound = false; // Remove video object... DeleteVideoObjectFromIndex( guiSMILY ); @@ -997,7 +1004,8 @@ void DoneFadeOutForDemoExitScreen( void ) gfProgramIsRunning = FALSE; } -extern INT8 gbFadeSpeed; +// unused +//extern INT8 gbFadeSpeed; #ifdef GERMAN void DisplayTopwareGermanyAddress() diff --git a/jascreens.h b/jascreens.h index 38e36857..8d5dc579 100644 --- a/jascreens.h +++ b/jascreens.h @@ -6,7 +6,7 @@ #include "mousesystem.h" #include "Button System.h" #include -#include "VFS/utf8string.h" +#include extern UINT32 EditScreenInit(void); extern UINT32 EditScreenHandle(void); @@ -169,7 +169,7 @@ void LeaveTacticalScreen( UINT32 uiNewScreen ); struct SExceptionData { - utf8string message,function,file; + vfs::String message,function,file; int line; }; diff --git a/lua/Lua Interpreter.h b/lua/Lua Interpreter.h index 59f13187..8be61dfe 100644 --- a/lua/Lua Interpreter.h +++ b/lua/Lua Interpreter.h @@ -1,3 +1,6 @@ +#ifndef _LUA_INTERPRETER_H_ +#define _LUA_INTERPRETER_H_ + extern "C" { #include "lua.h" #include "lauxlib.h" @@ -29,3 +32,5 @@ void NewLuaObject( lua_State *L, STR8 ClsName, void *Ptr ); void LuaStrategicSetup(lua_State *L); void LuaTacticalSetup(lua_State *L); void LuaEnvironmentSetup(lua_State *L); + +#endif // _LUA_INTERPRETER_H_ diff --git a/lua/lua_VS2005.vcproj b/lua/lua_VS2005.vcproj new file mode 100644 index 00000000..eb1212ed --- /dev/null +++ b/lua/lua_VS2005.vcproj @@ -0,0 +1,431 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lua/lua_VS2008.vcproj b/lua/lua_VS2008.vcproj index 9a36672d..ef1588ab 100644 --- a/lua/lua_VS2008.vcproj +++ b/lua/lua_VS2008.vcproj @@ -21,7 +21,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Debug.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Debug.vsprops" CharacterSet="0" > @@ -147,7 +147,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" WholeProgramOptimization="0" > @@ -211,7 +211,7 @@ OutputDirectory="..\lib\VS2008\$(ConfigurationName)" IntermediateDirectory="..\build\VS2008\$(ProjectName)_$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="..\ja2_VS2008.vsprops;..\ja2_VS2008Editor.vsprops" + InheritedPropertySheets="..\ja2.vsprops;..\ja2_Editor.vsprops" CharacterSet="0" > @@ -355,6 +355,22 @@ RelativePath="lua.hpp" > + + + + + + + + @@ -375,14 +391,30 @@ RelativePath="lua.cpp" > + + + + + + + + diff --git a/lua/lua_VS2010.vcxproj b/lua/lua_VS2010.vcxproj new file mode 100644 index 00000000..47fd14e8 --- /dev/null +++ b/lua/lua_VS2010.vcxproj @@ -0,0 +1,233 @@ + + + + + Debug + Win32 + + + MapEditorD + Win32 + + + MapEditor + Win32 + + + Release + Win32 + + + Relese_WithDebugInfo + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + {9DA9FE0C-B1F2-4E15-9097-A929E203AC28} + Win32Proj + lua + lua + + + + StaticLibrary + true + NotSet + + + StaticLibrary + true + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + StaticLibrary + false + false + NotSet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\lib\VS2010\$(Configuration)\ + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + ..\build\VS2010\$(ProjectName)_$(Configuration)\ + ..\lib\VS2010\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + + + + + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + + + Windows + true + true + true + + + + + Level3 + NotUsing + Disabled + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + + + + + EditAndContinue + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/lua/lua_VS2010.vcxproj.filters b/lua/lua_VS2010.vcxproj.filters new file mode 100644 index 00000000..72198bfa --- /dev/null +++ b/lua/lua_VS2010.vcxproj.filters @@ -0,0 +1,59 @@ + + + + + {363547e5-d794-4293-8484-b7cc64b304dd} + + + {ffb119e4-d4fc-4b6b-93ae-2958a9ec49dc} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + \ No newline at end of file diff --git a/lua/lua_class_interface.cpp b/lua/lua_class_interface.cpp new file mode 100644 index 00000000..b9f950b9 --- /dev/null +++ b/lua/lua_class_interface.cpp @@ -0,0 +1,247 @@ +#include "lua_class_interface.h" + +#include + +#define ARRAY_INDEX " idx" // The space is intentional to make this an out-of-band field + +luaL_Reg LuaInterface::s_ClassList[] = { + { "__index", LuaInterface::luaGetObject, }, + { "__newindex", LuaInterface::luaSetObject, }, + { NULL, }, +}; + +const char* LuaInterface::luaClassName = "ja2_LuaInterface"; + +LuaInterface::LuaInterface() +: luaObject(NULL) +{ +} + +LuaInterface::~LuaInterface() +{ +} + +LuaInterface::SInterfaceData* LuaInterface::luaGetInterface() +{ + return NULL; +} + + +void* LuaInterface::luaIsOfType(LuaState state, int index, const char* sClassName) +{ + lua_State* L = state(); + void *p = lua_touserdata(L, index); + LuaInterface::SInterfaceData* iface = NULL; + if( lua_getmetatable(L, index) ) /* does it have a metatable? */ + { + lua_getfield(L, -1, "__ClassInterface"); + iface = (LuaInterface::SInterfaceData*) lua_touserdata(L, -1); + if( !iface ) + { + return NULL; + } + lua_pop(L,2); + } + else + { + return NULL; + } + LuaInterface::SInterfaceData::tClassInterface::iterator it = iface->ClassHierarchy.begin(); + for(; it != iface->ClassHierarchy.end(); ++it) + { + if( *it == sClassName ) + { + return p; + } + } + return NULL; +} + +LuaInterface::SInterfaceData* LuaInterface::luaGetExportedInterface( SInterfaceData* iface ) +{ + //iface.Attribs.push_back(s_attrClassList); + //iface.ClassHierarchy.push_back(LuaInterface::luaClassName); + return iface; +} + +void LuaInterface::luaExportInterface(LuaState state, LuaInterface::SInterfaceData& iface ) +{ + luaL_Reg *i; + LuaAttrib *idx; + lua_State* L = state(); + + LuaInterface::SInterfaceData::tClassInterface::iterator it_class = iface.ClassHierarchy.begin(); + + luaL_newmetatable( L, (*it_class).c_str() ); + for (i = s_ClassList; i->name; i++) + { + lua_pushstring(L, i->name); + lua_pushlightuserdata(L, &iface); + lua_pushcclosure(L, i->func, 1); + lua_rawset(L, -3); + } + lua_pushlightuserdata(L, &iface); + lua_setfield(L, -2, "__ClassInterface"); + + LuaInterface::SInterfaceData::tAttribs::iterator it_attrib = iface.Attribs.begin(); + for(;it_attrib != iface.Attribs.end(); ++it_attrib) + { + for (idx=*it_attrib; idx->name; idx++) + { + if (idx->staticcall) + { + lua_pushstring(L, idx->name); + lua_pushcfunction(L, idx->staticcall); + lua_rawset(L, -3 ); + } + } + } +} + +LuaAttrib* LuaInterface::luaCommonGetSet(LuaState state) +{ + const char *AttrToFind; + typedef std::list tAttributes; + lua_State* L = state(); + + LuaInterface::SInterfaceData* iface = (LuaInterface::SInterfaceData*) lua_touserdata(L, lua_upvalueindex( 1)); + if(!iface) + { + return NULL; + } + tAttributes* Attributes = &iface->Attribs; + + if (lua_isnumber(L, 2) ) + { + AttrToFind = ARRAY_INDEX; + } + else if (lua_isstring(L, 2) ) + { + AttrToFind = lua_tostring(L, 2); + } + else + { + luaL_argcheck(L, 0, 2, "Invalid index to the table" ); + // The last function doesn't return, but gotta keep the compiler happy + return NULL; + } + + tAttributes::iterator it = Attributes->begin(); + for(;it != Attributes->end(); ++it) + { + LuaAttrib* attrib = (*it); + for ( ; attrib->name; attrib++ ) + { + if ( strcmp( attrib->name, AttrToFind) == 0 ) + { + return attrib; + } + } + } + std::string err = "No such field : " + std::string(AttrToFind); + luaL_error(L, err.c_str()); + return NULL; +} + +//int LuaInterface::luaGetObject(lua_State* L) +DEFINE_LUA_CFUNCTION(LuaInterface, luaGetObject) +{ + LuaAttrib *Attributes; + + Attributes = LuaInterface::luaCommonGetSet(L); + if (!Attributes) + { + lua_pushnil( L ); + return 1; + } + + if (!Attributes->get) + { + if (!Attributes->call) + { + lua_pushnil( L ); + } + else + { + lua_pushcfunction(L, Attributes->call); + } + return 1; + } + + return Attributes->get( L ); +} + +//int LuaInterface::luaSetObject(lua_State* L) +DEFINE_LUA_CFUNCTION(LuaInterface, luaSetObject) +{ + LuaAttrib *Attributes; + + Attributes = LuaInterface::luaCommonGetSet(L); + + if (!Attributes) + { + lua_rawset( L, 1 ); + return 0; + } + + if (!Attributes->set) + { + luaL_error( L, "The attribute is not writable" ); + } + + return Attributes->set(L); +} + + +void LuaInterface::luaCreateObject( LuaState state, void *Ptr ) +{ + lua_State* L = state(); + // Create the object and initialize its pointer + void **ud; + ud = (void**)lua_newuserdata( L, sizeof( void*) ); + *ud = Ptr; + // save user data + state.registry().GetUserDataTable(); + lua_pushlightuserdata(L, this); + lua_pushvalue(L, -3); + lua_rawset(L, -3); + lua_pop(L, 1); + // Swap the table and metatable for stack arg purposes + lua_insert( L, -2 ); + lua_setmetatable( L, -2 ); +} + +void LuaInterface::luaPushObject( LuaState state, const char* sClassName, void *Ptr ) +{ + lua_State* L = state(); + state.registry().GetUserDataTable(); + lua_pushlightuserdata(L, Ptr); + lua_rawget(L,-2); + if(lua_isnil(L,-1)) + { + lua_pop(L, 1); + luaL_getmetatable( L, sClassName ); + if (lua_istable( L, -1 ) ) + { + this->luaCreateObject( state, Ptr ); + } + } + if(!lua_isuserdata(L,-1)) + { + SGP_THROW(L"Could not create User Data"); + } + lua_insert(L, -2); + lua_pop(L, 1); +} + +void LuaInterface::luaPushObject( LuaState state, const char* luaName ) +{ + LuaInterface::SInterfaceData* iface = this->luaGetInterface(); + this->luaPushObject(state, iface->ClassHierarchy.front().c_str(), this); + if(luaName != NULL) + { + lua_setglobal( state(), luaName ); + } +} + + diff --git a/lua/lua_class_interface.h b/lua/lua_class_interface.h new file mode 100644 index 00000000..09571e43 --- /dev/null +++ b/lua/lua_class_interface.h @@ -0,0 +1,122 @@ +#ifndef _LUA_CLASS_INTERFACE_H_ +#define _LUA_CLASS_INTERFACE_H_ + +//#include "Lua Interpreter.h" +#include "lua_state.h" + +#include +#include + +#define DECLARE_LUA_CFUNCTION(name) static int name(lua_State* L) +#define DEFINE_LUA_CFUNCTION(class_name,name) int class_name::name(lua_State* L) + +class LuaInterface +{ +public: + struct SInterfaceData + { + typedef std::list tAttribs; + typedef std::list tClassInterface; + tAttribs Attribs; + tClassInterface ClassHierarchy; + }; + + static const char* luaClassName; +public: + LuaInterface(); + virtual ~LuaInterface(); + + virtual void luaPushObject( LuaState L, const char* luaName = NULL ); + +protected: + static void luaExportInterface(LuaState L, LuaInterface::SInterfaceData& iface); + static SInterfaceData* luaGetExportedInterface( SInterfaceData* iface=NULL); + + virtual SInterfaceData* luaGetInterface(); + + void luaPushObject( LuaState L, const char* sClassName, void *Ptr ); +private: + void luaCreateObject( LuaState L, void *Ptr ); + void* luaObject; + + static LuaAttrib* luaCommonGetSet( LuaState L ); + static void* luaIsOfType(LuaState L, int index, const char* sClassName); + + // "meta"-interface + //static int luaGetObject( lua_State *L); + //static int luaSetObject( lua_State *L); + DECLARE_LUA_CFUNCTION( luaGetObject ); + DECLARE_LUA_CFUNCTION( luaSetObject ); + + static luaL_Reg s_ClassList[]; +public: + ///////////////////////////////////////////////////////////////////////// + template + static void luaExportClass( LuaState L ) + { + LuaInterface::SInterfaceData* iface = T::luaGetExportedInterface(); + LuaInterface::luaExportInterface(L, *iface); + } + + template + static T* luaGetTypedUserData(LuaState L, int index) + { + void *ptr = LuaInterface::luaIsOfType(L, index, T::luaClassName); + if( !ptr ) + { + luaL_typerror(L(), index, T::luaClassName); + } + + T** ppNode = (T**)(ptr); + if(ppNode) + { + return *ppNode; + } + return NULL; + } +}; + +class LuaUserObject +{ +public: + LuaUserObject(LuaInterface* luaObject=NULL) : _luaObject(luaObject) {}; + void PushObject(LuaState state, const char* luaName = NULL) + { + if(_luaObject) _luaObject->luaPushObject(state, luaName); + } +private: + LuaInterface* _luaObject; +}; + +#ifndef DECLARE_LUA_INTERFACE +#define DECLARE_LUA_INTERFACE(BaseClass) \ + private: \ + typedef BaseClass tSuperClass; \ + public: \ + static const char* luaClassName; \ + static SInterfaceData* luaGetExportedInterface(SInterfaceData* iface=NULL); \ + protected: \ + virtual SInterfaceData* luaGetInterface(); \ + private: \ + static SInterfaceData luaInterface; +#endif // DECLARE_LUA_INTERFACE + +#ifndef IMPLEMENT_LUA_INTERFACE +#define IMPLEMENT_LUA_INTERFACE(className, classLuaName, AttribArray) \ + const char* className::luaClassName = classLuaName; \ + LuaInterface::SInterfaceData className::luaInterface; \ + LuaInterface::SInterfaceData* className::luaGetInterface() \ + { \ + return &(className::luaInterface); \ + } \ + LuaInterface::SInterfaceData* className::luaGetExportedInterface(LuaInterface::SInterfaceData* iface) \ + { \ + if(!iface) iface = &(className::luaInterface); \ + iface->ClassHierarchy.push_back(className::luaClassName); \ + iface->Attribs.push_back(AttribArray); \ + return tSuperClass::luaGetExportedInterface( iface ); \ + } +#endif // IMPLEMENT_LUA_INTERFACE + +#endif // _LUA_CLASS_INTERFACE_H_ + diff --git a/lua/lua_function.cpp b/lua/lua_function.cpp new file mode 100644 index 00000000..935675fc --- /dev/null +++ b/lua/lua_function.cpp @@ -0,0 +1,57 @@ +#include "DEBUG.H" +#include "lua/lua_function.h" + +template<> +LuaFunction& LuaFunction::Param(std::string const& par) +{ + if(m_is_function || is_function()) + { + lua_pushstring(_L, par.c_str()); + _counter++; + } + return *this; +} + +template<> +LuaFunction& LuaFunction::Param(double const& par) +{ + if(m_is_function || is_function()) + { + lua_pushnumber(_L, par); + _counter++; + } + return *this; +} + +template<> +LuaFunction& LuaFunction::Param(int const& par) +{ + if(m_is_function || is_function()) + { + lua_pushinteger(_L, par); + _counter++; + } + return *this; +} + +template<> +LuaFunction& LuaFunction::Param(unsigned int const& par) +{ + if(m_is_function || is_function()) + { + lua_pushnumber(_L, (double)par); + _counter++; + } + return *this; +} + +template<> +LuaFunction& LuaFunction::Param(bool const& par) +{ + if(m_is_function || is_function()) + { + lua_pushboolean(_L, par); + _counter++; + } + return *this; +} diff --git a/lua/lua_function.h b/lua/lua_function.h new file mode 100644 index 00000000..61534edc --- /dev/null +++ b/lua/lua_function.h @@ -0,0 +1,93 @@ +#ifndef _LUA_FUNCTION_H_ +#define _LUA_FUNCTION_H_ + +#include +#include + +#include + +class LuaFunction +{ +public: + LuaFunction(LuaState L, const char* function_name) + : _function_name(function_name), _L(L()), _counter(0), m_is_function(false) + { + lua_getglobal(_L, function_name); + } + + template + LuaFunction& Param(T const& par); + + template + LuaFunction& TParam(TI const index, TV const& par) + { + if(m_is_function || is_function(-2)) + { + if(!_tables.empty()) + { + LuaTable& tab = *_tables.top(); + tab.setValue(index, par); + } + } + return *this; + } + + LuaFunction& TableOpen() + { + _tables.push(new LuaTable(_L)); + return *this; + } + LuaFunction& TableClose() + { + if(!_tables.empty()) + { + LuaTable* tab = _tables.top(); + _tables.pop(); + if(tab) delete tab; + _counter++; + } + return *this; + } + + bool Call(int num_ret) + { + if(m_is_function || is_function()) + { + if(_tables.empty() && num_ret >= 0) + { + if( lua_pcall(_L, _counter, num_ret, 0) != 0) + { + std::string err = lua_tostring(_L, -1); + + std::wstring wstr; + convert_string(_function_name, wstr); + + std::wstringstream wss; + wss << L"Execution of lua function '" << wstr << L"' failed : "; + + convert_string(err, wstr); + wss << wstr; + + SGP_THROW(wss.str().c_str()); + } + return true; + } + } + return false; + } + +private: + bool is_function(int pos=-1) + { + return m_is_function = lua_isfunction(_L, pos); + } +private: + std::string _function_name; + lua_State* _L; + std::stack _tables; + int _counter; + bool m_is_function; +}; + + +#endif // _LUA_FUNCTION_H_ diff --git a/lua/lua_state.cpp b/lua/lua_state.cpp new file mode 100644 index 00000000..5b11019c --- /dev/null +++ b/lua/lua_state.cpp @@ -0,0 +1,293 @@ +#include "lua/lua_state.h" +#include +#include "sgp_logger.h" + +#include + +LuaState::LuaState(lua_State* state, bool own) : _L(state), _own(own), _registry(state) +{ +} + +LuaState::LuaState() : _L(NULL), _own(true), _registry(NULL) +{ + //_L = lua_open(); + //_registry._L = _L; +} + +LuaState::~LuaState() +{ +} + +void LuaState::init(bool init_libs) +{ + if(!_L) + { + _L = lua_open(); + if(init_libs) + { + luaL_openlibs(_L); + } + _registry._L = _L; + } +} + +void LuaState::close() +{ + if(_L && _own) + { + lua_close(_L); + } +} + +#include +bool LuaState::EvalFile(const char* filename) +{ + try + { + vfs::COpenReadFile rfile(filename); + vfs::UInt32 size = rfile.file().getSize(); + std::vector buffer(size+1); + rfile.file().read(&buffer[0], size); + buffer[size] = 0; + return this->EvalString((char*)&buffer[0], size, filename); + } + catch(std::exception &ex) + { + SGP_ERROR(ex.what()); + } + return false; +} + +bool LuaState::CallFunction(const char* function_name) +{ + if(function_name) + { + // call function + lua_getglobal(_L, function_name); + if(lua_isfunction(_L, -1)) + { + if( lua_pcall(_L, 0, 1, 0) != 0 ) + { + std::string err = lua_tostring(_L, -1); + std::wstringstream wss; + wss << L"Execution of lua function '" << vfs::String::as_utf16(function_name) << L"' failed : "; + wss << vfs::String::as_utf16(err); + SGP_THROW(wss.str().c_str()); + } + return true; + } + } + return false; +} + + +bool LuaState::EvalString(const wchar_t *lua_str, size_t length, const char* id_str) +{ + std::string s = vfs::String::as_utf8(lua_str, length); + + return this->EvalString(s.c_str(), s.length(), id_str); +} + +bool LuaState::EvalString(const char *lua_str, size_t length, const char* id_str) +{ + int error; + + if(length == 0) + { + length = strlen(lua_str); + } + error = luaL_loadbuffer(_L, lua_str, length, id_str) || + lua_pcall(_L, 0, 0, 0); + + if (error) + { + const char *error = lua_tostring(_L, -1); + int len = strlen( error); + if (len >= 7 && !strcmp( error + len - 7, "''")) + { + lua_pop(_L, 1); /* pop error message from the stack */ + return false; + } + std::string s = lua_tostring(_L, -1); + SGP_THROW(s); + //printf( "%s\n", lua_tostring(L, -1)); + //lua_pop(L, 1); /* pop error message from the stack */ + //return true; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////// + +LuaState::Registry::Registry(lua_State* L) : _L(L) +{ +} + +void LuaState::Registry::CreateCallbackTable() +{ + lua_getfield(_L, LUA_REGISTRYINDEX, "__CallBackRegistry"); + if(lua_isnil(_L,-1)) + { + lua_pop(_L,1); // pop 'nil' from stack + lua_newtable(_L); + lua_setfield(_L,LUA_REGISTRYINDEX,"__CallBackRegistry"); // 'setfield' removes value from stack + return; + } + else if(lua_istable(_L,-1)) + { + lua_pop(_L,1); + return; + } + SGP_THROW(L"Could not create callback registy table"); +} +void LuaState::Registry::GetCallbackTable() +{ + lua_getfield(_L, LUA_REGISTRYINDEX, "__CallBackRegistry"); + if(!lua_istable(_L,-1)) + { + SGP_THROW("CallBack registry table does not exist"); + } +} + +void LuaState::Registry::SetCallback(const char* callback_name) +{ + // function is at (L, -2) + // user data value is at (L, -1) + this->GetCallbackTable(); + lua_pushvalue(_L, -2); + lua_rawget(_L, -2); + if(!lua_istable(_L, -1)) + { + lua_pop(_L, 1); // remove 'nil' + // set new table + lua_pushvalue(_L, -2); + lua_newtable(_L); + lua_rawset(_L, -3); + // get table + lua_pushvalue(_L, -2); + lua_rawget(_L, -2); + } + if(!lua_istable(_L,-1)) + { + SGP_THROW("Could not create callback"); + } + lua_pushvalue(_L, -4); + lua_setfield(_L, -2, callback_name); + lua_pop(_L, 4); +} +void LuaState::Registry::GetCallback(const char* callback_name) +{ + // user data is at (L, -1) + this->GetCallbackTable(); + lua_pushvalue(_L, -2); + lua_rawget(_L, -2); + if(lua_istable(_L, -1)) + { + lua_getfield(_L, -1, callback_name); + if(lua_isfunction(_L, -1)) + { + lua_insert(_L, -4); + lua_pop(_L, 3); + if(!lua_isfunction(_L,-1)) + { + SGP_THROW("messed up stack"); + } + return; + } + // no callback defined + lua_pop(_L, 4); + } + // no table created + lua_pop(_L, 3); // also pops user data + return; +} + + +void LuaState::Registry::CreateUserDataTable() +{ + lua_getfield(_L, LUA_REGISTRYINDEX, "__UserData"); + if(lua_isnil(_L,-1)) + { + lua_pop(_L,1); // pop 'nil' from stack + lua_newtable(_L); + lua_setfield(_L,LUA_REGISTRYINDEX,"__UserData"); // 'setfield' removes value from stack + return; + } + else if(lua_istable(_L,-1)) + { + lua_pop(_L,1); + return; + } + SGP_THROW(L"Could not create User Data registy table"); +} + +void LuaState::Registry::GetUserDataTable() +{ + lua_getfield(_L, LUA_REGISTRYINDEX, "__UserData"); + if(!lua_istable(_L,-1)) + { + SGP_THROW("User Data registry table does not exist"); + } +} + + +/************************************************************************************/ + +#include + +class LuaStateManager +{ +public: + ~LuaStateManager() { + _states.clear(); + }; + + static LuaStateManager& instance() { + static LuaStateManager lsm; + return lsm; + }; + + LuaState& GetState(lua::State eState) { + return _states[eState]; + } + +private: + LuaStateManager() {}; + static std::map _states; +}; + +std::map LuaStateManager::_states; + + +void LuaState::INIT(lua::State state_id, bool init_libs) +{ + LuaStateManager::instance().GetState(state_id).init(init_libs); +} + +LuaState LuaState::INIT(bool init_libs) +{ + LuaState L; + L.init(init_libs); + return L; +} + +void LuaState::CLOSE(lua::State state_id) +{ + LuaStateManager::instance().GetState(state_id).close(); +} + +void LuaState::CLOSE(LuaState state) +{ + state.close(); +} + +LuaState LuaState::GET(lua::State state_id) +{ + return LuaStateManager::instance().GetState(state_id); +} + + + + + diff --git a/lua/lua_state.h b/lua/lua_state.h new file mode 100644 index 00000000..13704723 --- /dev/null +++ b/lua/lua_state.h @@ -0,0 +1,140 @@ +#ifndef _LUA_STATE_H_ +#define _LUA_STATE_H_ + +#include + +namespace lua +{ + enum State + { + LUA_STATE, + LUA_STATE_STRUCTURE, + LUA_STATE_GUI, + + LUA_STATE_STRATEGIC_MINES_AND_UNDERGROUND, + }; +}; + +class LuaState +{ + class Registry + { + public: + void CreateCallbackTable(); + void GetCallbackTable(); + + void SetCallback(const char* callback_name); + void GetCallback(const char* callback_name); + + void CreateUserDataTable(); + void GetUserDataTable(); + private: + friend class LuaState; + Registry(lua_State* L); + lua_State* _L; + }; +public: + /** + * takes over raw lua_State + * @param state pointer to lua_State + * @param own takes over raw state when true (= closes it) + */ + LuaState(lua_State* state, bool own=false); + + /** + * default ctor, does nothing other than allowing uninitialized variables + */ + LuaState(); + + /** + * default dtor + */ + ~LuaState(); + + /** + * initialize longterm lua state by its ID + */ + static void INIT(lua::State state_id, bool init_libs); + + /** + * initializes and returns shortterm lua state + */ + static LuaState INIT(bool init_libs=false); + + /** + * close longterm lua state + */ + static void CLOSE(lua::State state_id); + + /** + * close shortterm lua state + */ + static void CLOSE(LuaState state); + + /** + * get lua state after it was initialized (right before or in some other place) + */ + static LuaState GET(lua::State state_id); + + /** + * returns raw lua state + */ + inline lua_State* operator()() { return _L; } + + /** + * return registry object associated with this lua state + */ + inline Registry& registry() { return _registry; } + + /** + * loads and evaluates lua file. catches and logs error if file doesn't exist or could not be read. + * @return true if file could be loaded and evaluated, false otherwise. + */ + bool EvalFile(const char* filename); + + /** + * evaluate string + */ + bool EvalString(const char* lua_str, size_t length, const char* id_str); + /** + * evaluate string + */ + bool EvalString(const wchar_t* lua_str, size_t length, const char* id_str); + + /** + * deprecated (i guess), use LuaFunction instead + */ + bool CallFunction(const char* function_name); +private: + /** + * creates lua state and initializes additional libraries + * @param load_libs opens additional libraries if true + */ + void init(bool load_libs); + + /** + * closes lua state + */ + void close(); +private: + lua_State* _L; + bool _own; + Registry _registry; +}; + +class LuaScopeState +{ +public: + LuaState L; + + LuaScopeState(bool init_libs) : L(LuaState::INIT(init_libs)) + { + } + + ~LuaScopeState() + { + LuaState::CLOSE(L); + } +}; + +#endif // _LUA_STATE_H_ diff --git a/lua/lua_table.cpp b/lua/lua_table.cpp new file mode 100644 index 00000000..fcdc2a70 --- /dev/null +++ b/lua/lua_table.cpp @@ -0,0 +1,341 @@ +#include "lua/lua_table.h" + +/* + * Table constructors + */ + +LuaTable::LuaTable(LuaState L) +: _L(L) +{ + lua_newtable(_L()); + _off = -1; +} + +LuaTable::LuaTable(LuaState L, int st_off) +: _L(L), _off(st_off) +{}; + +LuaTable::LuaTable(LuaState L, const char* global) +: _L(L) +{ + lua_getglobal(_L(), global); + _off = -1; +}; + +LuaTable::LuaTable(LuaTable& table, const char* index) +: _off(-1) +{ + _L = table._L; + lua_State* L = _L(); + lua_getfield(L, table._off, index); + if(!is_valid()) + { + lua_pop(L,1); + } +} + +LuaTable::LuaTable(LuaTable& table, int index) +: _off(-1) +{ + _L = table._L; + lua_State* L = _L(); + lua_pushinteger(L, index); + lua_gettable(L, table._off < 0 ? table._off-1 : table._off); + if(!is_valid()) + { + lua_pop(L,1); + } +} + +///////////////////////////////////////////////////////////////////////////////// + +template<> +bool LuaTable::getValue(const char* index, std::string& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + lua_getfield(L, _off, index); + if(lua_isstring(L, -1)) + { + value = lua_tostring(L,-1); + lua_pop(L,1); + return true; + } + lua_pop(L,1); + } + return false; +} + +template<> +bool LuaTable::getValue(const char* index, double& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + lua_getfield(L, _off, index); + if(lua_isnumber(L, -1)) + { + value = lua_tonumber(L,-1); + lua_pop(L,1); + return true; + } + lua_pop(L,1); + } + return false; +} + +template<> +bool LuaTable::getValue(const char* index, int& value) +{ + double tmp; + if( getValue(index,tmp) ) + { + value = (int)tmp; + return true; + } + return false; +} +template<> +bool LuaTable::getValue(const char* index, unsigned int& value) +{ + double tmp; + if( getValue(index,tmp) ) + { + value = (unsigned int)tmp; + return true; + } + return false; +} + +template<> +bool LuaTable::getValue(const char* index, bool& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + lua_getfield(L, _off, index); + if(lua_isboolean(L, -1)) + { + value = lua_toboolean(L,-1) != 0; + lua_pop(L,1); + return true; + } + lua_pop(L,1); + } + return false; +} + +///// + +template<> +bool LuaTable::getValue(int index, std::string& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + lua_pushinteger(L, index); + lua_gettable(L, _off < 0 ? _off-1 : _off); + if(lua_isstring(L, -1)) + { + value = lua_tostring(L,-1); + lua_pop(L,1); + return true; + } + lua_pop(L,1); + } + return false; +} + +template<> +bool LuaTable::getValue(int index, double& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + lua_pushinteger(L, index); + lua_gettable(L, _off < 0 ? _off-1 : _off); + if(lua_isnumber(L, -1)) + { + value = lua_tonumber(L,-1); + lua_pop(L,1); + return true; + } + lua_pop(L,1); + } + return false; +} + +template<> +bool LuaTable::getValue(int index, int& value) +{ + double tmp; + if( getValue(index,tmp) ) + { + value = (int)tmp; + return true; + } + return false; +} +template<> +bool LuaTable::getValue(int index, unsigned int& value) +{ + double tmp; + if( getValue(index,tmp) ) + { + value = (unsigned int)tmp; + return true; + } + return false; +} + +template<> +bool LuaTable::getValue(int index, bool& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + lua_pushinteger(L, index); + lua_gettable(L, _off < 0 ? _off-1 : _off); + if(lua_isboolean(L, -1)) + { + value = lua_toboolean(L,-1) != 0; + lua_pop(L,1); + return true; + } + lua_pop(L,1); + } + return false; +} + +///////////////////////////////// + +template<> +bool LuaTable::setValue(const char* index, std::string const& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + + lua_pushstring(L, index); + lua_pushstring(L, value.c_str()); + lua_rawset(L, _off < 0 ? _off-2 : _off); + return true; + } + return false; +} + +template<> +bool LuaTable::setValue(const char* index, double const& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + + lua_pushstring(L, index); + lua_pushnumber(L, value); + lua_rawset(L, _off < 0 ? _off-2 : _off); + return true; + } + return false; +} + +template<> +bool LuaTable::setValue(const char* index, int const& value) +{ + return setValue(index, (double)value); +} +template<> +bool LuaTable::setValue(const char* index, unsigned int const& value) +{ + return setValue(index, (double)value); +} + +template<> +bool LuaTable::setValue(const char* index, bool const& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + + lua_pushstring(L, index); + lua_pushboolean(L, value); + lua_rawset(L, _off < 0 ? _off-2 : _off); + return true; + } + return false; +} + +///////////////////////////////////// + +template<> +bool LuaTable::setValue(int index, std::string const& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + + lua_pushinteger(L, index); + lua_pushstring(L, value.c_str()); + lua_rawset(L, _off < 0 ? _off-2 : _off); + return true; + } + return false; +} + +template<> +bool LuaTable::setValue(int index, double const& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + + lua_pushinteger(L, index); + lua_pushnumber(L, value); + lua_rawset(L, _off < 0 ? _off-2 : _off); + return true; + } + return false; +} + +template<> +bool LuaTable::setValue(int index, int const& value) +{ + return setValue(index, (double)value); +} +template<> +bool LuaTable::setValue(int index, unsigned int const& value) +{ + return setValue(index, (double)value); +} + +template<> +bool LuaTable::setValue(int index, bool const& value) +{ + if(is_valid()) + { + lua_State* L = _L(); + + lua_pushinteger(L, index); + lua_pushboolean(L, value); + lua_rawset(L, _off < 0 ? _off-2 : _off); + return true; + } + return false; +} + +///////////////////////////////////////////////////////////////////////////////////// + +int LuaTable::length() +{ + return (int)lua_objlen(_L(), _off); +} + +bool LuaTable::is_valid() +{ + if(lua_istable(_L(), _off)) + { + return true; + } + return false; +} diff --git a/lua/lua_table.h b/lua/lua_table.h new file mode 100644 index 00000000..b7df48bb --- /dev/null +++ b/lua/lua_table.h @@ -0,0 +1,128 @@ +#ifndef _LUA_TABLE_H_ +#define _LUA_TABLE_H_ + +#include "lua/lua_state.h" + +class LuaTable +{ +public: + /** + * Create new table + */ + LuaTable(LuaState L); + + /** + * Bind to table at stack offset 'st_off' + */ + LuaTable(LuaState L, int st_off); + + /** + * Bind to table with global name 'global' + */ + LuaTable(LuaState L, const char* global); + + /** + * Bind to table value 'index' of table 'table' + */ + LuaTable(LuaTable& table, const char* index); + + /** + * Bind to table value 'index' of table 'table' + */ + LuaTable(LuaTable& table, int index); + + //////////////////////////////////////////////////////////////////////// + + /** + * get value at given index; default implementation for standard types exists + * @return true if value at index exists and has required type, false otherwise + */ + template + bool getValue(const char* index, T& value); + + /** + * get value at given index; default implementation for standard types exists + * @return true if value at index exists and has required type, false otherwise + */ + template + bool getValue(int index, T& value); + + /** + * If value has not standard type, then the default implementation expects it to be user data. + * The userdata object itself must inherit from the 'LuaInterface' class. + * @return object if it has correct type, NULL otherwise + */ + template + T* getValue(const char* index) + { + if(is_valid()) + { + lua_getfield(_L(), _off, index); + T* value = LuaInterface::luaGetTypedUserData(_L, -1); + return value; + } + return NULL; + } + + /** + * set value at given index + * @return false if table object is invalid, true otherwise + */ + template + bool setValue(const char* index, T const& value); + + /** + * set value at given index + * @return false if table object is invalid, true otherwise + */ + template + bool setValue(int index, T const& value); + + //////////////////////////////////////////////////////////////////////// + + /** + * is it a table at offset '_off' + */ + bool is_valid(); + + /** + * returns size of table as determined by the "#" operator + */ + int length(); + +private: + LuaState _L; + int _off; +}; + +///////////////////// +// default implementation for 'getValue(const char*, xxx)' +template<> bool LuaTable::getValue (const char* index, std::string& value); +template<> bool LuaTable::getValue (const char* index, double& value); +template<> bool LuaTable::getValue (const char* index, int& value); +template<> bool LuaTable::getValue(const char* index, unsigned int& value); +template<> bool LuaTable::getValue (const char* index, bool& value); + +// default implementation for 'getValue(int, xxx)' +template<> bool LuaTable::getValue (int index, std::string& value); +template<> bool LuaTable::getValue (int index, double& value); +template<> bool LuaTable::getValue (int index, int& value); +template<> bool LuaTable::getValue(int index, unsigned int& value); +template<> bool LuaTable::getValue (int index, bool& value); + +///////////////////// +// default implementation for 'setValue(const char*, xxx)' +template<> bool LuaTable::setValue (const char* index, std::string const& value); +template<> bool LuaTable::setValue (const char* index, double const& value); +template<> bool LuaTable::setValue (const char* index, int const& value); +template<> bool LuaTable::setValue(const char* index, unsigned int const& value); +template<> bool LuaTable::setValue (const char* index, bool const& value); + +// default implementation for 'setValue(int*, xxx)' +template<> bool LuaTable::setValue (int index, std::string const& value); +template<> bool LuaTable::setValue (int index, double const& value); +template<> bool LuaTable::setValue (int index, int const& value); +template<> bool LuaTable::setValue(int index, unsigned int const& value); +template<> bool LuaTable::setValue (int index, bool const& value); + +#endif // _LUA_TABLE_H_