mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
New Feature: gear templates allow us to save and load a merc's equipment, thereby speeding up the equipment process.
For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23462&goto=350497&#msg_350497 Requires GameDir >= r2384 git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8440 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
+9
-9
@@ -15,9 +15,9 @@
|
||||
#ifdef JA2EDITOR
|
||||
|
||||
#ifdef JA2UB
|
||||
CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Unfinished Business - Map Editor v1.13.8440 (Development Build)" };
|
||||
#else
|
||||
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Map Editor v1.13.8440 (Development Build)" };
|
||||
#endif
|
||||
|
||||
// ------------------------------
|
||||
@@ -27,11 +27,11 @@
|
||||
|
||||
//DEBUG BUILD VERSION
|
||||
#ifdef JA2UB
|
||||
CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Debug: Unfinished Business - v1.13.8440 (Development Build)" };
|
||||
#elif defined (JA113DEMO)
|
||||
CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Debug: JA2 Demo - v1.13.8440 (Development Build)" };
|
||||
#else
|
||||
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Debug: v1.13.8440 (Development Build)" };
|
||||
#endif
|
||||
|
||||
#elif defined CRIPPLED_VERSION
|
||||
@@ -46,16 +46,16 @@
|
||||
|
||||
//RELEASE BUILD VERSION
|
||||
#ifdef JA2UB
|
||||
CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Release Unfinished Business - v1.13.8440 (Development Build)" };
|
||||
#elif defined (JA113DEMO)
|
||||
CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Release JA2 Demo - v1.13.8440 (Development Build)" };
|
||||
#else
|
||||
CHAR16 zVersionLabel[256] = { L"Release v1.13.8434 (Development Build)" };
|
||||
CHAR16 zVersionLabel[256] = { L"Release v1.13.8440 (Development Build)" };
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
CHAR8 czVersionNumber[16] = { "Build 17.07.29" }; //YY.MM.DD
|
||||
CHAR8 czVersionNumber[16] = { "Build 17.08.06" }; //YY.MM.DD
|
||||
CHAR16 zTrackingNumber[16] = { L"Z" };
|
||||
|
||||
// SAVE_GAME_VERSION is defined in header, change it there
|
||||
|
||||
@@ -199,7 +199,7 @@ UINT32 guiMapInvenSortButton[4];
|
||||
|
||||
UINT32 guiMapInvenFilterButtonImage[MAP_INVENTORY_FILTER_BUTTONS];
|
||||
UINT32 guiMapInvenFilterButton[MAP_INVENTORY_FILTER_BUTTONS];
|
||||
|
||||
BOOLEAN guiMapInvenFilterButtonDefined[MAP_INVENTORY_FILTER_BUTTONS];
|
||||
|
||||
|
||||
BOOLEAN gfCheckForCursorOverMapSectorInventoryItem = FALSE;
|
||||
@@ -286,6 +286,11 @@ void MapInventoryPoolEjectAmmoBtn( GUI_BUTTON *btn, INT32 reason );
|
||||
// HEADROCK HAM 5: Preliminary Filter Button
|
||||
void MapInventoryPoolFilterBtn( GUI_BUTTON *btn, INT32 reason );
|
||||
void MapInventoryPoolFilterBtnMoveItemDisplay( GUI_BUTTON *btn, INT32 reason ); // Flugente
|
||||
|
||||
// Flugente: gear templates
|
||||
void MapInventoryWriteEquipmentTemplate(GUI_BUTTON *btn, INT32 reason);
|
||||
void MapInventoryReadEquipmentTemplate(GUI_BUTTON *btn, INT32 reason);
|
||||
|
||||
void DisplayCurrentSector( void );
|
||||
void ResizeInventoryList( void );
|
||||
#ifdef INVFIX_Moa//dnl ch85 050214
|
||||
@@ -821,7 +826,8 @@ void UpdateHelpTextForInvnentoryStashSlots( void )
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Flugente:
|
||||
extern void EquipmentListMenuCancel( );
|
||||
|
||||
// create and remove buttons for inventory
|
||||
void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen )
|
||||
@@ -1861,6 +1867,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 0 ] ]->UserData[1] = IC_MAPFILTER_ALL;
|
||||
ButtonList[ guiMapInvenFilterButton[ 0 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 0 ] ]->UserData[3] = 0;
|
||||
guiMapInvenFilterButtonDefined[0] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 20, 20, -1, 21, -1 );
|
||||
guiMapInvenFilterButton[ 1 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 1 ], INVEN_POOL_X+214 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
@@ -1872,6 +1879,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 1 ] ]->UserData[1] = IC_MAPFILTER_GUN;
|
||||
ButtonList[ guiMapInvenFilterButton[ 1 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 1 ] ]->UserData[3] = IC_MAPFILTER_GUN;
|
||||
guiMapInvenFilterButtonDefined[1] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 2 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 22, 22, -1, 23, -1 );
|
||||
guiMapInvenFilterButton[ 2 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 2 ], INVEN_POOL_X+214 + xResOffset, INVEN_POOL_Y + 24 + yResOffset,
|
||||
@@ -1883,6 +1891,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 2 ] ]->UserData[1] = IC_MAPFILTER_AMMO;
|
||||
ButtonList[ guiMapInvenFilterButton[ 2 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 2 ] ]->UserData[3] = IC_MAPFILTER_AMMO;
|
||||
guiMapInvenFilterButtonDefined[2] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 3 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 24, 24, -1, 25, -1 );
|
||||
guiMapInvenFilterButton[ 3 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 3 ], INVEN_POOL_X+243 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
@@ -1894,6 +1903,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 3 ] ]->UserData[1] = IC_MAPFILTER_EXPLOSV;
|
||||
ButtonList[ guiMapInvenFilterButton[ 3 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 3 ] ]->UserData[3] = IC_MAPFILTER_EXPLOSV;
|
||||
guiMapInvenFilterButtonDefined[3] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 4 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 26, 26, -1, 27, -1 );
|
||||
guiMapInvenFilterButton[ 4 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 4 ], INVEN_POOL_X+243 + xResOffset, INVEN_POOL_Y + 24 + yResOffset,
|
||||
@@ -1905,6 +1915,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 4 ] ]->UserData[1] = IC_MAPFILTER_MELEE;
|
||||
ButtonList[ guiMapInvenFilterButton[ 4 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 4 ] ]->UserData[3] = IC_MAPFILTER_MELEE;
|
||||
guiMapInvenFilterButtonDefined[4] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 5 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 28, 28, -1, 29, -1 );
|
||||
guiMapInvenFilterButton[ 5 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 5 ], INVEN_POOL_X+272 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
@@ -1916,6 +1927,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 5 ] ]->UserData[1] = IC_MAPFILTER_ARMOR;
|
||||
ButtonList[ guiMapInvenFilterButton[ 5 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 5 ] ]->UserData[3] = IC_MAPFILTER_ARMOR;
|
||||
guiMapInvenFilterButtonDefined[5] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 6 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 30, 30, -1, 31, -1 );
|
||||
guiMapInvenFilterButton[ 6 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 6 ], INVEN_POOL_X+272 + xResOffset, INVEN_POOL_Y + 24 + yResOffset,
|
||||
@@ -1927,6 +1939,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 6 ] ]->UserData[1] = IC_MAPFILTER_LBE;
|
||||
ButtonList[ guiMapInvenFilterButton[ 6 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 6 ] ]->UserData[3] = IC_MAPFILTER_LBE;
|
||||
guiMapInvenFilterButtonDefined[6] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 7 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 32, 32, -1, 33, -1 );
|
||||
guiMapInvenFilterButton[ 7 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 7 ], INVEN_POOL_X+301 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
@@ -1938,6 +1951,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 7 ] ]->UserData[1] = IC_MAPFILTER_KIT;
|
||||
ButtonList[ guiMapInvenFilterButton[ 7 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 7 ] ]->UserData[3] = IC_MAPFILTER_KIT;
|
||||
guiMapInvenFilterButtonDefined[7] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[ 8 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 34, 34, -1, 35, -1 );
|
||||
guiMapInvenFilterButton[ 8 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 8 ], INVEN_POOL_X+301 + xResOffset, INVEN_POOL_Y + 24 + yResOffset,
|
||||
@@ -1949,6 +1963,7 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 8 ] ]->UserData[1] = IC_MAPFILTER_MISC;
|
||||
ButtonList[ guiMapInvenFilterButton[ 8 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 8 ] ]->UserData[3] = IC_MAPFILTER_MISC;
|
||||
guiMapInvenFilterButtonDefined[8] = TRUE;
|
||||
|
||||
// Flugente: toggle button for move item display
|
||||
guiMapInvenFilterButtonImage[ 9 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 36, 36, -1, 37, -1 );
|
||||
@@ -1963,24 +1978,33 @@ void CreateMapInventoryButtons( void )
|
||||
ButtonList[ guiMapInvenFilterButton[ 9 ] ]->UserData[1] = IC_MAPFILTER_MISC;
|
||||
ButtonList[ guiMapInvenFilterButton[ 9 ] ]->UserData[2] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 9 ] ]->UserData[3] = IC_MAPFILTER_MISC;
|
||||
guiMapInvenFilterButtonDefined[9] = TRUE;
|
||||
|
||||
/*
|
||||
guiMapInvenFilterButtonImage[ 9 ]= LoadButtonImage( "INTERFACE\\sector_inventory_buttons.sti" , 19, 17, -1, 18, -1 );
|
||||
guiMapInvenFilterButton[ 9 ] = QuickCreateButton( guiMapInvenFilterButtonImage[ 9 ], INVEN_POOL_X+340 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
// as no space is left, further buttons require better resolutions
|
||||
if ( iResolution > _640x480 )
|
||||
{
|
||||
// Flugente: gear templates
|
||||
guiMapInvenFilterButtonImage[10] = LoadButtonImage("INTERFACE\\sector_inventory_buttons.sti", 40, 40, -1, 40, -1);
|
||||
guiMapInvenFilterButton[10] = QuickCreateButton(guiMapInvenFilterButtonImage[10], INVEN_POOL_X + 371 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST,
|
||||
NULL, (GUI_CALLBACK)MapInventoryPoolFilterBtn );
|
||||
NULL, (GUI_CALLBACK)MapInventoryWriteEquipmentTemplate);
|
||||
|
||||
SetButtonFastHelpText( guiMapInvenFilterButton[ 9 ], pMapScreenInvenButtonHelpText[ 17 ] );
|
||||
ButtonList[ guiMapInvenFilterButton[ 9 ] ]->UserData[0] = 0;
|
||||
ButtonList[ guiMapInvenFilterButton[ 9 ] ]->UserData[1] = 0;
|
||||
*/
|
||||
SetButtonFastHelpText(guiMapInvenFilterButton[10], pMapScreenInvenButtonHelpText[18]);
|
||||
guiMapInvenFilterButtonDefined[10] = TRUE;
|
||||
|
||||
guiMapInvenFilterButtonImage[11] = LoadButtonImage("INTERFACE\\sector_inventory_buttons.sti", 42, 42, -1, 42, -1);
|
||||
guiMapInvenFilterButton[11] = QuickCreateButton(guiMapInvenFilterButtonImage[11], INVEN_POOL_X + 406 + xResOffset, INVEN_POOL_Y + 10 + yResOffset,
|
||||
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST,
|
||||
NULL, (GUI_CALLBACK)MapInventoryReadEquipmentTemplate);
|
||||
|
||||
SetButtonFastHelpText(guiMapInvenFilterButton[11], pMapScreenInvenButtonHelpText[19]);
|
||||
guiMapInvenFilterButtonDefined[11] = TRUE;
|
||||
}
|
||||
|
||||
//reset the current inventory page to be the first page
|
||||
iCurrentInventoryPoolPage = 0;
|
||||
|
||||
HandleSetFilterButtons();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2010,11 +2034,18 @@ void DestroyMapInventoryButtons( void )
|
||||
UnloadButtonImage( guiMapInvenSortButtonImage[ 3 ] );
|
||||
|
||||
// HEADROCK HAM 5: Filter button
|
||||
for (INT32 iCounter = 0; iCounter < MAP_INVENTORY_FILTER_BUTTONS; iCounter++)
|
||||
for (INT32 iCounter = 0; iCounter < MAP_INVENTORY_FILTER_BUTTONS; ++iCounter)
|
||||
{
|
||||
if ( guiMapInvenFilterButtonDefined[ iCounter ] )
|
||||
{
|
||||
RemoveButton( guiMapInvenFilterButton[ iCounter ] );
|
||||
UnloadButtonImage( guiMapInvenFilterButtonImage[ iCounter ] );
|
||||
guiMapInvenFilterButtonDefined[ iCounter ] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: destroy gear template selection, in case that thing is still open
|
||||
EquipmentListMenuCancel( );
|
||||
|
||||
/*
|
||||
// Destroy the popup.
|
||||
@@ -2023,8 +2054,6 @@ void DestroyMapInventoryButtons( void )
|
||||
gfMapInventoryFilterPopupInitialized = FALSE;
|
||||
gfMapInventoryFilterPopupVisible = FALSE;
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
@@ -2937,28 +2966,99 @@ void MapInventoryPoolFilterBtnMoveItemDisplay( GUI_BUTTON *btn, INT32 reason )
|
||||
// The refresh function moves the necessary items from the Seen to the Unseen inventories, and vice versa.
|
||||
RefreshSeenAndUnseenPools();
|
||||
|
||||
BlitInventoryPoolGraphic( );
|
||||
BlitInventoryPoolGraphic();
|
||||
|
||||
HandleSetFilterButtons();
|
||||
}
|
||||
}
|
||||
/*if (reason & MSYS_CALLBACK_REASON_RBUTTON_UP)
|
||||
}
|
||||
|
||||
// Flugente: gear templates
|
||||
extern void WriteEquipmentTemplate(SOLDIERTYPE* pSoldier, STR16 name);
|
||||
extern void EquipmentListMenu( );
|
||||
|
||||
void TemplateNameInputCallBack(UINT8 ubResult)
|
||||
{
|
||||
if (ubResult == MSG_BOX_RETURN_OK && wcscmp(gszMsgBoxInputString, L"") > 0)
|
||||
{
|
||||
if (btn->uiFlags & (BUTTON_CLICKED_ON))
|
||||
SOLDIERTYPE* pSoldier = &Menptr[gCharactersList[bSelectedInfoChar].usSolID];
|
||||
if (pSoldier)
|
||||
{
|
||||
if (btn->UserData[2] == 0)
|
||||
WriteEquipmentTemplate(pSoldier, gszMsgBoxInputString);
|
||||
|
||||
// The refresh function moves the necessary items from the Seen to the Unseen inventories, and vice versa.
|
||||
RefreshSeenAndUnseenPools();
|
||||
|
||||
BlitInventoryPoolGraphic();
|
||||
|
||||
HandleSetFilterButtons();
|
||||
}
|
||||
}
|
||||
memset(gszMsgBoxInputString, 0, sizeof(gszMsgBoxInputString));
|
||||
}
|
||||
|
||||
void MapInventoryWriteEquipmentTemplate(GUI_BUTTON *btn, INT32 reason)
|
||||
{
|
||||
if ( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ||
|
||||
reason & MSYS_CALLBACK_REASON_RBUTTON_DWN )
|
||||
{
|
||||
MapInventoryFilterSet( btn->UserData[3] );
|
||||
if ( !(btn->uiFlags & (BUTTON_CLICKED_ON)) )
|
||||
{
|
||||
// Set as "clicked on", but do nothing until the mouse is released.
|
||||
btn->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
if ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
|
||||
{
|
||||
if ( btn->uiFlags & (BUTTON_CLICKED_ON) )
|
||||
{
|
||||
SOLDIERTYPE* pSoldier = &Menptr[gCharactersList[bSelectedInfoChar].usSolID];
|
||||
if ( pSoldier )
|
||||
{
|
||||
DoMessageBox( MSG_BOX_BASIC_SMALL_BUTTONS, szGearTemplateText[0], guiCurrentScreen, MSG_BOX_FLAG_INPUTBOX, TemplateNameInputCallBack, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapInventoryReadEquipmentTemplate(GUI_BUTTON *btn, INT32 reason)
|
||||
{
|
||||
if ( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN ||
|
||||
reason & MSYS_CALLBACK_REASON_RBUTTON_DWN )
|
||||
{
|
||||
if ( !(btn->uiFlags & (BUTTON_CLICKED_ON)) )
|
||||
{
|
||||
// Set as "clicked on", but do nothing until the mouse is released.
|
||||
btn->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
if ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
|
||||
{
|
||||
if ( btn->uiFlags & (BUTTON_CLICKED_ON) )
|
||||
{
|
||||
SOLDIERTYPE* pSoldier = &Menptr[gCharactersList[bSelectedInfoChar].usSolID];
|
||||
if ( pSoldier &&
|
||||
pSoldier->sSectorX == sSelMapX && pSoldier->sSectorY == sSelMapY && pSoldier->bSectorZ == iCurrentMapSectorZ &&
|
||||
!pSoldier->flags.fBetweenSectors )
|
||||
{
|
||||
if ( (gTacticalStatus.uiFlags & INCOMBAT || gTacticalStatus.fEnemyInSector) )
|
||||
{
|
||||
DoScreenIndependantMessageBox( szGearTemplateText[1], MSG_BOX_FLAG_OK, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
MapInventoryFilterToggle( btn->UserData[3] );
|
||||
// open the menu
|
||||
EquipmentListMenu( );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DoScreenIndependantMessageBox( szGearTemplateText[2], MSG_BOX_FLAG_OK, NULL );
|
||||
}
|
||||
}
|
||||
|
||||
// HEADROCK HAM 5: Disabled for now, as we've got buttons for this.
|
||||
//CreateMapInventoryFilterMenu( );
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// HEADROCK HAM 5: Zoom button.
|
||||
@@ -5138,7 +5238,11 @@ void SortSectorInventorySeparateAttachments()
|
||||
while ((size = pInventoryItem->object[x]->attachments.size()) != cnt)
|
||||
{
|
||||
OBJECTTYPE * pNewObj = new OBJECTTYPE();
|
||||
gpTempObject = pInventoryItem->object[x]->GetAttachmentAtIndex(size - 1 - cnt);
|
||||
|
||||
// Flugente: prevent an underflow
|
||||
UINT8 attindex = size > cnt ? size - 1 - cnt : 0;
|
||||
|
||||
gpTempObject = pInventoryItem->object[x]->GetAttachmentAtIndex( attindex );
|
||||
|
||||
//WarmSteel - This actually still works with NAS, be it by accident
|
||||
if (gpTempObject != NULL && pInventoryItem->object.RemoveAttachment(gpTempObject, pNewObj, x))
|
||||
@@ -5153,13 +5257,13 @@ void SortSectorInventorySeparateAttachments()
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt++;
|
||||
++cnt;
|
||||
}
|
||||
|
||||
uiLoopCnt++;
|
||||
++uiLoopCnt;
|
||||
|
||||
// Failsafe
|
||||
if (uiLoopCnt > 100)
|
||||
if (uiLoopCnt > 50)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -5262,6 +5366,83 @@ void SortSectorInventoryStackAndMerge(bool ammoOnly )
|
||||
fMapPanelDirty = TRUE;
|
||||
}
|
||||
|
||||
// Flugente: on a key press, we loop over each team members' inventory and exchange it with world items that have a higher status
|
||||
// however, we ignore items that have inseparable attachments
|
||||
// the goal is to simulate the player manually changing items, as that is rather tedious
|
||||
BOOL GetBetterObject_InventoryPool(UINT16 usItem, INT16 status, UINT32& arLoop, UINT8& arIndex)
|
||||
{
|
||||
OBJECTTYPE* pBestObj = NULL;
|
||||
|
||||
INT16 beststatus = status;
|
||||
BOOLEAN found = FALSE;
|
||||
|
||||
for (UINT32 uiLoop = 0; uiLoop < pInventoryPoolList.size(); ++uiLoop) // ... for all items in the world ...
|
||||
{
|
||||
if (pInventoryPoolList[uiLoop].object.exists() &&
|
||||
pInventoryPoolList[uiLoop].usFlags & WORLD_ITEM_REACHABLE &&
|
||||
!(pInventoryPoolList[uiLoop].usFlags & WORLD_ITEM_ARMED_BOMB) &&
|
||||
pInventoryPoolList[uiLoop].bVisible == VISIBLE &&
|
||||
pInventoryPoolList[uiLoop].object.usItem == usItem)
|
||||
{
|
||||
OBJECTTYPE* pObj = &(pInventoryPoolList[uiLoop].object);
|
||||
|
||||
if (pObj != NULL )
|
||||
{
|
||||
for (UINT8 i = 0; i < pObj->ubNumberOfObjects; ++i)
|
||||
{
|
||||
if ((*pObj)[i]->data.objectStatus > beststatus)
|
||||
{
|
||||
// ignore if there are inseparable attachments - we wouldn't be able to change those by hand
|
||||
attachmentList::iterator iterend = (*pObj)[i]->attachments.end();
|
||||
for (attachmentList::iterator iter = (*pObj)[i]->attachments.begin(); iter != iterend; ++iter)
|
||||
{
|
||||
if (iter->exists() && Item[iter->usItem].inseparable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
beststatus = (*pObj)[i]->data.objectStatus;
|
||||
arLoop = uiLoop;
|
||||
arIndex = i;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Flugente: tell us the position of the first inventory item with a fitting calibre and ammotype
|
||||
BOOL GetFittingAmmo_InventoryPool( UINT8 usCalibre, UINT8 usAmmoType, UINT32& arLoop )
|
||||
{
|
||||
for ( UINT32 uiLoop = 0; uiLoop < pInventoryPoolList.size( ); ++uiLoop )
|
||||
{
|
||||
if ( pInventoryPoolList[uiLoop].object.exists( ) &&
|
||||
pInventoryPoolList[uiLoop].usFlags & WORLD_ITEM_REACHABLE &&
|
||||
!(pInventoryPoolList[uiLoop].usFlags & WORLD_ITEM_ARMED_BOMB) &&
|
||||
pInventoryPoolList[uiLoop].bVisible == VISIBLE &&
|
||||
(Item[pInventoryPoolList[uiLoop].object.usItem].usItemClass & IC_AMMO) )
|
||||
{
|
||||
UINT16 usMagIndex = Item[pInventoryPoolList[uiLoop].object.usItem].ubClassIndex;
|
||||
|
||||
if ( usCalibre == Magazine[usMagIndex].ubCalibre )
|
||||
{
|
||||
if ( usAmmoType == Magazine[usMagIndex].ubAmmoType )
|
||||
{
|
||||
arLoop = uiLoop;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// HEADROCK HAM 5: This is a helper function that puts together all seen and unseen items from the two
|
||||
// sector-inventory pools, and then rebuilds the pool. By changing the flags used by the function that tests
|
||||
// whether an item should appear in the "SEEN" list, we can create filters to show or hide specific items.
|
||||
@@ -5767,9 +5948,14 @@ void MapInventoryFilterSet( UINT32 uiFlags )
|
||||
void HandleSetFilterButtons()
|
||||
{
|
||||
// Show/Hide All button always off.
|
||||
if ( guiMapInvenFilterButtonDefined[0] )
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 0 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
|
||||
// Guns
|
||||
if ( guiMapInvenFilterButtonDefined[1] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_GUN)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 1 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5778,8 +5964,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 1 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Ammo
|
||||
if ( guiMapInvenFilterButtonDefined[2] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_AMMO)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 2 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5788,8 +5977,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 2 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Explosives
|
||||
if ( guiMapInvenFilterButtonDefined[3] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_EXPLOSV)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 3 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5798,8 +5990,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 3 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Melee Weapons
|
||||
if ( guiMapInvenFilterButtonDefined[4] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_MELEE)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 4 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5808,8 +6003,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 4 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Armor
|
||||
if ( guiMapInvenFilterButtonDefined[5] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_ARMOR)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 5 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5818,8 +6016,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 5 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// LBEs
|
||||
if ( guiMapInvenFilterButtonDefined[6] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_LBE)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 6 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5828,8 +6029,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 6 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Kits
|
||||
if ( guiMapInvenFilterButtonDefined[7] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_KIT)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 7 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5838,8 +6042,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 7 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Misc. Items
|
||||
if ( guiMapInvenFilterButtonDefined[8] )
|
||||
{
|
||||
if (guiMapInventoryFilter & IC_MAPFILTER_MISC)
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 8 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5848,8 +6055,11 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 8 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: move item display
|
||||
if ( guiMapInvenFilterButtonDefined[9] )
|
||||
{
|
||||
if ( IsShowMoveItem() )
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 9 ]]->uiFlags |= (BUTTON_CLICKED_ON);
|
||||
@@ -5858,6 +6068,7 @@ void HandleSetFilterButtons()
|
||||
{
|
||||
ButtonList[guiMapInvenFilterButton[ 9 ]]->uiFlags &=~ (BUTTON_CLICKED_ON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Moa:moved code to CreateDestroyMapInventoryPoolButtons() and EnterSector() to decrease loading time
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define MAX_DISTANCE_TO_PICKUP_ITEM 5
|
||||
|
||||
// Flugente: number of map inventory filter buttons
|
||||
#define MAP_INVENTORY_FILTER_BUTTONS 10 // Flugente: 9 -> 10
|
||||
#define MAP_INVENTORY_FILTER_BUTTONS 12 // Flugente: 9 -> 12
|
||||
|
||||
// number of inventory slots
|
||||
//#define MAP_INVENTORY_POOL_SLOT_COUNT 84 //45 //45
|
||||
|
||||
@@ -78,6 +78,9 @@
|
||||
#include "Game Clock.h" // added by Flugente
|
||||
#include <vfs/Core/vfs_file_raii.h> // added by Flugente for vfs-stuff
|
||||
#include "DynamicDialogue.h" // added by Flugente for SoldierRelation()
|
||||
#include "MessageBoxScreen.h" // added by Flugente
|
||||
#include "Map Screen Interface.h" // added by Flugente
|
||||
#include "Map Screen Interface Map.h" // added by Flugente
|
||||
#endif
|
||||
|
||||
#ifdef JA2UB
|
||||
@@ -92,6 +95,18 @@
|
||||
// directory for fortification plans (located in Profiles sub-folder)
|
||||
#define FORTIFICATIONPLAN_DIRECTORY "FortificationPlan\\"
|
||||
|
||||
#define EQUIPMENTTEMPLATE_DIRECTORY "GearTemplate\\"
|
||||
|
||||
extern BOOL GetBetterObject_InventoryPool( UINT16 usItem, INT16 status, UINT32& arLoop, UINT8& arIndex );
|
||||
extern BOOL GetFittingAmmo_InventoryPool( UINT8 usCalibre, UINT8 usAmmoType, UINT32& arLoop );
|
||||
|
||||
extern BOOLEAN HandleNailsVestFetish( SOLDIERTYPE *pSoldier, UINT32 uiHandPos, UINT16 usReplaceItem );
|
||||
|
||||
extern std::vector<WORLDITEM> pInventoryPoolList;
|
||||
extern INT32 GetAttachmentInfoIndex( UINT16 usItem );
|
||||
|
||||
extern INT32 giItemDescAmmoButton;
|
||||
|
||||
ITEM_POOL_LOCATOR FlashItemSlots[ NUM_ITEM_FLASH_SLOTS ];
|
||||
UINT32 guiNumFlashItemSlots = 0;
|
||||
// sevenfm: remember network settings for last planted tripwire
|
||||
@@ -8970,3 +8985,769 @@ BOOLEAN SpendMoney( SOLDIERTYPE *pSoldier, UINT32 aAmount )
|
||||
|
||||
return (aAmount == 0);
|
||||
}
|
||||
|
||||
// Flugente: gear templates
|
||||
extern std::vector<std::string> gTemplateVector;
|
||||
|
||||
// this class is used to store our gear templates
|
||||
class GEAR_NODE
|
||||
{
|
||||
public:
|
||||
GEAR_NODE(INT8 a, UINT16 b, UINT16 c) :
|
||||
slot( a ), item( b ), ammoitem(c){}
|
||||
|
||||
GEAR_NODE() :
|
||||
slot( NOWHERE ), item( 0 ), ammoitem(0) {}
|
||||
|
||||
void swap(GEAR_NODE& other)
|
||||
{
|
||||
std::swap( slot, other.slot );
|
||||
std::swap( item, other.item );
|
||||
std::swap( ammoitem, other.ammoitem );
|
||||
|
||||
std::vector<UINT16> tmp = other.attachments;
|
||||
other.attachments = attachments;
|
||||
attachments = tmp;
|
||||
}
|
||||
|
||||
INT8 slot;
|
||||
UINT16 item;
|
||||
UINT16 ammoitem;
|
||||
|
||||
std::vector<UINT16> attachments;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, GEAR_NODE const& data)
|
||||
{
|
||||
stream << (int)(data.slot) << " " << (UINT16)(data.item) << " " << (UINT16)(data.ammoitem);
|
||||
|
||||
std::vector<UINT16> tmp = data.attachments;
|
||||
|
||||
for ( std::vector<UINT16>::iterator it = tmp.begin( ); it != tmp.end( ); ++it )
|
||||
stream << " " << (*it);
|
||||
|
||||
stream << std::endl;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::vector<GEAR_NODE> LoadEquipmentTemplate( std::string aName )
|
||||
{
|
||||
CHAR8 filename[MAX_PATH];
|
||||
|
||||
sprintf(filename, "%s%s", EQUIPMENTTEMPLATE_DIRECTORY, aName.c_str());
|
||||
|
||||
// get full path to save file
|
||||
vfs::Path vfsPath;
|
||||
vfs::COpenWriteFile rfile( filename, true );
|
||||
rfile->_getRealPath(vfsPath);
|
||||
std::string str = vfsPath.to_string();
|
||||
|
||||
const char* filenamewithpath = str.c_str();
|
||||
|
||||
// Read data
|
||||
std::ifstream file;
|
||||
file.open(filenamewithpath, std::ios::in);
|
||||
std::vector<GEAR_NODE> vec;
|
||||
|
||||
std::string line;
|
||||
|
||||
while ( std::getline( file >> std::ws, line ) )
|
||||
{
|
||||
if ( line[0] != '#' && line[0] != '/' )
|
||||
{
|
||||
std::istringstream iss( line );
|
||||
|
||||
GEAR_NODE node;
|
||||
|
||||
int num;
|
||||
if ( iss >> num && iss >> (UINT16)node.item )
|
||||
{
|
||||
node.slot = num;
|
||||
|
||||
// additional data is optional
|
||||
if ( iss >> (UINT16)node.ammoitem )
|
||||
{
|
||||
while ( iss >> num )
|
||||
{
|
||||
node.attachments.push_back( num );
|
||||
}
|
||||
}
|
||||
|
||||
vec.push_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void SaveEquipmentTemplate(std::vector<GEAR_NODE> aVec, STR16 aName)
|
||||
{
|
||||
CHAR8 filename[MAX_PATH];
|
||||
|
||||
sprintf(filename, "%s%S.txt", EQUIPMENTTEMPLATE_DIRECTORY, aName);
|
||||
|
||||
// get full path to save file
|
||||
// what we are doing here might seem rather odd. If the file does not exist, we are creating a new file via vfs... and then create a fresh binary file afterwards.
|
||||
// I found this to be the easiest solution for using both vfs pathing and being able to use a std::fstream
|
||||
// If you don't like it, fix it yourself, or make vfs not such a pain to use
|
||||
vfs::Path vfsPath;
|
||||
vfs::COpenWriteFile rfile(filename, true);
|
||||
rfile->_getRealPath(vfsPath);
|
||||
std::string str = vfsPath.to_string();
|
||||
|
||||
const char* filenamewithpath = str.c_str();
|
||||
|
||||
// write
|
||||
std::fstream binary_file(filenamewithpath, std::ios::out);
|
||||
|
||||
for (std::vector<GEAR_NODE>::iterator it = aVec.begin(); it != aVec.end(); ++it)
|
||||
{
|
||||
GEAR_NODE node = (*it);
|
||||
|
||||
binary_file << node;
|
||||
}
|
||||
|
||||
binary_file.close();
|
||||
}
|
||||
|
||||
void WriteEquipmentTemplate(SOLDIERTYPE* pSoldier, STR16 name)
|
||||
{
|
||||
if (pSoldier)
|
||||
{
|
||||
std::vector<GEAR_NODE> vec;
|
||||
|
||||
INT8 invsize = (INT8)pSoldier->inv.size(); // remember inventorysize, so we don't call size() repeatedly
|
||||
|
||||
for (INT8 bLoop = 0; bLoop < invsize; ++bLoop) // ... for all items in our inventory ...
|
||||
{
|
||||
if (pSoldier->inv[bLoop].exists())
|
||||
{
|
||||
// if this item is a gun, note what magazine is currently loaded
|
||||
UINT16 ammoitem = 0;
|
||||
if ( Item[(pSoldier->inv[bLoop]).usItem].usItemClass & IC_GUN )
|
||||
ammoitem = (pSoldier->inv[bLoop])[0]->data.gun.usGunAmmoItem;
|
||||
|
||||
GEAR_NODE node( bLoop, (pSoldier->inv[bLoop]).usItem, ammoitem );
|
||||
|
||||
// add all attachments
|
||||
attachmentList::iterator iterend = (pSoldier->inv[bLoop])[0]->attachments.end( );
|
||||
for ( attachmentList::iterator iter = (pSoldier->inv[bLoop])[0]->attachments.begin( ); iter != iterend; ++iter )
|
||||
{
|
||||
if ( iter->exists( ) )
|
||||
node.attachments.push_back( iter->usItem );
|
||||
}
|
||||
|
||||
vec.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
SaveEquipmentTemplate(vec, name);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> get_all_files_names_within_folder(std::string folder)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
std::string search_path = folder + "/*.*";
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
// read all (real) files in current folder
|
||||
// , delete '!' read other 2 default folder . and ..
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
names.push_back(fd.cFileName);
|
||||
}
|
||||
}
|
||||
while (::FindNextFile(hFind, &fd));
|
||||
|
||||
::FindClose(hFind);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// get a vector of all tilesets that are allowed to be built in this sector (the above filtered by structure construct/deconstruct basically)
|
||||
void GetEquipmentTemplates()
|
||||
{
|
||||
CHAR8 filename[MAX_PATH];
|
||||
|
||||
sprintf(filename, "%sUpdate Gear.txt", EQUIPMENTTEMPLATE_DIRECTORY);
|
||||
|
||||
// get full path to save file
|
||||
// what we are doing here might seem rather odd. If the file does not exist, we are creating a new empty file via vfs
|
||||
// in this case, this is rather useful, as the above file simply updates our gear, which is already neat
|
||||
// I found this to be the easiest solution for using both vfs pathing and being able to use a std::fstream
|
||||
// If you don't like it, fix it yourself, or make vfs not such a pain to use
|
||||
vfs::Path vfsPath;
|
||||
vfs::COpenWriteFile rfile( filename, true );
|
||||
rfile->_getRealPath(vfsPath);
|
||||
|
||||
vfs::Path dir, file;
|
||||
vfsPath.splitLast(dir, file);
|
||||
|
||||
std::string str = dir.to_string();
|
||||
|
||||
const char* filenamewithpath = str.c_str();
|
||||
|
||||
gTemplateVector = get_all_files_names_within_folder( filenamewithpath );
|
||||
}
|
||||
|
||||
void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name )
|
||||
{
|
||||
// make sure the merc is actually in this sector
|
||||
if ( pSoldier )
|
||||
{
|
||||
UINT16 color = FONT_MCOLOR_WHITE;
|
||||
|
||||
// for safety, test again
|
||||
if ( pSoldier->sSectorX != sSelMapX ||
|
||||
pSoldier->sSectorY != sSelMapY ||
|
||||
pSoldier->bSectorZ != iCurrentMapSectorZ )
|
||||
{
|
||||
ScreenMsg( color, MSG_INTERFACE, szGearTemplateText[3], pSoldier->GetName( ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (gTacticalStatus.uiFlags & INCOMBAT || gTacticalStatus.fEnemyInSector) )
|
||||
{
|
||||
ScreenMsg( color, MSG_INTERFACE, szGearTemplateText[1] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<GEAR_NODE> vec = LoadEquipmentTemplate(name);
|
||||
|
||||
UINT16 usReloadSound = 0;
|
||||
BOOLEAN attachmentsound = FALSE;
|
||||
|
||||
// 1. loop over the gear we should pick up and remove mismatching items if we can find a fitting one in the sector
|
||||
for (std::vector<GEAR_NODE>::iterator it = vec.begin(); it != vec.end(); ++it)
|
||||
{
|
||||
GEAR_NODE node = (*it);
|
||||
|
||||
if ( node.slot >= 0 && node.slot < NUM_INV_SLOTS && node.item != NOTHING )
|
||||
{
|
||||
// is there already an item here?
|
||||
if (pSoldier->inv[node.slot].exists())
|
||||
{
|
||||
if ( (pSoldier->inv[node.slot]).usItem != node.item )
|
||||
{
|
||||
// can we get the requested item in the first place?
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( node.item, 0, poolslot, index ) )
|
||||
{
|
||||
// We have to check whether we have any LBE equipped that isn't in the template
|
||||
// in that case we have to dump it and it's contents, otherwise it can block slots that are used in the template
|
||||
if ( node.slot >= VESTPOCKPOS && node.slot <= BPACKPOCKPOS )
|
||||
{
|
||||
std::vector<INT8> pocketKey;
|
||||
GetLBESlots( node.slot, pocketKey );
|
||||
|
||||
// remove everything inside LBE
|
||||
for ( std::vector<INT8>::iterator lbeslotit = pocketKey.begin( ); lbeslotit != pocketKey.end( ); ++lbeslotit )
|
||||
{
|
||||
if ( pSoldier->inv[(*lbeslotit)].exists( ) )
|
||||
{
|
||||
AutoPlaceObjectInInventoryStash( &pSoldier->inv[(*lbeslotit)], pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &pSoldier->inv[(*lbeslotit)] );
|
||||
}
|
||||
}
|
||||
}
|
||||
// if we want to equip a two-handed item in our first hand, also drop whatever we have in the second hand
|
||||
else if ( node.slot == HANDPOS && Item[node.item].twohanded && pSoldier->inv[SECONDHANDPOS].exists( ) )
|
||||
{
|
||||
AutoPlaceObjectInInventoryStash( &pSoldier->inv[SECONDHANDPOS], pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &pSoldier->inv[SECONDHANDPOS] );
|
||||
}
|
||||
// if we are Nails and are ordered to drop our vest, refuse and complain!
|
||||
else if ( node.slot == VESTPOS && HandleNailsVestFetish( pSoldier, node.slot, NOTHING ) )
|
||||
continue;
|
||||
|
||||
// drop item
|
||||
AutoPlaceObjectInInventoryStash( &pSoldier->inv[node.slot], pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &pSoldier->inv[node.slot] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. loop over the gear again and pick up what fits
|
||||
for ( std::vector<GEAR_NODE>::iterator it = vec.begin( ); it != vec.end( ); ++it )
|
||||
{
|
||||
GEAR_NODE node = (*it);
|
||||
|
||||
if ( node.slot >= 0 && node.slot < NUM_INV_SLOTS )
|
||||
{
|
||||
// only if slot is still empty...
|
||||
if ( !pSoldier->inv[node.slot].exists( ) && node.item != NOTHING )
|
||||
{
|
||||
// see if we can find a better object in this sector and put it into our slot
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( node.item, 0, poolslot, index ) )
|
||||
{
|
||||
(pInventoryPoolList[poolslot].object).RemoveObjectAtIndex( index, &gItemPointer );
|
||||
|
||||
if ( !PlaceObject( pSoldier, node.slot, &gItemPointer ) )
|
||||
{
|
||||
ScreenMsg( color, MSG_INTERFACE, szGearTemplateText[4], pSoldier->GetName( ), Item[node.item].szItemName );
|
||||
|
||||
AutoPlaceObjectInInventoryStash( &gItemPointer, pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &gItemPointer );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if this is ammo, we might still be able to create a mag from different-sized mags
|
||||
if ( Item[node.item].usItemClass & IC_AMMO )
|
||||
{
|
||||
UINT16 usMagIndex = Item[node.item].ubClassIndex;
|
||||
|
||||
UINT16 neededammo = Magazine[usMagIndex].ubMagSize;
|
||||
|
||||
if ( neededammo > 0 )
|
||||
{
|
||||
UINT32 poolslot = 0;
|
||||
if ( GetFittingAmmo_InventoryPool( Magazine[usMagIndex].ubCalibre, Magazine[usMagIndex].ubAmmoType, poolslot ) )
|
||||
{
|
||||
UINT32 takeammo = min( neededammo, pInventoryPoolList[poolslot].object[pInventoryPoolList[poolslot].object.ubNumberOfObjects - 1]->data.ubShotsLeft );
|
||||
|
||||
pInventoryPoolList[poolslot].object[pInventoryPoolList[poolslot].object.ubNumberOfObjects - 1]->data.ubShotsLeft -= takeammo;
|
||||
|
||||
if ( !pInventoryPoolList[poolslot].object[pInventoryPoolList[poolslot].object.ubNumberOfObjects - 1]->data.ubShotsLeft )
|
||||
{
|
||||
pInventoryPoolList[poolslot].object.RemoveObjectAtIndex( pInventoryPoolList[poolslot].object.ubNumberOfObjects - 1 );
|
||||
}
|
||||
|
||||
CreateAmmo( node.item, &gItemPointer, takeammo );
|
||||
|
||||
if ( !PlaceObject( pSoldier, node.slot, &gItemPointer ) )
|
||||
{
|
||||
ScreenMsg( color, MSG_INTERFACE, szGearTemplateText[4], pSoldier->GetName( ), Item[node.item].szItemName );
|
||||
|
||||
AutoPlaceObjectInInventoryStash( &gItemPointer, pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &gItemPointer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if ( !pSoldier->inv[node.slot].exists( ) )
|
||||
//ScreenMsg( color, MSG_INTERFACE, L"%s found no %s to equip.", pSoldier->GetName( ), Item[node.item].szItemName );
|
||||
}
|
||||
}
|
||||
|
||||
// if this slot is a LBE slot, we need to add attachments here. Otherwise we add the attachments after we fail to pick up other items as their LBE slots won't exist
|
||||
if ( pSoldier->inv[node.slot].exists() && node.slot >= VESTPOCKPOS && node.slot <= BPACKPOCKPOS )
|
||||
{
|
||||
// try to add attachments if nod entry fits the item, or if the node item is NOTHING (essentially a wildcard for this)
|
||||
if ( !node.attachments.empty( ) && (pSoldier->inv[node.slot]).usItem == node.item || NOTHING == node.item )
|
||||
{
|
||||
OBJECTTYPE* pObj = &(pSoldier->inv[node.slot]);
|
||||
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
{
|
||||
for ( std::vector<UINT16>::iterator attit = node.attachments.begin( ); attit != node.attachments.end( ); ++attit )
|
||||
{
|
||||
UINT16 item_attachment = (*attit);
|
||||
|
||||
// only apply attachments if they don't require any checks!
|
||||
INT32 bAttachInfoIndex = GetAttachmentInfoIndex( item_attachment );
|
||||
|
||||
if ( bAttachInfoIndex < 0 || AttachmentInfo[bAttachInfoIndex].bAttachmentSkillCheck == NO_CHECK )
|
||||
{
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( item_attachment, 0, poolslot, index ) )
|
||||
{
|
||||
(pInventoryPoolList[poolslot].object).RemoveObjectAtIndex( index, &gItemPointer );
|
||||
|
||||
BOOLEAN isAttachedNow = pObj->AttachObject( pSoldier, &gItemPointer, FALSE, i ); //do the actual attaching
|
||||
|
||||
if ( !isAttachedNow )
|
||||
{
|
||||
attachmentsound = TRUE;
|
||||
|
||||
//ScreenMsg( color, MSG_INTERFACE, L"%s could not attach %s to %s", pSoldier->GetName( ), Item[item_attachment].szItemName, Item[pObj->usItem].szItemName );
|
||||
|
||||
AutoPlaceObjectInInventoryStash( &gItemPointer, pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &gItemPointer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. loop over all slots (not just those of the gear vector), improve, merge and fill stacks
|
||||
for ( int slot = HELMETPOS; slot < NUM_INV_SLOTS; ++slot )
|
||||
{
|
||||
if (pSoldier->inv[slot].exists())
|
||||
{
|
||||
OBJECTTYPE* pObj = &(pSoldier->inv[slot]);
|
||||
|
||||
if ( Item[pObj->usItem].usItemClass & (IC_KIT | IC_MEDKIT) && pObj->ubNumberOfObjects > 1 )
|
||||
{
|
||||
CleanUpStack( pObj, pObj );
|
||||
}
|
||||
|
||||
// if this is ammo, try merging mags first before replacing them, the not-full mag being the visible one
|
||||
// by doing this we won't have so many used magazines lying around
|
||||
if ( (Item[pObj->usItem].usItemClass & IC_AMMO) && pObj->ubNumberOfObjects > 1 )
|
||||
{
|
||||
UINT16 usMagIndex = Item[pObj->usItem].ubClassIndex;
|
||||
UINT16 magsize = Magazine[usMagIndex].ubMagSize;
|
||||
|
||||
if ( magsize )
|
||||
{
|
||||
UINT32 ammocount = 0;
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
ammocount += (*pObj)[i]->data.ubShotsLeft;
|
||||
|
||||
UINT8 fullmags = ammocount / magsize;
|
||||
|
||||
UINT16 leftover = ammocount - fullmags * magsize;
|
||||
|
||||
UINT8 totalmags = fullmags + (leftover > 0 ? 1 : 0);
|
||||
|
||||
if ( totalmags < pObj->ubNumberOfObjects )
|
||||
pObj->RemoveObjectsFromStack( pObj->ubNumberOfObjects - totalmags );
|
||||
|
||||
for ( INT16 i = 0; i < totalmags; ++i )
|
||||
(*pObj)[i]->data.ubShotsLeft = magsize;
|
||||
|
||||
if ( leftover > 0 )
|
||||
(*pObj)[0]->data.ubShotsLeft = leftover;
|
||||
}
|
||||
}
|
||||
|
||||
// for every object in the stack, try to find a better improvement
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
{
|
||||
// see if we can find a better object in this sector and put it into our slot
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( (*pObj)[i]->data.objectStatus < 100 && GetBetterObject_InventoryPool( pObj->usItem, (*pObj)[i]->data.objectStatus, poolslot, index ) )
|
||||
{
|
||||
// WARNING! The correct way of doing this would be to exchange both objects
|
||||
// we are not doing this here on purpose, as we want to save time
|
||||
// instead, we switch status and a few other properties
|
||||
// Only do this if you know what you are doing - in the wrong location, we could do odd things to global pointers. Consider yourself warned!
|
||||
|
||||
// tmp data
|
||||
INT16 objectStatus = (*pObj)[i]->data.objectStatus;
|
||||
INT8 bTrap = (*pObj)[i]->data.bTrap;
|
||||
UINT8 fUsed = (*pObj)[i]->data.fUsed;
|
||||
UINT8 ubImprintID = (*pObj)[i]->data.ubImprintID;
|
||||
FLOAT bTemperature = (*pObj)[i]->data.bTemperature;
|
||||
UINT8 ubDirection = (*pObj)[i]->data.ubDirection;
|
||||
UINT32 ubWireNetworkFlag = (*pObj)[i]->data.ubWireNetworkFlag;
|
||||
INT8 bDefuseFrequency = (*pObj)[i]->data.bDefuseFrequency;
|
||||
INT16 sRepairThreshold = (*pObj)[i]->data.sRepairThreshold;
|
||||
UINT64 sObjectFlag = (*pObj)[i]->data.sObjectFlag;
|
||||
|
||||
// set data on our object
|
||||
(*pObj)[i]->data.objectStatus = (pInventoryPoolList[poolslot].object)[index]->data.objectStatus;
|
||||
(*pObj)[i]->data.bTrap = (pInventoryPoolList[poolslot].object)[index]->data.bTrap;
|
||||
(*pObj)[i]->data.fUsed = (pInventoryPoolList[poolslot].object)[index]->data.fUsed;
|
||||
(*pObj)[i]->data.ubImprintID = (pInventoryPoolList[poolslot].object)[index]->data.ubImprintID;
|
||||
(*pObj)[i]->data.bTemperature = (pInventoryPoolList[poolslot].object)[index]->data.bTemperature;
|
||||
(*pObj)[i]->data.ubDirection = (pInventoryPoolList[poolslot].object)[index]->data.ubDirection;
|
||||
(*pObj)[i]->data.ubWireNetworkFlag = (pInventoryPoolList[poolslot].object)[index]->data.ubWireNetworkFlag;
|
||||
(*pObj)[i]->data.bDefuseFrequency = (pInventoryPoolList[poolslot].object)[index]->data.bDefuseFrequency;
|
||||
(*pObj)[i]->data.sRepairThreshold = (pInventoryPoolList[poolslot].object)[index]->data.sRepairThreshold;
|
||||
(*pObj)[i]->data.sObjectFlag = (pInventoryPoolList[poolslot].object)[index]->data.sObjectFlag;
|
||||
|
||||
// set data on world object
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.objectStatus = objectStatus;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.bTrap = bTrap;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.fUsed = fUsed;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.ubImprintID = ubImprintID;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.bTemperature = bTemperature;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.ubDirection = ubDirection;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.ubWireNetworkFlag = ubWireNetworkFlag;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.bDefuseFrequency = bDefuseFrequency;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.sRepairThreshold = sRepairThreshold;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.sObjectFlag = sObjectFlag;
|
||||
}
|
||||
}
|
||||
|
||||
// pick up new items from the sector and put them on the stack
|
||||
UINT8 ubSlotLimit = ItemSlotLimit(pObj, slot, pSoldier, FALSE);
|
||||
|
||||
while (pObj->ubNumberOfObjects < ubSlotLimit)
|
||||
{
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( pObj->usItem, 0, poolslot, index ) )
|
||||
{
|
||||
(pInventoryPoolList[poolslot].object).RemoveObjectAtIndex( index, &gItemPointer );
|
||||
|
||||
if ( !TryToStackInSlot( pSoldier, &gItemPointer, slot ) )
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// try to improve attachments, too
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
{
|
||||
for ( attachmentList::iterator iter = (*pObj)[i]->attachments.begin(); iter != (*pObj)[i]->attachments.end(); ++iter )
|
||||
{
|
||||
if ( iter->exists() )
|
||||
{
|
||||
// see if we can find a better object in this sector and put it into our slot
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( (*iter)[0]->data.objectStatus < 100 && GetBetterObject_InventoryPool( iter->usItem, (*iter)[0]->data.objectStatus, poolslot, index ) )
|
||||
{
|
||||
// WARNING! The correct way of doing this would be to exchange both objects
|
||||
// we are not doing this here on purpose, as we want to save time
|
||||
// instead, we switch status and a few other properties
|
||||
// Only do this if you know what you are doing - in the wrong location, we could do odd things to global pointers. Consider yourself warned!
|
||||
|
||||
// tmp data
|
||||
INT16 objectStatus = (*iter)[0]->data.objectStatus;
|
||||
INT8 bTrap = (*iter)[0]->data.bTrap;
|
||||
UINT8 fUsed = (*iter)[0]->data.fUsed;
|
||||
UINT8 ubImprintID = (*iter)[0]->data.ubImprintID;
|
||||
FLOAT bTemperature = (*iter)[0]->data.bTemperature;
|
||||
UINT8 ubDirection = (*iter)[0]->data.ubDirection;
|
||||
UINT32 ubWireNetworkFlag = (*iter)[0]->data.ubWireNetworkFlag;
|
||||
INT8 bDefuseFrequency = (*iter)[0]->data.bDefuseFrequency;
|
||||
INT16 sRepairThreshold = (*iter)[0]->data.sRepairThreshold;
|
||||
UINT64 sObjectFlag = (*iter)[0]->data.sObjectFlag;
|
||||
|
||||
// set data on our object
|
||||
(*iter)[0]->data.objectStatus = (pInventoryPoolList[poolslot].object)[index]->data.objectStatus;
|
||||
(*iter)[0]->data.bTrap = (pInventoryPoolList[poolslot].object)[index]->data.bTrap;
|
||||
(*iter)[0]->data.fUsed = (pInventoryPoolList[poolslot].object)[index]->data.fUsed;
|
||||
(*iter)[0]->data.ubImprintID = (pInventoryPoolList[poolslot].object)[index]->data.ubImprintID;
|
||||
(*iter)[0]->data.bTemperature = (pInventoryPoolList[poolslot].object)[index]->data.bTemperature;
|
||||
(*iter)[0]->data.ubDirection = (pInventoryPoolList[poolslot].object)[index]->data.ubDirection;
|
||||
(*iter)[0]->data.ubWireNetworkFlag = (pInventoryPoolList[poolslot].object)[index]->data.ubWireNetworkFlag;
|
||||
(*iter)[0]->data.bDefuseFrequency = (pInventoryPoolList[poolslot].object)[index]->data.bDefuseFrequency;
|
||||
(*iter)[0]->data.sRepairThreshold = (pInventoryPoolList[poolslot].object)[index]->data.sRepairThreshold;
|
||||
(*iter)[0]->data.sObjectFlag = (pInventoryPoolList[poolslot].object)[index]->data.sObjectFlag;
|
||||
|
||||
// set data on world object
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.objectStatus = objectStatus;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.bTrap = bTrap;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.fUsed = fUsed;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.ubImprintID = ubImprintID;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.bTemperature = bTemperature;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.ubDirection = ubDirection;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.ubWireNetworkFlag = ubWireNetworkFlag;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.bDefuseFrequency = bDefuseFrequency;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.sRepairThreshold = sRepairThreshold;
|
||||
(pInventoryPoolList[poolslot].object)[index]->data.sObjectFlag = sObjectFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. add attachments. If an attachment cannot be attached - for example because a different one is blocking it - tell us so
|
||||
for ( std::vector<GEAR_NODE>::iterator it = vec.begin( ); it != vec.end( ); ++it )
|
||||
{
|
||||
GEAR_NODE node = (*it);
|
||||
|
||||
// try to add attachments if nod entry fits the item, or if the node item is NOTHING (essentially a wildcard for this)
|
||||
if ( node.slot >= 0 && node.slot < NUM_INV_SLOTS &&
|
||||
(node.slot < VESTPOCKPOS || node.slot > BPACKPOCKPOS) && // we already did that for LBE slots though, no need to repeat
|
||||
!node.attachments.empty( ) && pSoldier->inv[node.slot].exists( ) &&
|
||||
((pSoldier->inv[node.slot]).usItem == node.item || NOTHING == node.item) )
|
||||
{
|
||||
OBJECTTYPE* pObj = &(pSoldier->inv[node.slot]);
|
||||
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
{
|
||||
for ( std::vector<UINT16>::iterator attit = node.attachments.begin( ); attit != node.attachments.end( ); ++attit )
|
||||
{
|
||||
UINT16 item_attachment = (*attit);
|
||||
|
||||
// only apply attachments if they don't require any checks!
|
||||
INT32 bAttachInfoIndex = GetAttachmentInfoIndex( item_attachment );
|
||||
|
||||
if ( bAttachInfoIndex < 0 || AttachmentInfo[bAttachInfoIndex].bAttachmentSkillCheck == NO_CHECK )
|
||||
{
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( item_attachment, 0, poolslot, index ) )
|
||||
{
|
||||
(pInventoryPoolList[poolslot].object).RemoveObjectAtIndex( index, &gItemPointer );
|
||||
|
||||
BOOLEAN isAttachedNow = pObj->AttachObject( pSoldier, &gItemPointer, FALSE, i ); //do the actual attaching
|
||||
|
||||
if ( !isAttachedNow )
|
||||
{
|
||||
attachmentsound = TRUE;
|
||||
|
||||
//ScreenMsg( color, MSG_INTERFACE, L"%s could not attach %s to %s", pSoldier->GetName( ), Item[item_attachment].szItemName, Item[pObj->usItem].szItemName );
|
||||
|
||||
AutoPlaceObjectInInventoryStash( &gItemPointer, pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &gItemPointer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. reload guns, fill mags
|
||||
for ( int slot = HELMETPOS; slot < NUM_INV_SLOTS; ++slot )
|
||||
{
|
||||
if ( pSoldier->inv[slot].exists( ) )
|
||||
{
|
||||
if ( Item[(pSoldier->inv[slot]).usItem].usItemClass & (IC_KIT | IC_MEDKIT) )
|
||||
{
|
||||
UINT32 poolslot = 0;
|
||||
UINT8 index = 0;
|
||||
if ( GetBetterObject_InventoryPool( (pSoldier->inv[slot]).usItem, 0, poolslot, index ) )
|
||||
{
|
||||
DistributeStatus( &(pInventoryPoolList[poolslot].object), &(pSoldier->inv[slot]), 100);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (Item[(pSoldier->inv[slot]).usItem].usItemClass & (IC_GUN | IC_AMMO)))
|
||||
{
|
||||
OBJECTTYPE* pObj = &(pSoldier->inv[slot]);
|
||||
|
||||
for ( INT16 i = 0; i < pObj->ubNumberOfObjects; ++i )
|
||||
{
|
||||
UINT16 ammoitem = (pSoldier->inv[slot]).usItem;
|
||||
|
||||
if ( (Item[(pSoldier->inv[slot]).usItem].usItemClass & IC_GUN) )
|
||||
{
|
||||
UINT8 calibre = Weapon[pObj->usItem].ubCalibre;
|
||||
UINT16 magsize = GetMagSize( pObj, i );
|
||||
|
||||
ammoitem = (*pObj)[i]->data.gun.usGunAmmoItem;
|
||||
for ( std::vector<GEAR_NODE>::iterator it = vec.begin( ); it != vec.end( ); ++it )
|
||||
{
|
||||
if ( (*it).slot == slot && (*it).item == pObj->usItem )
|
||||
{
|
||||
ammoitem = (*it).ammoitem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we somehow don't have a valid ammoitem (for example, if the gun was empty), find one
|
||||
if ( !ammoitem )
|
||||
ammoitem = DefaultMagazine( pObj->usItem );
|
||||
|
||||
UINT16 usMagIndex = Item[ammoitem].ubClassIndex;
|
||||
|
||||
// safety check: if the calibre or mag size doesn't fit, get a better mag
|
||||
if ( calibre != Magazine[usMagIndex].ubCalibre || magsize != Magazine[usMagIndex].ubMagSize )
|
||||
{
|
||||
ammoitem = FindReplacementMagazine( calibre, magsize, Magazine[usMagIndex].ubAmmoType );
|
||||
usMagIndex = Item[ammoitem].ubClassIndex;
|
||||
}
|
||||
|
||||
// if the requested ammo isn't the only currently loaded, take that one out
|
||||
if ( (*pObj)[i]->data.gun.usGunAmmoItem != ammoitem && (*pObj)[i]->data.gun.usGunAmmoItem != NOTHING && ammoitem != NOTHING )
|
||||
{
|
||||
CreateAmmo( (*pObj)[i]->data.gun.usGunAmmoItem, &gItemPointer, (*pObj)[i]->data.gun.ubGunShotsLeft );
|
||||
|
||||
AutoPlaceObjectInInventoryStash( &gItemPointer, pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
DeleteObj( &gItemPointer );
|
||||
|
||||
(*pObj)[i]->data.gun.usGunAmmoItem = NOTHING;
|
||||
(*pObj)[i]->data.gun.ubGunShotsLeft = 0;
|
||||
(*pObj)[i]->data.gun.ubGunAmmoType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UINT16 usMagIndex = Item[ammoitem].ubClassIndex;
|
||||
|
||||
UINT16 neededammo = Magazine[usMagIndex].ubMagSize - (*pObj)[i]->data.ubShotsLeft;
|
||||
if ( (Item[(pSoldier->inv[slot]).usItem].usItemClass & IC_GUN) )
|
||||
neededammo = Magazine[usMagIndex].ubMagSize - (*pObj)[i]->data.gun.ubGunShotsLeft;
|
||||
|
||||
while ( neededammo > 0 )
|
||||
{
|
||||
UINT32 poolslot = 0;
|
||||
if ( GetFittingAmmo_InventoryPool( Magazine[usMagIndex].ubCalibre, Magazine[usMagIndex].ubAmmoType, poolslot ) )
|
||||
{
|
||||
for ( INT16 j = pInventoryPoolList[poolslot].object.ubNumberOfObjects - 1; j >= 0; --j )
|
||||
{
|
||||
UINT32 takeammo = min( neededammo, pInventoryPoolList[poolslot].object[j]->data.ubShotsLeft );
|
||||
|
||||
neededammo -= takeammo;
|
||||
|
||||
pInventoryPoolList[poolslot].object[j]->data.ubShotsLeft -= takeammo;
|
||||
|
||||
if ( (Item[(pSoldier->inv[slot]).usItem].usItemClass & IC_GUN) )
|
||||
{
|
||||
(*pObj)[i]->data.gun.usGunAmmoItem = ammoitem;
|
||||
(*pObj)[i]->data.gun.ubGunAmmoType = Magazine[usMagIndex].ubAmmoType;
|
||||
(*pObj)[i]->data.gun.ubGunShotsLeft += takeammo;
|
||||
|
||||
usReloadSound = Weapon[pObj->usItem].sReloadSound;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*pObj)[i]->data.ubShotsLeft += takeammo;
|
||||
}
|
||||
|
||||
if ( !pInventoryPoolList[poolslot].object[j]->data.ubShotsLeft )
|
||||
{
|
||||
pInventoryPoolList[poolslot].object.RemoveObjectAtIndex( j );
|
||||
}
|
||||
|
||||
if ( !neededammo )
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ( (Item[(pSoldier->inv[slot]).usItem].usItemClass & IC_GUN) )
|
||||
neededammo = Magazine[usMagIndex].ubMagSize - (*pObj)[i]->data.gun.ubGunShotsLeft;
|
||||
else
|
||||
neededammo = Magazine[usMagIndex].ubMagSize - (*pObj)[i]->data.ubShotsLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Immersion, let's play a reload sound
|
||||
if ( usReloadSound != 0 )
|
||||
PlayJA2Sample( usReloadSound, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
||||
else if ( attachmentsound )
|
||||
PlayJA2Sample( ATTACH_TO_GUN, RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
||||
|
||||
// 6. redraw inventory
|
||||
fTeamPanelDirty = TRUE;
|
||||
fMapPanelDirty = TRUE;
|
||||
fInterfacePanelDirty = DIRTYLEVEL2;
|
||||
fCharacterInfoPanelDirty = TRUE;
|
||||
|
||||
// refresh ammo button in description box if it exists
|
||||
if ( giItemDescAmmoButton > -1 )
|
||||
MarkAButtonDirty( giItemDescAmmoButton ); // Required for tactical screen
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,15 @@
|
||||
#include "worldman.h"
|
||||
#include "Queen Command.h"
|
||||
#include "strategicmap.h"
|
||||
#include "Map Screen Interface.h"
|
||||
|
||||
extern void GetEquipmentTemplates( );
|
||||
|
||||
std::vector<std::string> gTemplateVector;
|
||||
|
||||
extern void ReadEquipmentTable( SOLDIERTYPE* pSoldier, std::string name );
|
||||
|
||||
extern INT8 bSelectedInfoChar;
|
||||
|
||||
// sevenfm: need this for correct calculation of traits menu position
|
||||
extern INT16 gsInterfaceLevel;
|
||||
@@ -740,3 +749,141 @@ void TraitsMenu( INT32 usMapPos )
|
||||
|
||||
gTraitSelection.Setup(0);
|
||||
}
|
||||
|
||||
/////////////////////////////// Trait Selection ////////////////////////////////////////////
|
||||
EquipmentSelection gEquipmentSelection;
|
||||
|
||||
void Wrapper_Function_EquipmentSelection(UINT32 aVal) { gEquipmentSelection.Functions(aVal); }
|
||||
void Wrapper_Setup_EquipmentSelection(UINT32 aVal) { gEquipmentSelection.Setup(aVal); }
|
||||
void Wrapper_Cancel_EquipmentSelection(UINT32 aVal) { gEquipmentSelection.Cancel(); }
|
||||
/////////////////////////////// Trait Selection ////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////// Trait Selection ////////////////////////////////////////////
|
||||
UINT32 gEquipmentSelectionFirstEntryShown = 0;
|
||||
UINT32 gEquipmentSelectionLastEntryShown = 0;
|
||||
UINT32 gEquipmentSelectionMaxEntriesShown = 0;
|
||||
|
||||
void
|
||||
EquipmentSelection::Setup(UINT32 aVal)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
SetupPopup("EquipmentSelection");
|
||||
|
||||
INT16 sX = 261 + 406 + xResOffset + 30;
|
||||
INT16 sY = 0 + 10 + yResOffset + 30;
|
||||
|
||||
if ( sX < 0 ) sX = 0;
|
||||
if ( sY < 0 ) sY = 0;
|
||||
|
||||
usTraitMenuPosX = sX + 30;
|
||||
usTraitMenuPosY = sY;
|
||||
|
||||
if ( (usTraitMenuPosX + 400) > SCREEN_WIDTH )
|
||||
usTraitMenuPosX = SCREEN_WIDTH - 400;
|
||||
|
||||
if ( (usTraitMenuPosY + 130) > SCREEN_HEIGHT )
|
||||
usTraitMenuPosY = SCREEN_HEIGHT - 190;
|
||||
|
||||
POPUP_OPTION *pOption;
|
||||
|
||||
CHAR16 pStr[300];
|
||||
|
||||
// create entries for the sub-menus for each trait
|
||||
GetEquipmentTemplates();
|
||||
|
||||
// we limit the maximum number of entries shown at once - too many entries could theoretically cause the button system to freak out
|
||||
gEquipmentSelectionMaxEntriesShown = min(40, max( 0, (SCREEN_HEIGHT - 150 - usTraitMenuPosY) / 12 ) );
|
||||
|
||||
gEquipmentSelectionLastEntryShown = min( gEquipmentSelectionFirstEntryShown + gEquipmentSelectionMaxEntriesShown, gTemplateVector.size( ) );
|
||||
|
||||
if ( gEquipmentSelectionLastEntryShown < gEquipmentSelectionMaxEntriesShown )
|
||||
gEquipmentSelectionFirstEntryShown = 0;
|
||||
else
|
||||
gEquipmentSelectionFirstEntryShown = gEquipmentSelectionLastEntryShown - gEquipmentSelectionMaxEntriesShown;
|
||||
|
||||
UINT32 cnt = gEquipmentSelectionFirstEntryShown;
|
||||
for ( UINT32 i = gEquipmentSelectionFirstEntryShown; i < gEquipmentSelectionLastEntryShown; ++i )
|
||||
{
|
||||
//std::string str8 = (*it);
|
||||
std::string str8 = gTemplateVector[i];
|
||||
|
||||
std::size_t found = str8.find_last_of( "." );
|
||||
|
||||
std::string str82 = str8.substr( 0, found );
|
||||
|
||||
const char* coca = str82.c_str( );
|
||||
|
||||
CHAR16 tmpchar[256];
|
||||
|
||||
int nChars = MultiByteToWideChar( CP_ACP, 0, coca, -1, NULL, 0 );
|
||||
MultiByteToWideChar( CP_UTF8, 0, coca, -1, tmpchar, nChars );
|
||||
|
||||
pOption = new POPUP_OPTION( &std::wstring( tmpchar ), new popupCallbackFunction<void, UINT32>( &Wrapper_Function_EquipmentSelection, i ) );
|
||||
|
||||
pOption->color_foreground = FONT_GREEN;
|
||||
|
||||
GetPopup()->addOption(*pOption);
|
||||
}
|
||||
|
||||
// 'more' option (moves down list)
|
||||
if ( gEquipmentSelectionMaxEntriesShown < gTemplateVector.size( ) )
|
||||
{
|
||||
swprintf( pStr, pSkillMenuStrings[SKILLMENU_MORE] );
|
||||
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Function_EquipmentSelection, 99999 ) );
|
||||
GetPopup( )->addOption( *pOption );
|
||||
}
|
||||
|
||||
// cancel option
|
||||
swprintf(pStr, pSkillMenuStrings[SKILLMENU_CANCEL]);
|
||||
pOption = new POPUP_OPTION( &std::wstring( pStr ), new popupCallbackFunction<void, UINT32>( &Wrapper_Function_EquipmentSelection, 99998 ) );
|
||||
GetPopup()->addOption(*pOption);
|
||||
|
||||
SetPos(usTraitMenuPosX, usTraitMenuPosY);
|
||||
}
|
||||
|
||||
void
|
||||
EquipmentSelection::Functions(UINT32 aVal)
|
||||
{
|
||||
// this special value allows to 'scroll down'
|
||||
if ( aVal == 99999 )
|
||||
{
|
||||
gEquipmentSelectionFirstEntryShown += gEquipmentSelectionMaxEntriesShown;
|
||||
|
||||
if ( gEquipmentSelectionFirstEntryShown >= gTemplateVector.size( ) )
|
||||
gEquipmentSelectionFirstEntryShown = 0;
|
||||
|
||||
Cancel( );
|
||||
|
||||
EquipmentListMenu();
|
||||
}
|
||||
else if ( aVal == 99998 )
|
||||
{
|
||||
gEquipmentSelectionFirstEntryShown = 0;
|
||||
|
||||
Cancel( );
|
||||
}
|
||||
else if ( aVal < gTemplateVector.size( ) )
|
||||
{
|
||||
SOLDIERTYPE* pSoldier = &Menptr[gCharactersList[bSelectedInfoChar].usSolID];
|
||||
if ( pSoldier )
|
||||
{
|
||||
std::string name = gTemplateVector[aVal];
|
||||
|
||||
ReadEquipmentTable( pSoldier, name );
|
||||
}
|
||||
|
||||
// Note that we don't close menu - this way we don't have to open it every time we want to apply a template
|
||||
}
|
||||
}
|
||||
/////////////////////////////// Trait Selection ////////////////////////////////////////////
|
||||
|
||||
void EquipmentListMenu()
|
||||
{
|
||||
gEquipmentSelection.Setup(0);
|
||||
}
|
||||
|
||||
void EquipmentListMenuCancel()
|
||||
{
|
||||
gEquipmentSelection.Cancel();
|
||||
}
|
||||
|
||||
+15
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
/**
|
||||
* @brief A basic class for popup menus
|
||||
* Use this to create mensu calling other menus, each having various sub-options
|
||||
* Use this to create menus calling other menus, each having various sub-options
|
||||
* I tried to make this as orderly as possible. It's ugly, but much more clean than the first solution, which was a hardcoded mess.
|
||||
* You will, however, still need wrapper functions (we use callbacks on member functions), see Implementation.
|
||||
*/
|
||||
@@ -162,4 +162,18 @@ private:
|
||||
*/
|
||||
void TraitsMenu( INT32 usMapPos );
|
||||
|
||||
// C17
|
||||
// not skill-related, but while we're here...
|
||||
class EquipmentSelection : public SkillMenuItem
|
||||
{
|
||||
public:
|
||||
EquipmentSelection() {}
|
||||
|
||||
void Setup(UINT32 aVal);
|
||||
void Functions(UINT32 aVal);
|
||||
};
|
||||
|
||||
void EquipmentListMenu();
|
||||
void EquipmentListMenuCancel();
|
||||
|
||||
#endif
|
||||
@@ -167,6 +167,7 @@ enum
|
||||
SKILLMENU_CANCEL,
|
||||
SKILLMENU_X_MILITIA,
|
||||
SKILLMENU_ALL_MILITIA,
|
||||
SKILLMENU_MORE,
|
||||
};
|
||||
|
||||
extern STR16 pSkillMenuStrings[]; //Flugente
|
||||
@@ -2992,6 +2993,9 @@ extern STR16 szInteractiveActionText[];
|
||||
|
||||
extern STR16 szLaptopStatText[];
|
||||
|
||||
// Flugente: gear templates
|
||||
extern STR16 szGearTemplateText[];
|
||||
|
||||
#define TACTICAL_INVENTORY_DIALOG_NUM 16
|
||||
#define TACTICAL_COVER_DIALOG_NUM 16
|
||||
|
||||
|
||||
+11
-1
@@ -2837,8 +2837,9 @@ STR16 pSkillMenuStrings[] =
|
||||
L"其他队伍",
|
||||
L"取消",
|
||||
L"%d 民兵",
|
||||
|
||||
L"所有民兵",
|
||||
|
||||
L"More",
|
||||
};
|
||||
|
||||
STR16 pSnitchMenuStrings[] =
|
||||
@@ -11251,6 +11252,15 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
// WANNE: Some Chinese specific strings that needs to be in unicode!
|
||||
STR16 ChineseSpecString1 = L"%%"; //defined in _ChineseText.cpp as this file is already unicode
|
||||
STR16 ChineseSpecString2 = L"*%3d%%%%"; //defined in _ChineseText.cpp as this file is already unicode
|
||||
|
||||
+11
-1
@@ -2836,8 +2836,9 @@ STR16 pSkillMenuStrings[] = // TODO.Translate
|
||||
L"Other Squads",
|
||||
L"Cancel",
|
||||
L"%d Militia",
|
||||
|
||||
L"All Militia",
|
||||
|
||||
L"More",
|
||||
};
|
||||
|
||||
// TODO.Translate
|
||||
@@ -11269,4 +11270,13 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //DUTCH
|
||||
|
||||
+11
-1
@@ -2833,8 +2833,9 @@ STR16 pSkillMenuStrings[] =
|
||||
L"Other Squads",
|
||||
L"Cancel",
|
||||
L"%d Militia",
|
||||
|
||||
L"All Militia",
|
||||
|
||||
L"More",
|
||||
};
|
||||
|
||||
STR16 pSnitchMenuStrings[] =
|
||||
@@ -11250,4 +11251,13 @@ STR16 szLaptopStatText[] =
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] =
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //ENGLISH
|
||||
|
||||
+12
-2
@@ -2839,14 +2839,15 @@ STR16 pTraitSkillsDenialStrings[] =
|
||||
L" - aimed gun\n",
|
||||
};
|
||||
|
||||
STR16 pSkillMenuStrings[] = // TODO.Translate
|
||||
STR16 pSkillMenuStrings[] =
|
||||
{
|
||||
L"Milice",
|
||||
L"Autre escouade",
|
||||
L"Annuler",
|
||||
L"%d miliciens",
|
||||
|
||||
L"Tous",
|
||||
|
||||
L"More", // TODO.Translate
|
||||
};
|
||||
|
||||
STR16 pSnitchMenuStrings[] =
|
||||
@@ -11251,4 +11252,13 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //FRENCH
|
||||
|
||||
+11
-1
@@ -2840,8 +2840,9 @@ STR16 pSkillMenuStrings[] = // TODO.Translate
|
||||
L"Other Squads",
|
||||
L"Cancel",
|
||||
L"%d Militia",
|
||||
|
||||
L"All Militia",
|
||||
|
||||
L"More", // TODO.Translate
|
||||
};
|
||||
|
||||
// TODO.Translate
|
||||
@@ -11081,4 +11082,13 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //GERMAN
|
||||
|
||||
+11
-1
@@ -2831,8 +2831,9 @@ STR16 pSkillMenuStrings[] = // TODO.Translate
|
||||
L"Other Squads",
|
||||
L"Cancel",
|
||||
L"%d Militia",
|
||||
|
||||
L"All Militia",
|
||||
|
||||
L"More", // TODO.Translate
|
||||
};
|
||||
|
||||
// TODO.Translate
|
||||
@@ -11260,4 +11261,13 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //ITALIAN
|
||||
|
||||
+11
-1
@@ -2843,8 +2843,9 @@ STR16 pSkillMenuStrings[] = // TODO.Translate
|
||||
L"Other Squads",
|
||||
L"Cancel",
|
||||
L"%d Militia",
|
||||
|
||||
L"All Militia",
|
||||
|
||||
L"More", // TODO.Translate
|
||||
};
|
||||
|
||||
STR16 pSnitchMenuStrings[] =
|
||||
@@ -11273,4 +11274,13 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //POLISH
|
||||
|
||||
+11
-1
@@ -2837,8 +2837,9 @@ STR16 pSkillMenuStrings[] =
|
||||
L"Другие отряды",
|
||||
L"Отмена",
|
||||
L"%d ополченцев",
|
||||
|
||||
L"Все ополченцы",
|
||||
|
||||
L"More", // TODO.Translate
|
||||
};
|
||||
|
||||
STR16 pSnitchMenuStrings[] =
|
||||
@@ -11254,4 +11255,13 @@ STR16 szLaptopStatText[] = // TODO.Translate
|
||||
L"Recruit approach",
|
||||
};
|
||||
|
||||
STR16 szGearTemplateText[] = // TODO.Translate
|
||||
{
|
||||
L"Enter Template Name",
|
||||
L"Not possible during combat.",
|
||||
L"Selected mercenary is not in this sector.",
|
||||
L"%s is not in that sector.",
|
||||
L"%s could not equip %s.",
|
||||
};
|
||||
|
||||
#endif //RUSSIAN
|
||||
|
||||
Reference in New Issue
Block a user