Files
source/Strategic/Map Screen Interface Map Inventory.cpp
T
Wanne 7ca53fadc7 *** MERGED source code from development trunk revision 4890 up to latest current revision 5105 ***
Development Trunk (now obsolete): https://ja2svn.dyndns.org/source/ja2/branches/Wanne/JA2%201.13%20MP
A detailed list of all the features (changes) is visible in the history log of the development trunk:

INFO: There will be no further development in the development source trunk, so is obsolete from now on!

This commit contains the following features (bugfixes are not listed):

- New Feature: Show merc ranks in Strategy Screen before merc name
o Toggle on/off in the ingame options screen
o For each experience level (0-10) there are defined rank names in the language specific text files
o Additional language text that is not translated yet is marked with // TODO.Translate

- New Feature: Faster Bobby Ray Shipments
o This feature is selectable in the ja2_options.ini
o When activated Bobby Ray shipments will be really fast
-> Overnight Express: 5 - 7 hours
-> Air Service: 10, 12 or 14 hours
-> Standard Service: 15, 18 or 21 hours
o In a multiplayer game, this feature is disabled (because shipment arrive immediately in the destination sector)

- New Feature: AP cost for manipulating the merc inventory
o This feature is selectable in the start new game screen
o For example, putting a weapon from hand in the backpack costs APs
o The AP costs are defined in the APBPConstants.ini
o In a multiplayer game, this feature is disabled

- New Feature: Added possibility to set individual Gear Kit names
o Set individual names in the optional new tag <mGearKitName> inside the <GEARKIT> root element (File: TableData\MercStartingGear.xml)

- New Feature: Externalized the maximum purchase amount (JA2 vanilla: 10) for Bobby Rays purchases per shipment
o Define the max. amount in the ja2_options.ini: BOBBY_RAY_MAX_PURCHASE_AMOUNT, Range: 10 - 100)
o Nice scrolling bars to scroll through all the purchases

- New Feature: Now it is possible to walk on "water" tiles or handle those tiles like "normal" tiles 
o (instead of showing the swimming animation and counting the APs for swimming), when the soldier is located on the second level (level > 0)

- New Feature: Externalized AIM Veterans laptop site
o Add maximum of 4 pages
o Add  new AIM to veterans page, and remove AIM from veterans page.
o New XML file: OldAIMArchive.xml (language specific XML files: *.OldAIMArchive.xml)

- New Feature: Added possibility to choose from 254 IMP faces
o Modified IMPPortraits.xml
o Added new GameDir folder "IMPFaces" which contains the IMP face portraits
o Moved IMP faces in the new "IMPFaces" folder

- New Feature: ARSP - All Resolution Support Project
o See here: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=298698&page=1
o Support any kind of screen resolution. This works by choosing the matching full supported resolution (640x480, 800x600, 1024x768) and then centering the graphics
o See ja2.ini for defining the screen resolution

- New Feature: AI Turn Speed Up (FF-MOD)
o see here: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=298699#Post298699
o When this feature is activated it allows fast enemy turns
o New entry in ja2.ini to enable this feature: HIGHSPEED_TIMER = TRUE
o Turn on/off auto fast turns in ingame options
o New ja2_options.ini settings for fine tuning: [Clock Settings] ini block

- New Feature: "Lock" / "Release" mouse cursor in tactical windowed mode, so the mouse can stay within window boundary
o This is very helpful for doing scrolling with the mouse (by moving the mouse to the window edge) in windowed mode
o You can toggle on/off the feature by pressing CTRL + Z. It is also possible to press CTRL + Y. So the user can decide which fits better :)
o Whenever you toggle on/off a screen message appears on the tactical log to notify the player

- New Feature: Weapon overheating
o Basically, every shot fired from a gun increases its temperature. On higher temperatures, the gun jams more frequently
o On/off toggle in the ingame options
o Graphical thermometer indication on the weapon picture
o New ja2_options.ini section with a few options, Section: [Tactical Weapon Overheating Settings]
o XML changes (New Tags)
--> AmmoTypes.xml: <temperatureModificator>
--> Items.xml: <barrel>, <usOverheatingCooldownFactor>
--> Weapons.xml: <usOverheatingJamThreshold>, <usOverheatingDamageThreshold>, <usOverheatingSingleShotTemperature>
o Added a few barells to Items.xml (end of the file)
o more infos: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=301059&page=1

- New Feature: Resting weapons on a surfaces
o You can now rest your weapon on crates, low walls, rocks, debris, open windows etc. while you are crouched. Resting will give yu the superior gun handling modifiers from PRONE position.
o A little 'A' on your gun indicates if you are resting it or not.
o Both settings can be turned on and off in Ja2_Options.ini under 'Tactical Gameplay Settings'

- New Feature: Externalized option on whether mercs can exit sector using grid exit in turn based mode
o new ja2_options.ini property: GRID_EXIT_IN_TURNBASED
o This ini setting does not affect leaving sectors on map edges

- Rework/Update: Ammo boxes and Ammo crates
o Ammo crate items added for remaining calibers.  Tweaked prices to correspond to magazines, tweaked capacities and weights to be reasonable (~800 or less).
o Shift-R reload now looks at both boxes and crates in sector items and merc's inventory to reload, and tops off magazines in inventory as well.  Only possible outside of combat.
o Ctrl-Shift-A still creates crates as per usual, with some fixes to ensure all ammo is caught on the first press.
o Shift-A now creates ammo boxes in the same loop.  They mostly behave like crates, but fit in mercs inventories.
o Ammo boxes are available to purchase at BR and tony, sam, etc.  Individual magazines/drums/etc are no longer available.
o Removed ammo crate xml tag.  Added ubMagType tag to Magazines array.  This allows us to differentiate between magazines, bullets, boxes and crates.
o Changed ammo filtering in BR's to display boxes appropriately.  Added back the "Mag:" display (changed text to "Size:")
o Added ja2set.dat.xml file (WF map version in WF maps folder) to be used instead of ja2set.dat file (ja2.ini setting added) For now, if you want to play vanilla instead, just change the setting in the ini (see comments in file).
o Added P4-P9Items image files (up to 5k images each) and tileslots.  1.13 core items will continue to use Guns and P1-P3Items for the foreseeable future.  P4-P9 can be used by customizers/modders to avoid conflicts with Guns/P1-P3 items.  TODO: Need to discuss a strategy for this in the forums.
o Added in Ambient/0.bad and 32.bad to avoid an exception in the code.
o Updated the XML Editor
o Standardized the text on all the ammo items.

- New Multiplayer Feature: Sharing same FOV (field of view) in a coop/team-dm (for friendly teams) game
o You will also see enemies, that your teammate sees

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5108 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2012-03-23 18:46:54 +00:00

2713 lines
84 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "GameSettings.h"
#else
#include "Map Screen Interface Map Inventory.h"
#include "Render Dirty.h"
#include "vobject.h"
#include "Utilities.h"
#include "WCheck.h"
#include "sysutil.h"
#include "Map Screen Interface Border.h"
#include "Map Screen Interface.h"
#include "Map Screen Interface Map.h"
#include "Items.h"
#include "Interface Items.h"
#include "Cursor Control.h"
#include "Interface Utils.h"
#include "Text.h"
#include "Font Control.h"
#include "strategicmap.h"
#include "Tactical Save.h"
#include "Overhead.h"
#include "english.h"
#include "Multi Language Graphic Utils.h"
#include "GameSettings.h"
#include "Radar Screen.h"
#include "message.h"
#include "weapons.h"
#include "finances.h"
#include "Game Clock.h"
#include "Sound Control.h"
#include "interface panels.h"
#include "wordwrap.h"
#include "Soldier macros.h"
#endif
#include "ShopKeeper Interface.h"
#include "ArmsDealerInvInit.h"
#include <algorithm>
#include "InterfaceItemImages.h"
#include "SaveLoadGame.h"//dnl ch51 081009
#include "Map Information.h"//dnl ch51 091009
#include "Interface Items.h"
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
class SOLDIERTYPE;
//dnl ch51 081009
UINT8 gInventoryPoolIndex = '0';
std::vector<WORLDITEM> pInventoryPoolListQ[INVPOOLLISTNUM];
INT32 iCurrentInventoryPoolPageQ[INVPOOLLISTNUM]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
INT32 iLastInventoryPoolPageQ[INVPOOLLISTNUM]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
extern BOOLEAN SaveWorldItemsToTempItemFile( INT16 sMapX, INT16 sMapY, INT8 bMapZ, UINT32 uiNumberOfItems, WORLDITEM* pData );
#define MAP_INV_X_OFFSET (((SCREEN_WIDTH - 261) - 380) / 2)
// status bar colors
#define DESC_STATUS_BAR FROMRGB( 201, 172, 133 )
#define DESC_STATUS_BAR_SHADOW FROMRGB( 140, 136, 119 )
// page display positions
#define MAP_INVENTORY_POOL_PAGE_X (MAP_INV_X_OFFSET + 506)
#define MAP_INVENTORY_POOL_PAGE_Y (SCREEN_HEIGHT - 121 - 23) //336
#define MAP_INVENTORY_POOL_PAGE_WIDTH 46
#define MAP_INVENTORY_POOL_PAGE_HEIGHT 13
// the number of items
#define MAP_INVENTORY_POOL_NUMBER_X (MAP_INV_X_OFFSET + 436)
#define MAP_INVENTORY_POOL_NUMBER_WIDTH 40
// location
#define MAP_INVENTORY_POOL_LOC_X (MAP_INV_X_OFFSET + 326)
#define MAP_INVENTORY_POOL_LOC_WIDTH 40
// delay for flash of item
#define DELAY_FOR_HIGHLIGHT_ITEM_FLASH 200
// inventory slot font
#define MAP_IVEN_FONT SMALLCOMPFONT
// the position of the background graphic
#define INVEN_POOL_X 261
#define INVEN_POOL_Y 0
// inventory Graphic Offset X and y
#define MAP_INVENTORY_POOL_SLOT_OFFSET_X 2
#define MAP_INVENTORY_POOL_SLOT_OFFSET_Y 5
// height of map inventory pool bar
#define ITEMDESC_ITEM_STATUS_HEIGHT_INV_POOL 20
#define ITEMDESC_ITEM_STATUS_WIDTH_INV_POOL 2
// map bar offsets
#define ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_X 5
#define ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_Y 22
// inventory pool slot positions and sizes
//#define MAP_INVENTORY_POOL_SLOT_START_X 271
//#define MAP_INVENTORY_POOL_SLOT_START_Y 36
#define MAP_INVEN_SLOT_WIDTH 65
#define MAP_INVEN_SPACE_BTWN_SLOTS 72
#define MAP_INVEN_SLOT_HEIGHT 32
#define MAP_INVEN_SLOT_IMAGE_HEIGHT 24
// Number of inventory slots in 1024x768
#define MAP_INVENTORY_POOL_MAX_SLOTS 170
INT32 MAP_INV_SLOT_COLS; // Number of vertical slots
INT32 MAP_INVENTORY_POOL_SLOT_COUNT;
INT32 MAP_INVENTORY_POOL_SLOT_START_X;
INT32 MAP_INVENTORY_POOL_SLOT_START_Y;
// the current highlighted item
INT32 iCurrentlyHighLightedItem = -1;
BOOLEAN fFlashHighLightInventoryItemOnradarMap = FALSE;
// whether we are showing the inventory pool graphic
BOOLEAN fShowMapInventoryPool = FALSE;
// the v-object index value for the background
UINT32 guiMapInventoryPoolBackground;
// inventory pool list
std::vector<WORLDITEM> pInventoryPoolList;
// current page of inventory
INT32 iCurrentInventoryPoolPage = 0;
INT32 iLastInventoryPoolPage = 0;
INT32 sObjectSourceGridNo = 0;
INT8 sObjectSourseSoldierID = -1;
// number of unseen items in sector
UINT32 uiNumberOfUnSeenItems = 0;
// the inventory slots
//MOUSE_REGION MapInventoryPoolSlots[ MAP_INVENTORY_POOL_SLOT_COUNT ];
MOUSE_REGION MapInventoryPoolSlots[ MAP_INVENTORY_POOL_MAX_SLOTS ];
MOUSE_REGION MapInventoryPoolMask;
//BOOLEAN fMapInventoryItemCompatable[ MAP_INVENTORY_POOL_SLOT_COUNT ];
BOOLEAN fMapInventoryItemCompatable[ MAP_INVENTORY_POOL_MAX_SLOTS ];
BOOLEAN fChangedInventorySlots = FALSE;
// the unseen items list...have to save this
WORLDITEM *pUnSeenItems = NULL;
// save list to write to temp file
WORLDITEM *pSaveList = NULL;
INT32 giFlashHighlightedItemBaseTime = 0;
INT32 giCompatibleItemBaseTime = 0;
// the buttons and images
UINT32 guiMapInvenButtonImage[ 3 ];
UINT32 guiMapInvenButton[ 3 ];
BOOLEAN gfCheckForCursorOverMapSectorInventoryItem = FALSE;
extern int PLAYER_INFO_Y;
extern int INV_REGION_Y;
extern BOOLEAN fShowInventoryFlag;
extern BOOLEAN fMapScreenBottomDirty;
extern BOOLEAN ReduceStringLength( STR16 pString, UINT32 uiWidthToFitIn, UINT32 uiFont );
extern OBJECTTYPE gItemPointer;
extern OBJECTTYPE * gpItemPointer;
// outside vidieo objects for cursor
extern UINT32 guiExternVo;
extern UINT16 gusExternVoSubIndex;
extern MOUSE_REGION gMPanelRegion;
// map inventory callback
void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason );
void MapInvenPoolSlotsMove( MOUSE_REGION * pRegion, INT32 iReason );
void CreateMapInventoryPoolSlots( void );
void DestroyMapInventoryPoolSlots( void );
void CreateMapInventoryButtons( void );
void DestroyMapInventoryButtons( void );
void DestroyStash( void );
void BuildStashForSelectedSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ );
void BeginInventoryPoolPtr( OBJECTTYPE *pInventorySlot );
BOOLEAN PlaceObjectInInventoryStash( OBJECTTYPE *pInventorySlot, OBJECTTYPE *pItemPtr );
void RenderItemsForCurrentPageOfInventoryPool( void );
BOOLEAN RenderItemInPoolSlot( INT32 iCurrentSlot, INT32 iFirstSlotOnPage );
void UpdateHelpTextForInvnentoryStashSlots( void );
void MapInventoryPoolPrevBtn( GUI_BUTTON *btn, INT32 reason );
void MapInventoryPoolNextBtn( GUI_BUTTON *btn, INT32 reason );
void DisplayPagesForMapInventoryPool( void );
void DrawNumberOfIventoryPoolItems( void );
void CreateMapInventoryPoolDoneButton( void );
void DestroyInventoryPoolDoneButton( void );
void MapInventoryPoolDoneBtn( GUI_BUTTON *btn, INT32 reason );
void DisplayCurrentSector( void );
void ResizeInventoryList( void );
void ClearUpTempUnSeenList( void );
void SaveSeenAndUnseenItems( void );
void DrawTextOnMapInventoryBackground( void );
void DrawTextOnSectorInventory( void );
INT32 GetTotalNumberOfItemsInSectorStash( void );
void HandleMapSectorInventory( void );
void ResetMapSectorInventoryPoolHighLights( void );
void ReBuildWorldItemStashForLoadedSector( INT32 iNumberSeenItems, INT32 iNumberUnSeenItems, WORLDITEM *pSeenItemsList, WORLDITEM *pUnSeenItemsList );
BOOLEAN IsMapScreenWorldItemVisibleInMapInventory( WORLDITEM *pWorldItem );
BOOLEAN IsMapScreenWorldItemInvisibleInMapInventory( WORLDITEM *pWorldItem );
void CheckGridNoOfItemsInMapScreenMapInventory();
INT32 MapScreenSectorInventoryCompare( const void *pNum1, const void *pNum2);
void SortSectorInventory( std::vector<WORLDITEM>& pInventory, UINT32 uiSizeOfArray );
BOOLEAN CanPlayerUseSectorInventory( SOLDIERTYPE *pSelectedSoldier );
extern void MAPEndItemPointer( );
extern BOOLEAN GetCurrentBattleSectorXYZAndReturnTRUEIfThereIsABattle( INT16 *psSectorX, INT16 *psSectorY, INT16 *psSectorZ );
extern BOOLEAN MAPInternalInitItemDescriptionBox( OBJECTTYPE *pObject, UINT8 ubStatusIndex, SOLDIERTYPE *pSoldier );
void DeleteAllItemsInInventoryPool();
void DeleteItemsOfType( UINT16 usItemType );
INT32 SellItem( OBJECTTYPE& object, BOOLEAN useModifier = TRUE );
// load the background panel graphics for inventory
BOOLEAN LoadInventoryPoolGraphic( void )
{
VOBJECT_DESC VObjectDesc;
// load the file
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
if (iResolution >= _640x480 && iResolution < _800x600)
{
MAP_INV_SLOT_COLS = 8;
MAP_INVENTORY_POOL_SLOT_COUNT = 40;
MAP_INVENTORY_POOL_SLOT_START_X = 269;
MAP_INVENTORY_POOL_SLOT_START_Y = 51;
sprintf( VObjectDesc.ImageFile, "INTERFACE\\sector_inventory.sti" );
}
else if (iResolution < _1024x768)
{
MAP_INV_SLOT_COLS = 11;
MAP_INVENTORY_POOL_SLOT_COUNT = 77;
MAP_INVENTORY_POOL_SLOT_START_X = (SCREEN_WIDTH - INTERFACE_WIDTH)/2 + 278;
MAP_INVENTORY_POOL_SLOT_START_Y = 62;
sprintf( VObjectDesc.ImageFile, "INTERFACE\\sector_inventory_800x600.sti" );
}
else
{
MAP_INV_SLOT_COLS = 17;
MAP_INVENTORY_POOL_SLOT_COUNT = MAP_INVENTORY_POOL_MAX_SLOTS;
MAP_INVENTORY_POOL_SLOT_START_X = (SCREEN_WIDTH - INTERFACE_WIDTH)/2 + 282;
MAP_INVENTORY_POOL_SLOT_START_Y = 50;
sprintf( VObjectDesc.ImageFile, "INTERFACE\\sector_inventory_1024x768.sti" );
}
// add to V-object index
CHECKF(AddVideoObject(&VObjectDesc, &guiMapInventoryPoolBackground));
return( TRUE );
}
// remove background panel graphics for inventory
void RemoveInventoryPoolGraphic( void )
{
// remove from v-object index
if( guiMapInventoryPoolBackground )
{
DeleteVideoObjectFromIndex( guiMapInventoryPoolBackground );
guiMapInventoryPoolBackground = 0;
}
return;
}
// blit the background panel for the inventory
void BlitInventoryPoolGraphic( void )
{
HVOBJECT hHandle;
// blit inventory pool graphic to the screen
GetVideoObject(&hHandle, guiMapInventoryPoolBackground);
BltVideoObject( guiSAVEBUFFER , hHandle, 0,(SCREEN_WIDTH - INTERFACE_WIDTH)/2 + INVEN_POOL_X, INVEN_POOL_Y , VO_BLT_SRCTRANSPARENCY,NULL );
// resize list
ResizeInventoryList( );
// now the items
RenderItemsForCurrentPageOfInventoryPool( );
// now update help text
UpdateHelpTextForInvnentoryStashSlots( );
// show which page and last page
DisplayPagesForMapInventoryPool( );
// draw number of items in current inventory
DrawNumberOfIventoryPoolItems( );
// display current sector inventory pool is at
DisplayCurrentSector( );
DrawTextOnMapInventoryBackground( );
// re render buttons
MarkButtonsDirty( );
// which buttons will be active and which ones not
HandleButtonStatesWhileMapInventoryActive( );
// Invalidate
RestoreExternBackgroundRect(xResOffset + MAP_BORDER_X, MAP_BORDER_Y, SCREEN_WIDTH - MAP_BORDER_X - 2 * xResOffset, SCREEN_HEIGHT - 121 - 2 * yResOffset);
return;
}
void RenderItemsForCurrentPageOfInventoryPool( void )
{
INT32 iCounter = 0;
// go through list of items on this page and place graphics to screen
for( iCounter = 0; iCounter < MAP_INVENTORY_POOL_SLOT_COUNT ; iCounter++ )
{
RenderItemInPoolSlot( iCounter, ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) );
}
return;
}
BOOLEAN RenderItemInPoolSlot( INT32 iCurrentSlot, INT32 iFirstSlotOnPage )
{
// render item in this slot of the list
INT16 sCenX, sCenY, usWidth, usHeight, sX, sY;
HVOBJECT hHandle;
ETRLEObject *pTrav;
CHAR16 sString[ 64 ];
INT16 sWidth = 0, sHeight = 0;
INT16 sOutLine = 0;
BOOLEAN fOutLine = FALSE;
// check if anything there
if( pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.exists() == false )
{
//return ( FALSE );
}
GetVideoObject( &hHandle, GetInterfaceGraphicForItem( &(Item[ pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.usItem ] ) ) );
UINT16 usGraphicNum = g_bUsePngItemImages ? 0 : Item[pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.usItem ].ubGraphicNum;
pTrav = &( hHandle->pETRLEObject[ usGraphicNum ] );
usHeight = (UINT16)pTrav->usHeight;
usWidth = (UINT16)pTrav->usWidth;
// set sx and sy
sX = ( INT16 )( MAP_INVENTORY_POOL_SLOT_OFFSET_X + MAP_INVENTORY_POOL_SLOT_START_X + ( ( MAP_INVEN_SPACE_BTWN_SLOTS ) * ( iCurrentSlot / MAP_INV_SLOT_COLS ) ) );
sY = ( INT16 )( MAP_INVENTORY_POOL_SLOT_START_Y + ( ( MAP_INVEN_SLOT_HEIGHT ) * ( iCurrentSlot % ( MAP_INV_SLOT_COLS ) ) ) );
// CENTER IN SLOT!
sCenX = sX + ( abs( MAP_INVEN_SPACE_BTWN_SLOTS - usWidth ) / 2 ) - pTrav->sOffsetX;
sCenY = sY + ( abs( MAP_INVEN_SLOT_HEIGHT - 5 - usHeight ) / 2 ) - pTrav->sOffsetY;
if( fMapInventoryItemCompatable[ iCurrentSlot ] )
{
sOutLine = Get16BPPColor( FROMRGB( 255, 255, 255 ) );
fOutLine = TRUE;
}
else
{
sOutLine = us16BPPItemCyclePlacedItemColors[ 0 ];
fOutLine = FALSE;
}
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
if(UsingNewInventorySystem() == true && gpItemPointer != NULL)
{
int itemSlotLimit = ItemSlotLimit(gpItemPointer, STACK_SIZE_LIMIT);
RenderPocketItemCapacity( guiSAVEBUFFER, itemSlotLimit, STACK_SIZE_LIMIT, 0, &pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object, (sX + 7), sY );
}
INVRenderItem( guiSAVEBUFFER, NULL, &(pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object),
(INT16)(sX + 7), sY, 60, 25, DIRTYLEVEL2, NULL, 0, fOutLine, sOutLine );//67
SetFontDestBuffer( FRAME_BUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
if( pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.exists() == false )
{
return ( FALSE );
}
// now blit this object in the box
//BltVideoObjectOutlineFromIndex( guiSAVEBUFFER, GetInterfaceGraphicForItem( &(Item[ pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.usItem ]) ),
// Item[ pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.usItem ].ubGraphicNum,
// sCenX, sCenY,
//sOutLine, TRUE );
// now draw bar for condition
// Display ststus
DrawItemUIBarEx( &( pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object ), 0,
(INT16)( ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_X + MAP_INVENTORY_POOL_SLOT_START_X + ( ( MAP_INVEN_SPACE_BTWN_SLOTS ) * ( iCurrentSlot / MAP_INV_SLOT_COLS ) ) ),
( INT16 )( ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_Y + MAP_INVENTORY_POOL_SLOT_START_Y + ( ( MAP_INVEN_SLOT_HEIGHT ) * ( iCurrentSlot % ( MAP_INV_SLOT_COLS ) ) ) )
, ITEMDESC_ITEM_STATUS_WIDTH_INV_POOL, ITEMDESC_ITEM_STATUS_HEIGHT_INV_POOL, Get16BPPColor( DESC_STATUS_BAR ), Get16BPPColor( DESC_STATUS_BAR_SHADOW ), TRUE, guiSAVEBUFFER );
//
// if the item is not reachable, or if the selected merc is not in the current sector
//
if( !( pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].usFlags & WORLD_ITEM_REACHABLE ) ||
!(( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].sSectorX == sSelMapX ) &&
( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].sSectorY == sSelMapY ) &&
( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].bSectorZ == iCurrentMapSectorZ )
) )
{
//Shade the item, but only if it is an active item!
if ( pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.exists() == true) {
DrawHatchOnInventory( guiSAVEBUFFER, sX, sY, MAP_INVEN_SLOT_WIDTH, MAP_INVEN_SLOT_IMAGE_HEIGHT );
}
}
// the name
wcscpy( sString, ShortItemNames[ pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.usItem ] );
if( StringPixLength( sString, MAP_IVEN_FONT ) >= ( MAP_INVEN_SLOT_WIDTH ) )
{
ReduceStringLength( sString, ( INT16 )( MAP_INVEN_SLOT_WIDTH - StringPixLength( L" ...", MAP_IVEN_FONT ) ), MAP_IVEN_FONT );
}
FindFontCenterCoordinates( (INT16)( 4 + MAP_INVENTORY_POOL_SLOT_START_X + ( ( MAP_INVEN_SPACE_BTWN_SLOTS ) * ( iCurrentSlot / MAP_INV_SLOT_COLS ) ) ),
0, MAP_INVEN_SLOT_WIDTH, 0,
sString, MAP_IVEN_FONT,
&sWidth, &sHeight );
SetFontDestBuffer( guiSAVEBUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
SetFont( MAP_IVEN_FONT );
SetFontForeground( FONT_WHITE );
SetFontBackground( FONT_BLACK );
mprintf( sWidth,
( INT16 )( 3 + ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_Y + MAP_INVENTORY_POOL_SLOT_START_Y + ( ( MAP_INVEN_SLOT_HEIGHT ) * ( iCurrentSlot % ( MAP_INV_SLOT_COLS ) ) ) )
, sString );
/*
if( pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.ubNumberOfObjects > 1 )
{
swprintf( sString, L"x%d", pInventoryPoolList[ iCurrentSlot + iFirstSlotOnPage ].object.ubNumberOfObjects );
// find font right coord
FindFontRightCoordinates( ( INT16 )( ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_X + MAP_INVENTORY_POOL_SLOT_START_X - 1 + ( ( MAP_INVEN_SPACE_BTWN_SLOTS ) * ( iCurrentSlot / MAP_INV_SLOT_COLS ) ) ),0, MAP_INVEN_SPACE_BTWN_SLOTS - 10, 0, sString, MAP_IVEN_FONT, &sX, &sY );
sY = ( INT16 )( 3 + ITEMDESC_ITEM_STATUS_INV_POOL_OFFSET_Y + MAP_INVENTORY_POOL_SLOT_START_Y + ( ( MAP_INVEN_SLOT_HEIGHT ) * ( iCurrentSlot % ( MAP_INV_SLOT_COLS ) ) ) ) - 7;
// print string
mprintf( sX, sY, sString );
}
*/
SetFontDestBuffer( FRAME_BUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
return( TRUE );
}
void UpdateHelpTextForInvnentoryStashSlots( void )
{
CHAR16 pStr[ 512 ];
INT32 iCounter = 0;
INT32 iFirstSlotOnPage = ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT );
// run through list of items in slots and update help text for mouse regions
for( iCounter = 0; iCounter < MAP_INVENTORY_POOL_SLOT_COUNT; iCounter++ )
{
if( pInventoryPoolList[ iCounter + iFirstSlotOnPage ].object.exists() == true )
{
GetHelpTextForItem( pStr , &( pInventoryPoolList[ iCounter + iFirstSlotOnPage ].object ), NULL );
SetRegionFastHelpText( &(MapInventoryPoolSlots[ iCounter ] ), pStr );
/*
// set text for current item
if( pInventoryPoolList[ iCounter + iFirstSlotOnPage ].object.usItem == MONEY )
{
swprintf( pStr, L"$%ld", pInventoryPoolList[ iCounter + iFirstSlotOnPage ].object[0]->data.money.uiMoneyAmount );
SetRegionFastHelpText( &(MapInventoryPoolSlots[ iCounter ]), pStr );
}
else
{
SetRegionFastHelpText( &(MapInventoryPoolSlots[ iCounter ]), ItemNames[ pInventoryPoolList[ iCounter + iFirstSlotOnPage ].object.usItem ] );
}
*/
}
else
{
//OK, for each item, set dirty text if applicable!
SetRegionFastHelpText( &(MapInventoryPoolSlots[ iCounter ]), L"" );
}
}
return;
}
// create and remove buttons for inventory
void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen )
{
static BOOLEAN fCreated = FALSE;
/* player can leave items underground, no?
if( iCurrentMapSectorZ )
{
fShowMapInventoryPool = FALSE;
}
*/
if( ( fShowMapInventoryPool ) && ( fCreated == FALSE ) )
{
if( ( gWorldSectorX == sSelMapX ) && ( gWorldSectorY == sSelMapY ) && ( gbWorldSectorZ == iCurrentMapSectorZ ) )
{
// handle all reachable before save
HandleAllReachAbleItemsInTheSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
}
// destroy buttons for map border
DeleteMapBorderButtons( );
// delete map level markers regions
DeleteMouseRegionsForLevelMarkers( );
fCreated = TRUE;
// also create the inventory slot
CreateMapInventoryPoolSlots( );
// create buttons
CreateMapInventoryButtons( );
// build stash
BuildStashForSelectedSector( sSelMapX, sSelMapY, ( INT16 )( iCurrentMapSectorZ ) );
CreateMapInventoryPoolDoneButton( );
fMapPanelDirty = TRUE;
fMapScreenBottomDirty = TRUE;
}
else if( ( fShowMapInventoryPool == FALSE ) && ( fCreated == TRUE ) )
{
if(gGameExternalOptions.fEnableInventoryPoolQ)//dnl ch51 081009
SwitchToInventoryPoolQ(0);
// check fi we are in fact leaving mapscreen
if( fExitFromMapScreen == FALSE )
{
// recreate mapborder buttons
CreateButtonsForMapBorder( );
// recreate map level markers regions
CreateMouseRegionsForLevelMarkers( );
}
fCreated = FALSE;
// destroy the map inventory slots
DestroyMapInventoryPoolSlots( );
// destroy map inventory buttons
DestroyMapInventoryButtons( );
DestroyInventoryPoolDoneButton( );
// clear up unseen list
ClearUpTempUnSeenList( );
// now save results
SaveSeenAndUnseenItems( );
DestroyStash( );
fMapPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
// HEADROCK HAM 3.6: Yet again, make sure to refresh the bottom panel on closing.
fMapScreenBottomDirty = TRUE;
//CHRISL: close stack popup and item description windows
DeleteItemStackPopup();
if ( gfInItemDescBox )
{
DeleteItemDescriptionBox();
}
//DEF: added to remove the 'item blip' from staying on the radar map
iCurrentlyHighLightedItem = -1;
// re render radar map
RenderRadarScreen( );
}
// do our handling here
HandleMapSectorInventory( );
}
void CancelSectorInventoryDisplayIfOn( BOOLEAN fExitFromMapScreen )
{
if ( fShowMapInventoryPool )
{
// get rid of sector inventory mode & buttons
fShowMapInventoryPool = FALSE;
CreateDestroyMapInventoryPoolButtons( fExitFromMapScreen );
}
}
void ClearUpTempUnSeenList( void )
{
// save these items and all the others
if( pUnSeenItems == NULL )
{
return;
}
// build the list based on this
pSaveList = pUnSeenItems;
pUnSeenItems = NULL;
return;
}
void SaveSeenAndUnseenItems( void )
{
WORLDITEM *pSeenItemsList = NULL;
UINT32 iCounter = 0;
INT32 iItemCount = 0;
INT32 iTotalNumberItems = 0;
// allocate space
iTotalNumberItems = GetTotalNumberOfItems( );
// if there are seen items, build a temp world items list of them and save them
if( iTotalNumberItems > 0 )
{
pSeenItemsList = new WORLDITEM[ iTotalNumberItems ];
// copy
for( iCounter = 0; iCounter < pInventoryPoolList.size(); iCounter++ )
{
if( pInventoryPoolList[ iCounter ].object.exists() == true )
{
// copy object stuff
pSeenItemsList[ iItemCount ] = pInventoryPoolList[ iCounter ];
// check if item actually lives at a gridno
// if not, check predicessor, iItemCount is not 0
if( pSeenItemsList[ iItemCount ].sGridNo == 0 )
{
if( iItemCount > 0 )
{
// borrow from predicessor
pSeenItemsList[ iItemCount ].sGridNo = pSeenItemsList[ iItemCount - 1 ].sGridNo;
}
else
{
// get entry grid location
}
}
pSeenItemsList[ iItemCount ].fExists = TRUE;
pSeenItemsList[ iItemCount ].bVisible = TRUE;
iItemCount++;
}
}
}
// if this is the loaded sector handle here
if( ( gWorldSectorX == sSelMapX ) && ( gWorldSectorY == sSelMapY ) && ( gbWorldSectorZ == ( INT8 ) ( iCurrentMapSectorZ ) ) )
{
ReBuildWorldItemStashForLoadedSector( iItemCount, uiNumberOfUnSeenItems, pSeenItemsList, pSaveList );
}
else
{
// now copy over unseen and seen
if( uiNumberOfUnSeenItems > 0 )
{
// over write file and copy unseen
AddWorldItemsToUnLoadedSector( sSelMapX, sSelMapY, ( INT8 )( iCurrentMapSectorZ ), 0, uiNumberOfUnSeenItems, pSaveList, TRUE );
// check if seen items exist too
if( iItemCount > 0 )
{
AddWorldItemsToUnLoadedSector( sSelMapX, sSelMapY, ( INT8 )( iCurrentMapSectorZ ), 0, iItemCount, pSeenItemsList, FALSE );
}
}
else if( iItemCount > 0 )
{
// copy only seen items
AddWorldItemsToUnLoadedSector( sSelMapX, sSelMapY, ( INT8 )( iCurrentMapSectorZ ), 0, iItemCount, pSeenItemsList, TRUE );
}
else
{
// get rid of the file
SaveWorldItemsToTempItemFile( sSelMapX, sSelMapY, ( INT8 )( iCurrentMapSectorZ ), 0, NULL );
return;
}
}
// now clear out seen list
if( pSeenItemsList != NULL )
{
delete[]( pSeenItemsList );
pSeenItemsList = NULL;
}
// clear out unseen list
if( pSaveList != NULL )
{
delete[]( pSaveList );
pSaveList = NULL;
}
uiNumberOfUnSeenItems = 0;
iItemCount = 0;
}
// the screen mask bttn callaback...to disable the inventory and lock out the map itself
void MapInvenPoolScreenMaskCallback(MOUSE_REGION * pRegion, INT32 iReason )
{
if( ( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) )
{
fShowMapInventoryPool = FALSE;
}
return;
}
void CreateMapInventoryPoolSlots( void )
{
INT32 iCounter = 0;
INT16 sX = 0, sY = 0;
INT16 sXA = 0, sYA = 0;
INT16 sULX = 0, sULY = 0;
INT16 sBRX = 0, sBRY = 0;
MSYS_DefineRegion( &MapInventoryPoolMask,
MAP_INVENTORY_POOL_SLOT_START_X, 0, SCREEN_WIDTH - MAP_INVENTORY_POOL_SLOT_START_X, SCREEN_HEIGHT - 120,
MSYS_PRIORITY_HIGH, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, MapInvenPoolScreenMaskCallback);
for( iCounter = 0; iCounter < MAP_INVENTORY_POOL_SLOT_COUNT; iCounter++ )
{
sX = ( iCounter / MAP_INV_SLOT_COLS );
sY = ( iCounter % ( MAP_INV_SLOT_COLS ) );
sXA = sX + 1;
sYA = sY + 1;
sULX = MAP_INVENTORY_POOL_SLOT_START_X + 4;
sULY = MAP_INVENTORY_POOL_SLOT_START_Y + 1;
sULX += ( INT16 ) ( sX * MAP_INVEN_SPACE_BTWN_SLOTS );
sULY += ( INT16 ) ( ( sY * MAP_INVEN_SLOT_HEIGHT ) );
sBRX = ( INT16 ) ( MAP_INVENTORY_POOL_SLOT_START_X + ( sXA * MAP_INVEN_SPACE_BTWN_SLOTS ) );
sBRY = ( INT16 ) ( MAP_INVENTORY_POOL_SLOT_START_Y + ( sYA * MAP_INVEN_SLOT_HEIGHT ) ) - 1;
MSYS_DefineRegion( &MapInventoryPoolSlots[ iCounter ],
sULX, sULY, sBRX, sBRY,
MSYS_PRIORITY_HIGH, MSYS_NO_CURSOR, MapInvenPoolSlotsMove, MapInvenPoolSlots );
MSYS_SetRegionUserData( &MapInventoryPoolSlots[iCounter], 0, iCounter );
}
}
void DestroyMapInventoryPoolSlots( void )
{
INT32 iCounter = 0;
for( iCounter = 0; iCounter < MAP_INVENTORY_POOL_SLOT_COUNT; iCounter++ )
{
MSYS_RemoveRegion( &MapInventoryPoolSlots[ iCounter ] );
}
// remove map inventory mask
MSYS_RemoveRegion( &MapInventoryPoolMask );
}
void MapInvenPoolSlotsMove( MOUSE_REGION * pRegion, INT32 iReason )
{
INT32 iCounter = 0;
iCounter = MSYS_GetRegionUserData( pRegion, 0 );
if( iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
{
iCurrentlyHighLightedItem = iCounter;
fChangedInventorySlots = TRUE;
gfCheckForCursorOverMapSectorInventoryItem = TRUE;
}
else if( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
iCurrentlyHighLightedItem = -1;
fChangedInventorySlots = TRUE;
gfCheckForCursorOverMapSectorInventoryItem = FALSE;
// re render radar map
RenderRadarScreen( );
}
}
void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason )
{
// btn callback handler for assignment screen mask region
INT32 iCounter = 0;
UINT16 usOldItemIndex, usNewItemIndex;
INT32 iOldNumberOfObjects = 0;
INT16 sDistanceFromObject = 0;
SOLDIERTYPE *pSoldier = NULL;
CHAR16 sString[ 128 ];
extern OBJECTTYPE *gpItemDescObject;
iCounter = MSYS_GetRegionUserData( pRegion, 0 );
if( ( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) )
{
if(gGameExternalOptions.fSectorDesc == TRUE)
{
//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;
//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] ))
{
//CHRISL: The old setup had a flaw I didn't consider. if, for some reason, the ItemSlotLimit = 0
// nothing might happen. Now we setup a flag to determine if our cursor is value for the item we're
// clicking on. If it's not valid, we can't do anything so all conditions rely on it being true.
//if(ItemSlotLimit( &twItem->object, STACK_SIZE_LIMIT ) == 1)
if(gpItemPointer == NULL)
fValidPointer = true;
else
{
if(gpItemPointer->usItem == twItem->object.usItem)
fValidPointer = true;
if(ValidAttachment(gpItemPointer->usItem, &(twItem->object)) == TRUE)
fValidPointer = true;
if(ValidAmmoType(twItem->object.usItem, gpItemPointer->usItem) == TRUE)
fValidPointer = true;
}
if(twItem->object.ubNumberOfObjects == 1 && fValidPointer)
{
fShowInventoryFlag = TRUE;
if (InItemDescriptionBox( ))
{
DeleteItemDescriptionBox();
}
MAPInternalInitItemDescriptionBox( &twItem->object, 0, MercPtrs[gCharactersList[bSelectedInfoChar].usSolID] );
}
else if(fValidPointer)
{
InitSectorStackPopup( MercPtrs[gCharactersList[bSelectedInfoChar].usSolID], twItem, iCounter, (SCREEN_WIDTH - INTERFACE_WIDTH)/2, -10, 261, ( SCREEN_HEIGHT - PLAYER_INFO_Y ) );
fTeamPanelDirty=TRUE;
fInterfacePanelDirty = DIRTYLEVEL2;
}
}
}
}
else
{
if ( gpItemPointer == NULL )
{
fShowMapInventoryPool = FALSE;
}
// else do nothing
}
}
else if( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
// check if item in cursor, if so, then swap, and no item in curor, pick up, if item in cursor but not box, put in box
if ( gpItemPointer == NULL )
{
// Return if empty
if ( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object.exists() == false )
return;
// CHRISL: Also return if the item we've clicked on is currently displayed in the item description box
if(InItemDescriptionBox( ) && gpItemDescObject == &pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object)
return;
}
// is this item reachable
if( !( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].usFlags & WORLD_ITEM_REACHABLE ) )
{
if ( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object.exists() == true )
{
// not reachable
DoMapMessageBox( MSG_BOX_BASIC_STYLE, gzLateLocalizedString[38], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
}
// check if selected merc is in this sector, if not, warn them and leave
// valid character?
if( gCharactersList[ bSelectedInfoChar ].fValid == FALSE )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, pMapInventoryErrorString[ 1 ], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
//if( fShowInventoryFlag )
{
// not in sector?
if( ( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].sSectorX != sSelMapX ) ||
( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].sSectorY != sSelMapY ) ||
( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].bSectorZ != iCurrentMapSectorZ ) ||
( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].flags.fBetweenSectors ) )
{
if ( gpItemPointer == NULL )
{
swprintf( sString, pMapInventoryErrorString[ 2 ], Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].name );
}
else
{
swprintf( sString, pMapInventoryErrorString[ 5 ], Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].name );
}
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
}
// If we do not have an item in hand, start moving it
if ( gpItemPointer == NULL )
{
// Return if empty
if ( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object.exists() == false )
return;
// if in battle inform player they will have to do this in tactical
// if( ( ( gTacticalStatus.fEnemyInSector ) ||( ( sSelMapX == gWorldSectorX ) && ( sSelMapY == gWorldSectorY ) && ( iCurrentMapSectorZ == gbWorldSectorZ ) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) ) )
if( !CanPlayerUseSectorInventory( &Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ] ) )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, pMapInventoryErrorString[ 3 ], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
sObjectSourceGridNo = pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].sGridNo;
sObjectSourseSoldierID = pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].soldierID;
// check if this is the loaded sector, if so, then notify player, can't do anything
if( ( sSelMapX == gWorldSectorX )&&( gWorldSectorY == sSelMapY ) &&(gbWorldSectorZ == iCurrentMapSectorZ ) )
{
// notify
pSoldier = &( Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ] );
sDistanceFromObject = PythSpacesAway( sObjectSourceGridNo, pSoldier->sGridNo);
/* if( sDistanceFromObject > MAX_DISTANCE_TO_PICKUP_ITEM )
{
// see for the loaded sector if the merc is cloase enough?
swprintf( sString, pMapInventoryErrorString[ 0 ], Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ].name );
DoMapMessageBox( MSG_BOX_BASIC_STYLE, sString, MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
*/
}
BeginInventoryPoolPtr( &( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object ) );
}
else
{
// if in battle inform player they will have to do this in tactical
// if( ( gTacticalStatus.fEnemyInSector ) ||( ( sSelMapX == gWorldSectorX ) && ( sSelMapY == gWorldSectorY ) && ( iCurrentMapSectorZ == gbWorldSectorZ ) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) )
if( !CanPlayerUseSectorInventory( &Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ] ) )
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, pMapInventoryErrorString[ 4 ], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
usOldItemIndex = pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object.usItem;
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 ) )
{
if(gGameExternalOptions.fEnableInventoryPoolQ)//dnl ch51 091009
{
pInventoryPoolList[(iCurrentInventoryPoolPage*MAP_INVENTORY_POOL_SLOT_COUNT)+iCounter].bVisible = TRUE;
pInventoryPoolList[(iCurrentInventoryPoolPage*MAP_INVENTORY_POOL_SLOT_COUNT)+iCounter].fExists = TRUE;
if(!GridNoOnVisibleWorldTile(sObjectSourceGridNo))
sObjectSourceGridNo = gMapInformation.sCenterGridNo;
}
//CHRISL: Make sure we put the item at the same level as the merc
if(gpItemPointerSoldier->exists() == true)
pInventoryPoolList[(iCurrentInventoryPoolPage*MAP_INVENTORY_POOL_SLOT_COUNT)+iCounter].ubLevel = gpItemPointerSoldier->pathing.bLevel;
// set as reachable and set gridno
pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].usFlags |= WORLD_ITEM_REACHABLE;
// if loaded sector, grab grid no of dropping soldier
//if( ( sSelMapX == gWorldSectorX )&&( gWorldSectorY == sSelMapY ) &&(gbWorldSectorZ == iCurrentMapSectorZ ) )
//{
// nothing here before, then place here
if( iOldNumberOfObjects == 0 )
{
if(TileIsOutOfBounds(sObjectSourceGridNo))
{
pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT;
pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].sGridNo = sObjectSourceGridNo;
}
else
{
pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].sGridNo = sObjectSourceGridNo;
}
if( sObjectSourseSoldierID != -1 )
pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].soldierID = sObjectSourseSoldierID;
}
//}
// Check if it's the same now!
if ( gpItemPointer->exists() == false )
{
MAPEndItemPointer( );
}
else
{
// update ptr
// now set the cursor
guiExternVo = GetInterfaceGraphicForItem( &(Item[ gpItemPointer->usItem ]) );
gusExternVoSubIndex = g_bUsePngItemImages ? 0 : Item[ gpItemPointer->usItem ].ubGraphicNum;
fMapInventoryItem = TRUE;
MSYS_ChangeRegionCursor( &gMPanelRegion , EXTERN_CURSOR );
SetCurrentCursorFromDatabase( EXTERN_CURSOR );
}
/*
if ( fShowInventoryFlag && bSelectedInfoChar >= 0 )
{
ReevaluateItemHatches( MercPtrs[ gCharactersList[ bSelectedInfoChar ].usSolID ], FALSE );
}
*/
}
}
// dirty region, force update
fMapPanelDirty = TRUE;
}
}
void CreateMapInventoryButtons( void )
{
guiMapInvenButtonImage[ 0 ]= LoadButtonImage( "INTERFACE\\map_screen_bottom_arrows.sti" , 10, 1, -1, 3, -1 );
guiMapInvenButton[ 0 ] = QuickCreateButton( guiMapInvenButtonImage[ 0 ], (MAP_INV_X_OFFSET + 559), (SCREEN_HEIGHT - 144 - 2 * yResOffset),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)MapInventoryPoolNextBtn );
guiMapInvenButtonImage[ 1 ]= LoadButtonImage( "INTERFACE\\map_screen_bottom_arrows.sti" ,9, 0, -1, 2, -1 );
guiMapInvenButton[ 1 ] = QuickCreateButton( guiMapInvenButtonImage[ 1 ], (MAP_INV_X_OFFSET + 487), (SCREEN_HEIGHT - 144 - 2 * yResOffset),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)MapInventoryPoolPrevBtn );
// set up fast help text
SetButtonFastHelpText( guiMapInvenButton[ 0 ], pMapScreenInvenButtonHelpText[ 0 ] );
SetButtonFastHelpText( guiMapInvenButton[ 1 ], pMapScreenInvenButtonHelpText[ 1 ] );
//reset the current inventory page to be the first page
iCurrentInventoryPoolPage = 0;
return;
}
void DestroyMapInventoryButtons( void )
{
RemoveButton( guiMapInvenButton[ 0 ] );
RemoveButton( guiMapInvenButton[ 1 ] );
UnloadButtonImage( guiMapInvenButtonImage[ 0 ] );
UnloadButtonImage( guiMapInvenButtonImage[ 1 ] );
return;
}
void BuildStashForSelectedSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ )
{
INT32 iSize = 0;
UINT32 uiItemCount = 0;
UINT32 uiTotalNumberOfItems = 0, uiTotalNumberOfRealItems = 0;
WORLDITEM * pTotalSectorList = NULL;
INT32 iCounter = 0;
UINT32 uiTotalNumberOfSeenItems=0;
// #ifdef _DEBUG
BOOLEAN fReturn = TRUE;
// #endif
// get size of the current stash in sector (count stacks as one item)
iSize = GetSizeOfStashInSector( sMapX, sMapY, sMapZ, TRUE );
// round off .. we want at least 1 free page of space...
iSize = ((iSize / MAP_INVENTORY_POOL_SLOT_COUNT) + 1) * MAP_INVENTORY_POOL_SLOT_COUNT;
// allocate space for list
pInventoryPoolList.clear();
pInventoryPoolList.resize( iSize );
iLastInventoryPoolPage = ( ( iSize - 1 ) / MAP_INVENTORY_POOL_SLOT_COUNT );
uiNumberOfUnSeenItems = 0;
// now laod these items into memory, based on fact if sector is in fact loaded
if( ( sMapX == gWorldSectorX )&&( gWorldSectorY == sMapY ) &&(gbWorldSectorZ == sMapZ ) )
{
// sector loaded, just copy from list
for( iCounter = 0; ( UINT32 )( iCounter ) < guiNumWorldItems; iCounter++ )
{
// check if visible, if so, then copy over object type
// if visible to player, then state fact
/*
if( gWorldItems[ iCounter].bVisible == 1 &&
gWorldItems[ iCounter ].fExists &&
gWorldItems[ iCounter ].object.usItem != SWITCH &&
gWorldItems[ iCounter ].object.bTrap <= 0 )
*/
if( IsMapScreenWorldItemVisibleInMapInventory( &gWorldItems[ iCounter ] ) )
{
// one more item
pInventoryPoolList[ uiItemCount ] = gWorldItems[ iCounter ];
uiItemCount++;
}
}
uiTotalNumberOfSeenItems = uiItemCount;
// now allocate space for all the unseen items
if( guiNumWorldItems > uiItemCount )
{
pUnSeenItems = new WORLDITEM[ guiNumWorldItems - uiItemCount ];
uiItemCount = 0;
// now copy over
for( iCounter = 0; ( UINT32 )iCounter < guiNumWorldItems; iCounter++ )
{
if( IsMapScreenWorldItemInvisibleInMapInventory( &gWorldItems[ iCounter ] ) )
{
// one more item
pUnSeenItems[ uiItemCount ] = gWorldItems[ iCounter ];
uiItemCount++;
}
}
// copy over number of unseen
uiNumberOfUnSeenItems = uiItemCount;
}
}
else
{
// not loaded, load
// get total number, visable and invisible
fReturn = GetNumberOfWorldItemsFromTempItemFile( sMapX, sMapY, ( INT8 )( sMapZ ), &( uiTotalNumberOfItems ), FALSE );
Assert( fReturn );
fReturn = GetNumberOfActiveWorldItemsFromTempFile( sMapX, sMapY, ( INT8 )( sMapZ ), &( uiTotalNumberOfRealItems ) );
Assert( fReturn );
if( uiTotalNumberOfRealItems > 0 )
{
// allocate space for the list
pTotalSectorList = new WORLDITEM[ uiTotalNumberOfItems ];
// now load into mem
LoadWorldItemsFromTempItemFile( sMapX, sMapY, ( INT8 ) ( sMapZ ), pTotalSectorList );
}
// now run through list and
for( iCounter = 0; ( UINT32 )( iCounter )< uiTotalNumberOfRealItems; iCounter++ )
{
// if visible to player, then state fact
/*
if( pTotalSectorList[ iCounter].bVisible == 1 &&
pTotalSectorList[ iCounter].fExists &&
pTotalSectorList[ iCounter].object.usItem != SWITCH &&
pTotalSectorList[ iCounter].object.bTrap <= 0 )
*/
//TEST!! If the item exists, and is NOT VALID, report it
if( pTotalSectorList[ iCounter].fExists && pTotalSectorList[ iCounter].object.usItem > MAXITEMS )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"The %d item in the list is NOT valid. Please send save. DF 1.", iCounter );
}
if( IsMapScreenWorldItemVisibleInMapInventory( &pTotalSectorList[ iCounter] ) )
{
// one more item
pInventoryPoolList[ uiItemCount ] = pTotalSectorList[ iCounter ];
uiItemCount++;
}
}
uiTotalNumberOfSeenItems = uiItemCount;
// now allocate space for all the unseen items
if( uiTotalNumberOfRealItems > uiItemCount )
{
pUnSeenItems = new WORLDITEM[ uiTotalNumberOfRealItems - uiItemCount ];
uiItemCount = 0;
// now copy over
for( iCounter = 0; ( UINT32 )iCounter < uiTotalNumberOfItems; iCounter++ )
{
if( IsMapScreenWorldItemInvisibleInMapInventory( &pTotalSectorList[ iCounter] ) )
{
// one more item
pUnSeenItems[ uiItemCount ] = pTotalSectorList[ iCounter ];
uiItemCount++;
}
}
// copy over number of unseen
uiNumberOfUnSeenItems = uiItemCount;
}
// if anything was alloced, then get rid of it
if( uiTotalNumberOfRealItems > 0 )
{
delete[]( pTotalSectorList );
}
}
//Check to see if any of the items in the list have a gridno of NOWHERE and the entry point flag NOT set
CheckGridNoOfItemsInMapScreenMapInventory();
//Sort the sector invenrtory
SortSectorInventory( pInventoryPoolList, uiTotalNumberOfSeenItems );
}
void ReBuildWorldItemStashForLoadedSector( INT32 iNumberSeenItems, INT32 iNumberUnSeenItems, WORLDITEM *pSeenItemsList, WORLDITEM *pUnSeenItemsList )
{
INT32 iTotalNumberOfItems = 0;
INT32 iCurrentItem = 0;
INT32 iCounter = 0;
INT32 iRemainder = 0;
UINT32 uiTotalNumberOfVisibleItems=0;
WORLDITEM * pTotalList = NULL;
// clear out the list
TrashWorldItems( );
// get total number of items
iTotalNumberOfItems = iNumberUnSeenItems + iNumberSeenItems;
iRemainder = iTotalNumberOfItems % 10;
// if there is a remainder, then add onto end of list
if( iRemainder )
{
iTotalNumberOfItems += 10 - iRemainder;
}
// allocate space for items
pTotalList = new WORLDITEM[ iTotalNumberOfItems ];
// place seen items in the world
for( iCounter = 0; iCounter < iNumberSeenItems; iCounter++ )
{
pTotalList[ iCurrentItem ] = pSeenItemsList[ iCounter ];
iCurrentItem++;
}
// now store the unseen item list
for( iCounter = 0; iCounter < iNumberUnSeenItems; iCounter++ )
{
pTotalList[ iCurrentItem ] = pUnSeenItemsList[ iCounter ];
iCurrentItem++;
}
RefreshItemPools( pTotalList, iTotalNumberOfItems );
//Count the total number of visible items
for( iCounter = 0; iCounter < iNumberSeenItems; iCounter++ )
{
uiTotalNumberOfVisibleItems += pSeenItemsList[ iCounter ].object.ubNumberOfObjects;
}
//reset the visible item count in the sector info struct
SetNumberOfVisibleWorldItemsInSectorStructureForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ , uiTotalNumberOfVisibleItems );
// clear out allocated space for total list
delete[]( pTotalList );
// reset total list
pTotalList = NULL;
return;
}
void DestroyStash( void )
{
// clear out stash
pInventoryPoolList.clear();
}
INT32 GetSizeOfStashInSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ, BOOLEAN fCountStacksAsOne )
{
// get # of items in sector that are visible to the player
UINT32 uiTotalNumberOfItems = 0, uiTotalNumberOfRealItems = 0;
WORLDITEM * pTotalSectorList = NULL;
UINT32 uiItemCount = 0;
INT32 iCounter = 0;
BOOLEAN fReturn = TRUE;
if( ( sMapX == gWorldSectorX ) && ( sMapY == gWorldSectorY) && ( sMapZ == gbWorldSectorZ ) )
{
uiTotalNumberOfItems = guiNumWorldItems;
// now run through list and
for( iCounter = 0; ( UINT32 )( iCounter )< uiTotalNumberOfItems; iCounter++ )
{
// if visible to player, then state fact
// if( gWorldItems[ iCounter ].bVisible == 1 && gWorldItems[ iCounter ].fExists )
if( IsMapScreenWorldItemVisibleInMapInventory( &gWorldItems[ iCounter ] ) )
{
// add it
if ( fCountStacksAsOne )
{
uiItemCount++;
}
else
{
uiItemCount += gWorldItems[ iCounter ].object.ubNumberOfObjects;
}
}
}
}
else
{
// get total number, visable and invisible
fReturn = GetNumberOfActiveWorldItemsFromTempFile( sMapX, sMapY, ( INT8 )( sMapZ ), &( uiTotalNumberOfRealItems ) );
Assert( fReturn );
fReturn = GetNumberOfWorldItemsFromTempItemFile( sMapX, sMapY, ( INT8 )( sMapZ ), &( uiTotalNumberOfItems ), FALSE );
Assert( fReturn );
if( uiTotalNumberOfItems > 0 )
{
// allocate space for the list
pTotalSectorList = new WORLDITEM[ uiTotalNumberOfItems ];
// now load into mem
LoadWorldItemsFromTempItemFile( sMapX, sMapY, ( INT8 ) ( sMapZ ), pTotalSectorList );
}
// now run through list and
for( iCounter = 0; ( UINT32 )( iCounter )< uiTotalNumberOfRealItems; iCounter++ )
{
// if visible to player, then state fact
// if( pTotalSectorList[ iCounter ].bVisible == 1 && pTotalSectorList[ iCounter ].fExists )
if( IsMapScreenWorldItemVisibleInMapInventory( &pTotalSectorList[ iCounter ] ) )
{
// add it
if ( fCountStacksAsOne )
{
uiItemCount++;
}
else
{
uiItemCount += pTotalSectorList[ iCounter ].object.ubNumberOfObjects;
}
}
}
// if anything was alloced, then get rid of it
if( pTotalSectorList != NULL )
{
delete[]( pTotalSectorList );
pTotalSectorList = NULL;
#ifdef JA2BETAVERSION
if( uiTotalNumberOfItems == 0 )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"pTotalSectorList is NOT NULL when uiTotalNumberOfRealItems is %d.", uiTotalNumberOfRealItems );
}
#endif
}
}
return( uiItemCount );
}
void BeginInventoryPoolPtr( OBJECTTYPE *pInventorySlot )
{
BOOLEAN fOk = FALSE;
BOOLEAN fSELLALL = gGameExternalOptions.fSellAll;
// If not null return
if ( gpItemPointer != NULL )
{
return;
}
// if shift key get all
if (_KeyDown( SHIFT ))
{
// Remove all from soldier's slot
fOk = (0 == pInventorySlot->MoveThisObjectTo(gItemPointer,-1,0,NUM_INV_SLOTS,MAX_OBJECTS_PER_SLOT));
}
else
{
fOk = (0 == pInventorySlot->MoveThisObjectTo(gItemPointer, 1));
}
if (fOk)
{
if (pInventorySlot->exists() == false) {
pInventorySlot->initialize();
}
// Dirty interface
fMapPanelDirty = TRUE;
gpItemPointer = &gItemPointer;
if ( _KeyDown ( CTRL ))//Delete Item
{
gpItemPointer = NULL;
fMapInventoryItem = FALSE;
if ( _KeyDown ( 89 )) //Lalien: delete all items of this type on Ctrl+Y
{
DeleteItemsOfType( gItemPointer.usItem );
ScreenMsg( FONT_MCOLOR_LTRED, MSG_INTERFACE, New113Message[MSG113_DELETE_ALL] );
}
else {
ScreenMsg( FONT_MCOLOR_LTRED, MSG_INTERFACE, New113Message[MSG113_DELETED] );
}
if ( fShowMapInventoryPool )
HandleButtonStatesWhileMapInventoryActive();
}
else if ( _KeyDown ( ALT ) && fSELLALL)//Sell Item
{
INT32 iPrice = SellItem( gItemPointer );
PlayJA2Sample( COMPUTER_BEEP2_IN, RATE_11025, 15, 1, MIDDLEPAN );
gpItemPointer = NULL;
fMapInventoryItem = FALSE;
if ( _KeyDown ( 89 )) //Lalien: sell all items of this type on Alt+Y
{
for( UINT32 iNumber = 0 ; iNumber < pInventoryPoolList.size() ; ++iNumber)
{
// WANNE: Fix by Headrock
//if ( pInventoryPoolList[ iNumber ].object.usItem == gItemPointer.usItem )
if ( pInventoryPoolList[ iNumber ].object.usItem == gItemPointer.usItem && pInventoryPoolList[ iNumber ].usFlags & WORLD_ITEM_REACHABLE)
{
iPrice += SellItem( pInventoryPoolList[ iNumber ].object );
DeleteObj( &pInventoryPoolList [ iNumber ].object );
}
}
}
//ADB you can sell items for 0, but that's not fair
//and it's not easy to stop the sale so make the price 1
if (iPrice == 0) {
iPrice = 1;
}
if ( _KeyDown ( 89 )) //Lalien: sell all items of this type on Alt+Y
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_SOLD_ALL] );
}
else {
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_SOLD] );
}
AddTransactionToPlayersBook( SOLD_ITEMS, 0, GetWorldTotalMin(), iPrice );
if ( fShowMapInventoryPool )
HandleButtonStatesWhileMapInventoryActive();
}
else
{
gpItemPointerSoldier = NULL;
// now set the cursor
guiExternVo = GetInterfaceGraphicForItem( &(Item[ gpItemPointer->usItem ]) );
gusExternVoSubIndex = g_bUsePngItemImages ? 0 : Item[ gpItemPointer->usItem ].ubGraphicNum;
fMapInventoryItem = TRUE;
MSYS_ChangeRegionCursor( &gMPanelRegion , EXTERN_CURSOR );
SetCurrentCursorFromDatabase( EXTERN_CURSOR );
if ( fShowInventoryFlag && bSelectedInfoChar >= 0 )
{
ReevaluateItemHatches( MercPtrs[ gCharactersList[ bSelectedInfoChar ].usSolID ], FALSE );
fTeamPanelDirty = TRUE;
}
}
}
}
BOOLEAN PlaceObjectInInventoryStash( OBJECTTYPE *pInventorySlot, OBJECTTYPE *pItemPtr )
{
// if there is something there, swap it, if they are of the same type and stackable then add to the count
if (pInventorySlot->exists() == false)
{
// placement in an empty slot
pItemPtr->MoveThisObjectTo(*pInventorySlot);
}
else
{
if (pItemPtr->usItem == pInventorySlot->usItem && ItemSlotLimit(pItemPtr, STACK_SIZE_LIMIT) >= 2)
{
// stacking
pInventorySlot->AddObjectsToStack(*pItemPtr);
}
else
{
SwapObjs( pItemPtr, pInventorySlot );
}
}
return( TRUE );
}
BOOLEAN AutoPlaceObjectInInventoryStash( OBJECTTYPE *pItemPtr, INT32 sGridNo )
{
OBJECTTYPE *pInventorySlot;
INT32 cnt = 0;
//CHRISL: I'm not sure why this never fails. Maybe it just isn't used often. But if we try and look for index
// pInventoryPoolList.size() we're going to crash since "size()" returns the total number of indecies in human terms (1-xxx)
// but we have to start with 0. In other words, size() might return a value of 10 but those are numbers 0-9.
while(1)
{
//if we run out of indecies before running out of items to place, make new indecies
if(cnt == pInventoryPoolList.size())
{
ResizeInventoryList();
}
pInventorySlot = &pInventoryPoolList[cnt].object;
if(pInventorySlot->usItem == pItemPtr->usItem)
{
pInventorySlot->AddObjectsToStack(*pItemPtr);
}
else if(pInventorySlot->exists() == false)
{
pItemPtr->MoveThisObjectTo(*pInventorySlot);
if(sGridNo != 0)
{
pInventoryPoolList[cnt].sGridNo = sGridNo;
pInventoryPoolList[cnt].usFlags = 512;
pInventoryPoolList[cnt].bVisible = 1;
pInventoryPoolList[cnt].fExists = TRUE;
}
}
else
{
cnt++;
continue;
}
if(pItemPtr->exists() == false)
{
break;
}
else
{
cnt++;
}
}
// if there is something there, swap it, if they are of the same type and stackable then add to the count
// pInventorySlot = &( pInventoryPoolList[ pInventoryPoolList.size() ].object );
// placement in an empty slot
// could be wrong type of object for slot... need to check...
// but assuming it isn't
// pItemPtr->MoveThisObjectTo(*pInventorySlot);
return( TRUE );
}
void MapInventoryPoolNextBtn( GUI_BUTTON *btn, INT32 reason )
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags|=(BUTTON_CLICKED_ON);
}
else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if (btn->uiFlags & BUTTON_CLICKED_ON)
{
btn->uiFlags&=~(BUTTON_CLICKED_ON);
// if can go to next page, go there
if( iCurrentInventoryPoolPage < ( iLastInventoryPoolPage ) )
{
iCurrentInventoryPoolPage++;
fMapPanelDirty = TRUE;
}
}
}
}
void MapInventoryPoolPrevBtn( GUI_BUTTON *btn, INT32 reason )
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags|=(BUTTON_CLICKED_ON);
}
else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if (btn->uiFlags & BUTTON_CLICKED_ON)
{
btn->uiFlags&=~(BUTTON_CLICKED_ON);
// if can go to next page, go there
if( iCurrentInventoryPoolPage > 0 )
{
iCurrentInventoryPoolPage--;
fMapPanelDirty = TRUE;
}
}
}
}
void MapInventoryPoolDoneBtn( GUI_BUTTON *btn, INT32 reason )
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags|=(BUTTON_CLICKED_ON);
}
else if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
if (btn->uiFlags & BUTTON_CLICKED_ON)
{
btn->uiFlags&=~(BUTTON_CLICKED_ON);
if (gfInItemDescBox)
{
DoMapMessageBox( MSG_BOX_BASIC_STYLE, gzLateLocalizedString[64], MAP_SCREEN, MSG_BOX_FLAG_OK, NULL );
}
else
{
// done
fShowMapInventoryPool = FALSE;
}
}
}
}
void DisplayPagesForMapInventoryPool( void )
{
// get the current and last pages and display them
CHAR16 sString[ 32 ];
INT16 sX, sY;
SetFont( COMPFONT );
SetFontForeground( 183 );
SetFontBackground( FONT_BLACK );
// set the buffer
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// grab current and last pages
swprintf( sString, L"%d / %d", iCurrentInventoryPoolPage + 1, iLastInventoryPoolPage + 1 );
// grab centered coords
FindFontCenterCoordinates(MAP_INVENTORY_POOL_PAGE_X, MAP_INVENTORY_POOL_PAGE_Y - 2 * yResOffset, MAP_INVENTORY_POOL_PAGE_WIDTH ,MAP_INVENTORY_POOL_PAGE_HEIGHT ,sString , MAP_SCREEN_FONT, &sX, &sY);
mprintf( sX, sY, sString );
SetFontDestBuffer( FRAME_BUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
}
INT32 GetTotalNumberOfItemsInSectorStash( void )
{
INT32 iCount = 0;
// run through list of items and find out how many are there
for( UINT32 iCounter = 0; iCounter < pInventoryPoolList.size(); iCounter++ )
{
if( pInventoryPoolList[ iCounter].object.exists() == true )
{
iCount += pInventoryPoolList[ iCounter].object.ubNumberOfObjects;
}
}
return iCount;
}
INT32 GetTotalNumberOfItems( void )
{
INT32 iCount = 0;
// run through list of items and find out how many are there
for(UINT32 iCounter = 0; iCounter < pInventoryPoolList.size(); iCounter++ )
{
if( pInventoryPoolList[ iCounter].object.exists() == true )
{
iCount++;
}
}
return iCount;
}
void DrawNumberOfIventoryPoolItems( void )
{
INT32 iNumberOfItems = 0;
CHAR16 sString[ 32 ];
INT16 sX, sY;
iNumberOfItems = GetTotalNumberOfItemsInSectorStash( );
// get number of items
swprintf( sString, L"%d", iNumberOfItems );
// set font stuff
SetFont( COMPFONT );
SetFontForeground( 183 );
SetFontBackground( FONT_BLACK );
// set the buffer
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// grab centered coords
FindFontCenterCoordinates(MAP_INVENTORY_POOL_NUMBER_X, MAP_INVENTORY_POOL_PAGE_Y - 2 * yResOffset, MAP_INVENTORY_POOL_NUMBER_WIDTH ,MAP_INVENTORY_POOL_PAGE_HEIGHT ,sString , MAP_SCREEN_FONT, &sX, &sY);
mprintf( sX, sY, sString );
SetFontDestBuffer( FRAME_BUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
return;
}
void CreateMapInventoryPoolDoneButton( void )
{
// create done button
guiMapInvenButtonImage[ 2 ]= LoadButtonImage( "INTERFACE\\done_button.sti" , -1, 0, -1, 1, -1 );
guiMapInvenButton[ 2 ] = QuickCreateButton( guiMapInvenButtonImage[ 2 ], MAP_INV_X_OFFSET + 587 , (yResSize - 147),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)MapInventoryPoolDoneBtn );
// set up fast help text
SetButtonFastHelpText( guiMapInvenButton[ 2 ], pMapScreenInvenButtonHelpText[ 2 ] );
return;
}
void DestroyInventoryPoolDoneButton( void )
{
// destroy ddone button
RemoveButton( guiMapInvenButton[ 2 ] );
UnloadButtonImage( guiMapInvenButtonImage[ 2 ] );
return;
}
void DisplayCurrentSector( void )
{
// grab current sector being displayed
CHAR16 sString[ 32 ];
INT16 sX, sY;
swprintf( sString, L"%s%s%s", pMapVertIndex[ sSelMapY ], pMapHortIndex[ sSelMapX ], pMapDepthIndex[ iCurrentMapSectorZ ] );
// set font stuff
SetFont( COMPFONT );
SetFontForeground( 183 );
SetFontBackground( FONT_BLACK );
// set the buffer
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// grab centered coords
FindFontCenterCoordinates(MAP_INVENTORY_POOL_LOC_X, MAP_INVENTORY_POOL_PAGE_Y - 2 * yResOffset, MAP_INVENTORY_POOL_LOC_WIDTH ,MAP_INVENTORY_POOL_PAGE_HEIGHT ,sString , MAP_SCREEN_FONT, &sX, &sY);
mprintf( sX, sY, sString );
SetFontDestBuffer( FRAME_BUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
}
void ResizeInventoryList( void )
{
if (pInventoryPoolList.empty() == true) {
pInventoryPoolList.resize(MAP_INVENTORY_POOL_SLOT_COUNT);
}
int emptySlots = 0;
//if it's not the exact size of a page, then make it so
if (pInventoryPoolList.size() % MAP_INVENTORY_POOL_SLOT_COUNT) {
emptySlots = MAP_INVENTORY_POOL_SLOT_COUNT - (pInventoryPoolList.size() % MAP_INVENTORY_POOL_SLOT_COUNT);
pInventoryPoolList.resize(pInventoryPoolList.size() + emptySlots);
}
//This lets us determine whether to create a new page based on the contents of the last page instead of every page
// which lets players move things around without having to first hunt down and fill up blank slots on other pages
iLastInventoryPoolPage = ( ( pInventoryPoolList.size() - 1 ) / MAP_INVENTORY_POOL_SLOT_COUNT );
int lastPageIndex = iLastInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT;
int activeSlotsOnPage = 0;
for (int x = 0; x < MAP_INVENTORY_POOL_SLOT_COUNT; ++x) {
//don't test fExists because that hasn't been set yet, test object.exists
if (pInventoryPoolList[lastPageIndex + x].object.exists() == true) {
++activeSlotsOnPage;
}
}
//if there aren't enough empty slots we need to grow it further
emptySlots = MAP_INVENTORY_POOL_SLOT_COUNT - activeSlotsOnPage;
if (emptySlots < 3) {
//we want 1 blank page
pInventoryPoolList.resize(pInventoryPoolList.size() + MAP_INVENTORY_POOL_SLOT_COUNT);
}
//do this again, it may have changed
iLastInventoryPoolPage = ( ( pInventoryPoolList.size() - 1 ) / MAP_INVENTORY_POOL_SLOT_COUNT );
return;
}
void DrawTextOnMapInventoryBackground( void )
{
UINT16 usStringHeight;
SetFont( MAP_IVEN_FONT );
SetFontBackground( FONT_BLACK );
SetFontForeground( FONT_BEIGE );
// set the buffer
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
//Calculate the height of the string, as it needs to be vertically centered.
usStringHeight = DisplayWrappedString(MAP_INV_X_OFFSET + 268, (SCREEN_HEIGHT - 138 - 2 * yResOffset), 53, 1, MAP_IVEN_FONT, FONT_BEIGE, pMapInventoryStrings[ 0 ], FONT_BLACK, FALSE, RIGHT_JUSTIFIED | DONT_DISPLAY_TEXT );
DisplayWrappedString(MAP_INV_X_OFFSET + 268, (UINT16)((SCREEN_HEIGHT - 138 - 2 * yResOffset) - (usStringHeight / 2) ), 53, 1, MAP_IVEN_FONT, FONT_BEIGE, pMapInventoryStrings[ 0 ], FONT_BLACK, FALSE, RIGHT_JUSTIFIED );
//Calculate the height of the string, as it needs to be vertically centered.
usStringHeight = DisplayWrappedString( MAP_INV_X_OFFSET + 369, (SCREEN_HEIGHT - 138 - 2 * yResOffset), 65, 1, MAP_IVEN_FONT, FONT_BEIGE, pMapInventoryStrings[ 1 ], FONT_BLACK, FALSE, RIGHT_JUSTIFIED | DONT_DISPLAY_TEXT );
DisplayWrappedString(MAP_INV_X_OFFSET + 369, (UINT16)((SCREEN_HEIGHT - 138 - 2 * yResOffset) - (usStringHeight / 2) ), 65, 1, MAP_IVEN_FONT, FONT_BEIGE, pMapInventoryStrings[ 1 ], FONT_BLACK, FALSE, RIGHT_JUSTIFIED );
DrawTextOnSectorInventory( );
SetFontDestBuffer( FRAME_BUFFER, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
return;
}
void HandleButtonStatesWhileMapInventoryActive( void )
{
// are we even showing the amp inventory pool graphic?
if( fShowMapInventoryPool == FALSE )
{
return;
}
// first page, can't go back any
if( iCurrentInventoryPoolPage == 0 )
{
DisableButton( guiMapInvenButton[ 1 ] );
}
else
{
EnableButton( guiMapInvenButton[ 1 ] );
}
// last page, go no further
if( iCurrentInventoryPoolPage == iLastInventoryPoolPage )
{
DisableButton( guiMapInvenButton[ 0 ] );
}
else
{
EnableButton( guiMapInvenButton[ 0 ] );
}
// item picked up ..disable button
if( gMPanelRegion.Cursor == EXTERN_CURSOR )
{
DisableButton( guiMapInvenButton[ 2 ] );
}
else
{
EnableButton( guiMapInvenButton[ 2 ] );
}
}
void DrawTextOnSectorInventory( void )
{
INT16 sX = 0, sY = 0;
CHAR16 sString[ 64 ];
// parse the string
swprintf( sString, zMarksMapScreenText[ 11 ] );
if(gGameExternalOptions.fEnableInventoryPoolQ && gInventoryPoolIndex != '0')//dnl ch51 081009
swprintf(sString, L"Inventory Pool %c", gInventoryPoolIndex);
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
FindFontCenterCoordinates( (SCREEN_WIDTH - INTERFACE_WIDTH)/2 + 271, 18, xResSize - 271, GetFontHeight( FONT14ARIAL ), sString, FONT14ARIAL, &sX, &sY );
SetFont( FONT14ARIAL );
SetFontForeground( FONT_WHITE );
SetFontBackground( FONT_BLACK );
mprintf( sX, sY, sString );
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
}
void HandleFlashForHighLightedItem( void )
{
INT32 iCurrentTime = 0;
INT32 iDifference = 0;
// if there is an invalid item, reset
if( iCurrentlyHighLightedItem == -1 )
{
fFlashHighLightInventoryItemOnradarMap = FALSE;
giFlashHighlightedItemBaseTime = 0;
}
// get the current time
iCurrentTime = GetJA2Clock();
// if there basetime is uninit
if( giFlashHighlightedItemBaseTime == 0 )
{
giFlashHighlightedItemBaseTime = iCurrentTime;
}
iDifference = iCurrentTime - giFlashHighlightedItemBaseTime;
if( iDifference > DELAY_FOR_HIGHLIGHT_ITEM_FLASH )
{
// reset timer
giFlashHighlightedItemBaseTime = iCurrentTime;
// flip flag
fFlashHighLightInventoryItemOnradarMap = !fFlashHighLightInventoryItemOnradarMap;
// re render radar map
RenderRadarScreen( );
}
}
void HandleMouseInCompatableItemForMapSectorInventory( INT32 iCurrentSlot )
{
SOLDIERTYPE *pSoldier = NULL;
static BOOLEAN fItemWasHighLighted = FALSE;
if( iCurrentSlot == -1 )
{
giCompatibleItemBaseTime = 0;
}
if( fChangedInventorySlots == TRUE )
{
giCompatibleItemBaseTime = 0;
fChangedInventorySlots = FALSE;
}
// reset the base time to the current game clock
if( giCompatibleItemBaseTime == 0 )
{
giCompatibleItemBaseTime = GetJA2Clock( );
if( fItemWasHighLighted == TRUE )
{
fTeamPanelDirty = TRUE;
fMapPanelDirty = TRUE;
fItemWasHighLighted = FALSE;
}
}
ResetCompatibleItemArray( );
ResetMapSectorInventoryPoolHighLights( );
if( iCurrentSlot == -1 )
{
return;
}
// given this slot value, check if anything in the displayed sector inventory or on the mercs inventory is compatable
if( fShowInventoryFlag )
{
// check if any compatable items in the soldier inventory matches with this item
if( gfCheckForCursorOverMapSectorInventoryItem )
{
pSoldier = &Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ];
if( pSoldier )
{
if( HandleCompatibleAmmoUIForMapScreen( pSoldier, iCurrentSlot + ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ), TRUE, FALSE ) )
{
if( GetJA2Clock( ) - giCompatibleItemBaseTime > 100 )
{
if( fItemWasHighLighted == FALSE )
{
fTeamPanelDirty = TRUE;
fItemWasHighLighted = TRUE;
}
}
}
}
}
else
{
giCompatibleItemBaseTime = 0;
}
}
// now handle for the sector inventory
if( fShowMapInventoryPool )
{
// check if any compatable items in the soldier inventory matches with this item
if( gfCheckForCursorOverMapSectorInventoryItem )
{
if( HandleCompatibleAmmoUIForMapInventory( pSoldier, iCurrentSlot, ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) , TRUE, FALSE ) )
{
if( GetJA2Clock( ) - giCompatibleItemBaseTime > 100 )
{
if( fItemWasHighLighted == FALSE )
{
fItemWasHighLighted = TRUE;
fMapPanelDirty = TRUE;
}
}
}
}
else
{
giCompatibleItemBaseTime = 0;
}
}
return;
}
void ResetMapSectorInventoryPoolHighLights( void )
{
INT32 iCounter = 0;
// now reset the highlight list for the map sector inventory
for ( iCounter = 0; iCounter < MAP_INVENTORY_POOL_SLOT_COUNT; iCounter++ )
{
if ( fMapInventoryItemCompatable[ iCounter ] )
{
fMapInventoryItemCompatable[ iCounter ] = FALSE;
}
}
return;
}
void HandleMapSectorInventory( void )
{
// handle mouse in compatable item map sectors inventory
HandleMouseInCompatableItemForMapSectorInventory( iCurrentlyHighLightedItem );
return;
}
//CJC look here to add/remove checks for the sector inventory
BOOLEAN IsMapScreenWorldItemVisibleInMapInventory( WORLDITEM *pWorldItem )
{
if( pWorldItem->bVisible == 1 &&
pWorldItem->fExists &&
pWorldItem->object.exists() == true &&
pWorldItem->object.usItem != SWITCH &&
pWorldItem->object.usItem != ACTION_ITEM &&
pWorldItem->object[0]->data.bTrap <= 0 )
{
return( TRUE );
}
return( FALSE );
}
//CJC look here to add/remove checks for the sector inventory
BOOLEAN IsMapScreenWorldItemInvisibleInMapInventory( WORLDITEM *pWorldItem )
{
if( pWorldItem->fExists &&
pWorldItem->object.exists() == true &&
!IsMapScreenWorldItemVisibleInMapInventory( pWorldItem ) )
{
return( TRUE );
}
return( FALSE );
}
//Check to see if any of the items in the list have a gridno of NOWHERE and the entry point flag NOT set
void CheckGridNoOfItemsInMapScreenMapInventory()
{
INT32 iCnt;
UINT32 uiNumFlagsNotSet = 0;
INT32 iTotalNumberItems = GetTotalNumberOfItems( );
for( iCnt=0; iCnt<iTotalNumberItems; iCnt++)
{
if( ( TileIsOutOfBounds(pInventoryPoolList[ iCnt ].sGridNo) )&& !( pInventoryPoolList[ iCnt ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) )
{
//set the flag
pInventoryPoolList[ iCnt ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT;
//count the number
uiNumFlagsNotSet++;
}
}
//loop through all the UNSEEN items
for( iCnt=0; iCnt<(INT32)uiNumberOfUnSeenItems; iCnt++)
{
if (TileIsOutOfBounds(pUnSeenItems[ iCnt ].sGridNo) && !( pUnSeenItems[ iCnt ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) )
{
//set the flag
pUnSeenItems[ iCnt ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT;
//count the number
uiNumFlagsNotSet++;
}
}
#ifdef JA2BETAVERSION
if( uiNumFlagsNotSet > 0 )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Item with invalid gridno doesnt have flag set.", uiNumFlagsNotSet );
}
#endif
}
void SortSectorInventory( std::vector<WORLDITEM>& pInventory, UINT32 uiSizeOfArray )
{
//first, compress the inventory by stacking like items that are reachable, while moving empty items towards the back
for (std::vector<WORLDITEM>::iterator iter = pInventory.begin(); iter != pInventory.end(); ++iter) {
//if object exists, we want to try to stack it
if (iter->fExists && iter->object.exists() == true) {
//ADB TODO if it is active and reachable etc, alternatively if it's on the same gridNo
#if 0
if (iter->object.ubNumberOfObjects < ItemSlotLimit( iter->object.usItem, STACK_SIZE_LIMIT )) {
std::vector<WORLDITEM>::iterator second = iter;
for (++second; second != pInventory.end(); ++second) {
if (second->object.usItem == iter->object.usItem
&& second->object.exists() == true) {
iter->object.AddObjectsToStack(second->object, second->object.ubNumberOfObjects);
if (iter->object.ubNumberOfObjects >= ItemSlotLimit( iter->object.usItem, STACK_SIZE_LIMIT )) {
break;
}
}
}
}
#endif
}
else {
//object does not exist, so compress the list
std::vector<WORLDITEM>::iterator second = iter;
for (++second; second != pInventory.end(); ++second) {
if (second->fExists && second->object.exists() == true) {
*iter = *second;
second->initialize();
break;
}
}
if (second == pInventory.end()) {
//we reached the end of the list without finding any active item, so we can break out of this loop too!
break;
}
}
}
//once compressed, we need only sort the existing items
//all empty items should be at the back!!!
std::vector<WORLDITEM>::iterator endSort = pInventory.begin();
for (unsigned int x = 1; x < pInventory.size(); ++x) {
if (pInventory[x].fExists && pInventory[x].object.exists() == true) {
++endSort;
}
else {
break;
}
}
++endSort;
//ADB I'm not sure qsort will work with OO data, so replace it with stl sort, which is faster anyways
std::sort(pInventory.begin(), endSort);
//then compress it by removing the empty objects, we know they are at the back
//we want the size to equal x * MAP_INVENTORY_POOL_SLOT_COUNT
for (unsigned int x = 1; x <= pInventory.size() / MAP_INVENTORY_POOL_SLOT_COUNT && pInventory.size() > x * MAP_INVENTORY_POOL_SLOT_COUNT; ++x) {
if (pInventory[x * MAP_INVENTORY_POOL_SLOT_COUNT].fExists == false
&& pInventory[x * MAP_INVENTORY_POOL_SLOT_COUNT].object.exists() == false) {
//we have found a page where the first item on the page does not exist, resize to this
//we may have just cut off a blank page leaving the previous page full with no place to put
//any new objects, but ResizeInventoryList after this will take care of that.
pInventory.resize(x * MAP_INVENTORY_POOL_SLOT_COUNT);
}
}
}
INT32 MapScreenSectorInventoryCompare( const void *pNum1, const void *pNum2)
{
WORLDITEM *pFirst = (WORLDITEM *)pNum1;
WORLDITEM *pSecond = (WORLDITEM *)pNum2;
UINT16 usItem1Index;
UINT16 usItem2Index;
UINT16 ubItem1Quality;
UINT16 ubItem2Quality;
/*
if(gGameExternalOptions.fEnableInventoryPoolQ)//dnl??? ch51 081009
{
if(pFirst->object.usItem == 0)
return(1);
else if(pSecond->object.usItem == 0)
return(-1);
}
*/
usItem1Index = pFirst->object.usItem;
usItem2Index = pSecond->object.usItem;
ubItem1Quality = pFirst->object[0]->data.objectStatus;
ubItem2Quality = pSecond->object[0]->data.objectStatus;
return( CompareItemsForSorting( usItem1Index, usItem2Index, ubItem1Quality, ubItem2Quality ) );
}
BOOLEAN CanPlayerUseSectorInventory( SOLDIERTYPE *pSelectedSoldier )
{
INT16 sSectorX, sSectorY, sSectorZ;
//Get the sector that has a battle
BOOLEAN fInCombat = GetCurrentBattleSectorXYZAndReturnTRUEIfThereIsABattle( &sSectorX, &sSectorY, &sSectorZ );
//if there is a battle going on
if( fInCombat )
{
//if the selected map is the one with the combat
if( ( ( sSelMapX == sSectorX ) &&
( sSelMapY == sSectorY ) &&
( iCurrentMapSectorZ == sSectorZ )
)
)
{
return( FALSE );
}
}
return( TRUE );
}
//dnl ch51 081009 start
BOOLEAN LoadInventoryPoolQ (UINT8 ubSaveGameID)
{
BOOLEAN ret;
INT32 i, j, iTotNumSlots;
CHAR8 tmpbuf[1024];
UINT32 uiNumBytesRead;
HWFILE hFile;
if(MAP_INVENTORY_POOL_SLOT_COUNT <= 0)
{
if (iResolution >= _640x480 && iResolution < _800x600)
MAP_INVENTORY_POOL_SLOT_COUNT = 40;
else if (iResolution < _1024x768)
MAP_INVENTORY_POOL_SLOT_COUNT = 77;
else
MAP_INVENTORY_POOL_SLOT_COUNT = 170;
}
ret = FALSE;
CreateSavedGameFileNameFromNumber(ubSaveGameID, tmpbuf);
strcat(tmpbuf, ".IPQ");
hFile = FileOpen(tmpbuf, FILE_ACCESS_READ|FILE_OPEN_EXISTING, FALSE);
if(hFile == 0)
return(TRUE);
MemFreeInventoryPoolQ();
FileRead(hFile, iCurrentInventoryPoolPageQ+1, (INVPOOLLISTNUM-1)*sizeof(INT32), &uiNumBytesRead);
if(uiNumBytesRead != (INVPOOLLISTNUM-1)*sizeof(INT32))
goto ERR;
FileRead(hFile, iLastInventoryPoolPageQ+1, (INVPOOLLISTNUM-1)*sizeof(INT32), &uiNumBytesRead);
if(uiNumBytesRead != (INVPOOLLISTNUM-1)*sizeof(INT32))
goto ERR;
for(i=1; i<INVPOOLLISTNUM; i++)
{
FileRead(hFile, &j, sizeof(INT32), &uiNumBytesRead);
if(uiNumBytesRead != sizeof(INT32))
goto ERR;
if(j == 0)
continue;
iTotNumSlots = j;
if(MAP_INVENTORY_POOL_SLOT_COUNT != (j/(iLastInventoryPoolPageQ[i]+1)))
{
iLastInventoryPoolPageQ[i] = j / MAP_INVENTORY_POOL_SLOT_COUNT + 1;
j = iLastInventoryPoolPageQ[i] * MAP_INVENTORY_POOL_SLOT_COUNT;
iCurrentInventoryPoolPageQ[i] = 0;
}
pInventoryPoolListQ[i].resize(j);
for(j=0; j<iTotNumSlots; j++)
if(!pInventoryPoolListQ[i][j].Load(hFile))
goto ERR;
}
ret = TRUE;
ERR:
if(ret == FALSE)
MemFreeInventoryPoolQ();
FileClose(hFile);
return(ret);
}
BOOLEAN MemFreeInventoryPoolQ(void)
{
INT32 i;
for(i=1; i<INVPOOLLISTNUM; i++)
{
pInventoryPoolListQ[i].clear();
iCurrentInventoryPoolPageQ[i] = 0;
iLastInventoryPoolPageQ[i] = 0;
}
return(TRUE);
}
BOOLEAN SaveInventoryPoolQ(UINT8 ubSaveGameID)
{
BOOLEAN ret;
INT32 i, j;
CHAR8 tmpbuf[1024];
UINT32 uiNumBytesWritten;
HWFILE hFile;
if(MAP_INVENTORY_POOL_SLOT_COUNT <= 0)
{
if (iResolution >= _640x480 && iResolution < _800x600)
MAP_INVENTORY_POOL_SLOT_COUNT = 40;
else if (iResolution < _1024x768)
MAP_INVENTORY_POOL_SLOT_COUNT = 77;
else
MAP_INVENTORY_POOL_SLOT_COUNT = 170;
}
ret = FALSE;
CreateSavedGameFileNameFromNumber(ubSaveGameID, tmpbuf);
strcat(tmpbuf, ".IPQ");
hFile = FileOpen(tmpbuf, FILE_ACCESS_WRITE|FILE_OPEN_ALWAYS, FALSE);
if(hFile == 0)
goto ERR;
FileWrite(hFile, iCurrentInventoryPoolPageQ+1, (INVPOOLLISTNUM-1)*sizeof(INT32), &uiNumBytesWritten);
if(uiNumBytesWritten != (INVPOOLLISTNUM-1)*sizeof(INT32))
goto ERR;
FileWrite(hFile, iLastInventoryPoolPageQ+1, (INVPOOLLISTNUM-1)*sizeof(INT32), &uiNumBytesWritten);
if(uiNumBytesWritten != (INVPOOLLISTNUM-1)*sizeof(INT32))
goto ERR;
for(i=1; i<INVPOOLLISTNUM; i++)
{
j = pInventoryPoolListQ[i].size();
FileWrite(hFile, &j, sizeof(INT32), &uiNumBytesWritten);
if(uiNumBytesWritten != sizeof(INT32))
goto ERR;
for(j=0; j<(INT32)pInventoryPoolListQ[i].size(); j++)
if(!pInventoryPoolListQ[i][j].Save(hFile, TRUE))
goto ERR;
}
ret = TRUE;
ERR:
FileClose(hFile);
return(ret);
}
BOOLEAN SortInventoryPoolQ(void)
{
if(pInventoryPoolList.size() > 0)
{
for(INT32 iSlotCounter=0; iSlotCounter<(INT32)pInventoryPoolList.size(); iSlotCounter++)
if(pInventoryPoolList[iSlotCounter].object.usItem == NOTHING && pInventoryPoolList[iSlotCounter].object.exists() == false)
{
pInventoryPoolList[iSlotCounter].fExists = FALSE;
pInventoryPoolList[iSlotCounter].bVisible = FALSE;
}
SortSectorInventory(pInventoryPoolList, pInventoryPoolList.size());
iLastInventoryPoolPage = (pInventoryPoolList.size() - 1) / MAP_INVENTORY_POOL_SLOT_COUNT;
if(iCurrentInventoryPoolPage > iLastInventoryPoolPage)
iCurrentInventoryPoolPage = iLastInventoryPoolPage;
}
fMapPanelDirty = TRUE;
return(TRUE);
}
BOOLEAN SwitchToInventoryPoolQ(UINT8 newidx)
{
UINT8 curidx;
curidx = gInventoryPoolIndex & 0x0F;
pInventoryPoolListQ[curidx] = pInventoryPoolList;
iCurrentInventoryPoolPageQ[curidx] = iCurrentInventoryPoolPage;
iLastInventoryPoolPageQ[curidx] = iLastInventoryPoolPage;
newidx &= 0x0F;
if (pInventoryPoolListQ[newidx].empty() == true)
pInventoryPoolListQ[newidx].resize(MAP_INVENTORY_POOL_SLOT_COUNT);
pInventoryPoolList = pInventoryPoolListQ[newidx];
iCurrentInventoryPoolPage = iCurrentInventoryPoolPageQ[newidx];
iLastInventoryPoolPage = iLastInventoryPoolPageQ[newidx];
gInventoryPoolIndex = newidx | 0x30;
fMapPanelDirty = TRUE;
return(TRUE);
}
BOOLEAN CopySectorInventoryToInventoryPoolQ(UINT8 idx)
{
INT32 iSlotCounter, iSlotCounterQ;
idx = gInventoryPoolIndex & 0x0F;
if(idx <= 0 || idx >= INVPOOLLISTNUM)
return(FALSE);
SwitchToInventoryPoolQ('0');
iSlotCounterQ = 0;
for(iSlotCounter=0; iSlotCounter<(INT32)pInventoryPoolList.size(); iSlotCounter++)
{
if(pInventoryPoolList[iSlotCounter].bVisible==1 && pInventoryPoolList[iSlotCounter].fExists && pInventoryPoolList[iSlotCounter].usFlags&WORLD_ITEM_REACHABLE && pInventoryPoolList[iSlotCounter].object.usItem != NOTHING)
{
while(1)
{
if(iSlotCounterQ >= (INT32)pInventoryPoolListQ[idx].size())
{
pInventoryPoolListQ[idx].resize(pInventoryPoolListQ[idx].size() + MAP_INVENTORY_POOL_SLOT_COUNT);
iLastInventoryPoolPageQ[idx] = (pInventoryPoolListQ[idx].size() - 1) / MAP_INVENTORY_POOL_SLOT_COUNT;
}
if(pInventoryPoolListQ[idx][iSlotCounterQ].object.usItem == NOTHING)
{
pInventoryPoolListQ[idx][iSlotCounterQ] = pInventoryPoolList[iSlotCounter];
DeleteObj(&pInventoryPoolList[iSlotCounter].object);
iSlotCounterQ++;
break;
}
iSlotCounterQ++;
}
}
}
SwitchToInventoryPoolQ(idx|'0');
return(TRUE);
}
BOOLEAN CopySectorInventoryToInventoryPoolQs(UINT8 idx)
{
UINT8 defaultidx;
INT32 iSlotCounter, iSlotCounterQ[INVPOOLLISTNUM];
idx = gInventoryPoolIndex & 0x0F;
if(!(idx == 0 || idx == 8 || idx == 9))// Only from these inventories items could be separate to 1-7
return(FALSE);
defaultidx = idx;
memset(iSlotCounterQ, 0, sizeof(iSlotCounterQ));
for(iSlotCounter=0; iSlotCounter<(INT32)pInventoryPoolList.size(); iSlotCounter++)
{
if(pInventoryPoolList[iSlotCounter].bVisible==1 && pInventoryPoolList[iSlotCounter].fExists && pInventoryPoolList[iSlotCounter].usFlags&WORLD_ITEM_REACHABLE && pInventoryPoolList[iSlotCounter].object.usItem != NOTHING)
{
UINT32 usItemClass = Item[pInventoryPoolList[iSlotCounter].object.usItem].usItemClass;
if(usItemClass == IC_GUN || usItemClass == IC_LAUNCHER)
idx = 1;
else if(usItemClass == IC_AMMO || usItemClass == IC_BELTCLIP)
idx = 2;
else if(usItemClass == IC_BOMB || usItemClass == IC_GRENADE)
idx = 3;
else if(usItemClass == IC_BLADE || usItemClass == IC_THROWING_KNIFE || usItemClass == IC_THROWN || usItemClass == IC_PUNCH)
idx = 4;
else if(usItemClass == IC_ARMOUR || usItemClass == IC_LBEGEAR)
idx = 5;
else if(usItemClass == IC_MEDKIT || usItemClass == IC_KIT || usItemClass == IC_APPLIABLE)
idx = 6;
else if(usItemClass == IC_NONE || usItemClass == IC_FACE || usItemClass == IC_KEY || usItemClass == IC_MISC || usItemClass == IC_MONEY || usItemClass == IC_TENTACLES)
idx = 7;
else
idx = defaultidx;
while(1)
{
if(iSlotCounterQ[idx] >= (INT32)pInventoryPoolListQ[idx].size())
{
pInventoryPoolListQ[idx].resize(pInventoryPoolListQ[idx].size() + MAP_INVENTORY_POOL_SLOT_COUNT);
iLastInventoryPoolPageQ[idx] = (pInventoryPoolListQ[idx].size() - 1) / MAP_INVENTORY_POOL_SLOT_COUNT;
}
if(pInventoryPoolListQ[idx][iSlotCounterQ[idx]].object.usItem == NOTHING)
{
pInventoryPoolListQ[idx][iSlotCounterQ[idx]] = pInventoryPoolList[iSlotCounter];
DeleteObj(&pInventoryPoolList[iSlotCounter].object);
pInventoryPoolList[iSlotCounter].fExists = FALSE;
pInventoryPoolList[iSlotCounter].bVisible = FALSE;
iSlotCounterQ[idx]++;
break;
}
iSlotCounterQ[idx]++;
}
}
}
fMapPanelDirty = TRUE;
return(TRUE);
}
//dnl ch51 081009 finish
void DeleteAllItemsInInventoryPool()
{
pInventoryPoolList.clear();
fMapPanelDirty = TRUE;
ClearUpTempUnSeenList( );
SaveSeenAndUnseenItems();
iCurrentInventoryPoolPage = 0;
iLastInventoryPoolPage = 0;
DestroyStash();
BuildStashForSelectedSector( sSelMapX, sSelMapY, iCurrentMapSectorZ);
}
void DeleteItemsOfType( UINT16 usItemType )
{
for( UINT32 iNumber = 0 ; iNumber < pInventoryPoolList.size() ; ++iNumber)
{
if ( pInventoryPoolList [ iNumber ].object.usItem == usItemType )
{
DeleteObj( &pInventoryPoolList [ iNumber ].object );
}
}
}
extern UINT8 CurrentPlayerProgressPercentage(void);
INT32 SellItem( OBJECTTYPE& object, BOOLEAN useModifier )
{
INT32 iPrice = 0;
INT16 iPriceModifier = gGameExternalOptions.iPriceModifier;
UINT16 usItemType = object.usItem;
UINT16 itemPrice = Item[usItemType].usPrice;
//CHRISL: make price modifier based on current game progress
if(iPriceModifier == 0)
{
iPriceModifier = __max(1, (INT16)((CurrentPlayerProgressPercentage()/5)+.5));
}
else if(iPriceModifier == -1)
{
iPriceModifier = __max(1, (INT16)(((100-CurrentPlayerProgressPercentage())/5)+.5));
}
if( Item[ usItemType ].usItemClass == IC_AMMO )
{
//we are selling ammo
UINT16 magSize = Magazine[ Item[ usItemType ].ubClassIndex ].ubMagSize;
for (UINT8 ubLoop = 0; ubLoop < object.ubNumberOfObjects; ubLoop++)
{
iPrice += (INT32)( itemPrice * (float) object[ubLoop]->data.ubShotsLeft / magSize );
}
}
//CHRISL: If we're dealing with money, we want to use the money's amount and just return that value with no modification
else if(Item[usItemType].usItemClass == IC_MONEY)
{
for (UINT8 ubLoop = 0; ubLoop < object.ubNumberOfObjects; ubLoop++)
{
iPrice += (INT32)(object[ubLoop]->data.money.uiMoneyAmount);
}
return iPrice;
}
else if(Item[usItemType].usItemClass == IC_LBEGEAR && UsingNewInventorySystem() == true)
{
//CHRISL: If we're selling an LBE Item, we need to verify if it's an LBENODE, first. If it is, we need to sell
// everything stored in the LBENODE before we sell teh LBE Item itself.
for(UINT8 ubLoop = 0; ubLoop < object.ubNumberOfObjects; ubLoop++)
{
if(object.IsActiveLBE(ubLoop) == true)
{
LBENODE* pLBE = object.GetLBEPointer(ubLoop);
if(pLBE)
{
for(unsigned int x = 0; x < pLBE->inv.size(); x++)
{
if(pLBE->inv[x].exists() == true)
{
iPrice += SellItem(pLBE->inv[x], FALSE);
}
}
}
}
iPrice += ( itemPrice * object[ubLoop]->data.objectStatus / 100 );
for (attachmentList::iterator iter = object[ubLoop]->attachments.begin(); iter != object[ubLoop]->attachments.end(); ++iter) {
if(iter->exists())
iPrice += SellItem(*iter, FALSE);
}
}
}
else
{
//we are selling a gun or something - it could be stacked or single, and if single it could have attachments
for (UINT8 ubLoop = 0; ubLoop < object.ubNumberOfObjects; ubLoop++)
{
iPrice += ( itemPrice * object[ubLoop]->data.objectStatus / 100 );
for (attachmentList::iterator iter = object[ubLoop]->attachments.begin(); iter != object[ubLoop]->attachments.end(); ++iter) {
if(iter->exists())
iPrice += SellItem(*iter, FALSE);
}
}
}
if( iPriceModifier > 1 && useModifier == TRUE) {
iPrice /= iPriceModifier;
}
return iPrice;
}