Files
source/Tactical/ShopKeeper Interface.cpp
T
Overhaul d8145755c3 Added window around windowed JA2
Replaced Windows console with freeware console implementation.  Activate in windowed mode with \
Added error and quit if JA2 started in window mode in >16bpp color depth
Fix to enemy sector investigation:  Was deducting from redshirts when elites investigated
Fix AWOL militia (need additional fix to prevent them from being redistributed during after reinforcements)
Fix to tanks to add them in their original spot when a new one cannot be found.  Should modify to remove old wreckage in this case.
AI no longer tries to fire mortar when no room for it
Tanks no longer try to throw knives


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1030 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-07-08 07:02:56 +00:00

7883 lines
248 KiB
C++

// WANNE 2 <changed some lines>
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "Types.h"
#include "ShopKeeper Interface.h"
#include "Utilities.h"
#include "Game Clock.h"
#include "Render Dirty.h"
#include "wCheck.h"
#include "Font Control.h"
#include "WordWrap.h"
#include "Text Input.h"
#include "Interface.h"
#include "Interface Control.h"
#include "Overhead.h"
#include "Cursors.h"
//#include "Store Inventory.h"
#include "SysUtil.h"
#include "Interface Panels.h"
#include "Radar Screen.h"
#include "Interface Items.h"
#include "Interface Utils.h"
#include "VObject_Blitters.h"
#include "Finances.h"
#include "Text.h"
#include "Cursor Control.h"
#include "Input.h"
#include "Arms Dealer Init.h"
#include "english.h"
#include "Soldier Add.h"
#include "Faces.h"
#include "Dialogue Control.h"
#include "ShopKeeper Quotes.h"
#include "GameSettings.h"
#include "MercTextBox.h"
#include "Random.h"
#include "Squads.h"
#include "Soldier Profile.h"
#include "Message.h"
#include "Personnel.h"
#include "LaptopSave.h"
#include "Quests.h"
#include "Weapons.h"
#include "MessageBoxScreen.h"
#include "LINE.H"
#include "Drugs and Alcohol.h"
#include "Map Screen Interface.h"
#include "Soldier macros.h"
#include "armsdealerinvinit.h"
#include "opplist.h"
#include "los.h"
#include "NPC.h"
#include "Soldier Create.h"
#endif
#include "BuildDefines.h"
// temp
struct skirgbcolor
{
UINT8 ubRed;
UINT8 ubGreen;
UINT8 ubBlue;
};
typedef struct skirgbcolor SKIRGBCOLOR;
SKIRGBCOLOR SkiGlowColorsA[]={
{0,0,0},
{25,0,0},
{50,0,0},
{75,0,0},
{100,0,0},
{125,0,0},
{150,0,0},
{175,0,0},
{200,0,0},
{225,0,0},
{250,0,0},
};
////////////////////////////////////////////
//
// global defines
//
///////////////////////////////////////////
// WANNE 2
#define SKI_INTERFACE_WIDTH 536
#define SKI_INTERFACE_HEIGHT 340
#define SCREEN_X_OFFSET (((SCREEN_WIDTH - SKI_INTERFACE_WIDTH) / 2))
#define SCREEN_Y_OFFSET ((((SCREEN_HEIGHT - INV_INTERFACE_HEIGHT) - (SKI_INTERFACE_HEIGHT)) / 2))
#define SKI_BUTTON_FONT MILITARYFONT1//FONT14ARIAL
#define SKI_BUTTON_COLOR 73
#define SKI_ATM_BUTTON_FONT FONT10ARIAL
#define SKI_ATM_BUTTON_COLOR FONT_MCOLOR_BLACK
#define SKI_TITLE_FONT MILITARYFONT1//FONT14ARIAL
#define SKI_TITLE_COLOR 169//FONT_MCOLOR_LTYELLOW
#define SKI_LABEL_FONT MILITARYFONT1
#define SKI_ITEM_DESC_FONT SMALLCOMPFONT
#define SKI_ITEM_PRICE_COLOR FONT_MCOLOR_WHITE
#define SKIT_NUMBER_FONT BLOCKFONT2
#define SKI_MAIN_BACKGROUND_X SCREEN_X_OFFSET
#define SKI_MAIN_BACKGROUND_Y SCREEN_Y_OFFSET
#define SKI_FACE_X (SCREEN_X_OFFSET + 13)
#define SKI_FACE_Y (SCREEN_Y_OFFSET + 13)
#define SKI_FACE_WIDTH 90
#define SKI_FACE_HEIGHT 100
#define SKI_PAGE_UP_ARROWS_X (SCREEN_X_OFFSET + 121)
#define SKI_PAGE_UP_ARROWS_Y (SCREEN_Y_OFFSET + 35)
#define SKI_PAGE_DOWN_ARROWS_X SKI_PAGE_UP_ARROWS_X
#define SKI_PAGE_DOWN_ARROWS_Y (SCREEN_Y_OFFSET + 102)
//Evaluate:
//#define SKI_EVALUATE_BUTTON_X 15
//#define SKI_EVALUATE_BUTTON_Y 233
#define SKI_TRANSACTION_BUTTON_X (SCREEN_X_OFFSET + 147)//214
#define SKI_TRANSACTION_BUTTON_Y (SCREEN_Y_OFFSET +233)//SKI_EVALUATE_BUTTON_Y
#define SKI_DONE_BUTTON_X (SCREEN_X_OFFSET + 292)//414
#define SKI_DONE_BUTTON_Y (SCREEN_Y_OFFSET + 233)//SKI_EVALUATE_BUTTON_Y
#define SKI_MAIN_TITLE_X (SCREEN_X_OFFSET + 112)
#define SKI_MAIN_TITLE_Y (SCREEN_Y_OFFSET + 12)
#define SKI_MAIN_TITLE_WIDTH 420
#define SKI_TOTAL_COST_X (SCREEN_X_OFFSET + 9)
#define SKI_TOTAL_COST_Y (SCREEN_Y_OFFSET + 162)//159
#define SKI_TOTAL_COST_WIDTH 73
#define SKI_TOTAL_VALUE_X SKI_TOTAL_COST_X
#define SKI_TOTAL_VALUE_Y (SCREEN_Y_OFFSET + 291)//268
#define SKI_TOTAL_VALUE_WIDTH SKI_TOTAL_COST_WIDTH
#define SKI_PLAYERS_CURRENT_BALANCE_X SKI_TOTAL_COST_X
#define SKI_PLAYERS_CURRENT_BALANCE_Y (SCREEN_Y_OFFSET + 235)
#define SKI_PLAYERS_CURRENT_BALANCE_WIDTH SKI_TOTAL_COST_WIDTH
#define SKI_PLAYERS_CURRENT_BALANCE_OFFSET_TO_VALUE SCREEN_Y_OFFSET + 265
#define SKI_PAGE_X (SCREEN_X_OFFSET + 112)
#define SKI_PAGE_Y (SCREEN_Y_OFFSET + 70)
#define SKI_PAGE_WIDTH 45
#define SKI_PAGE_HEIGHT 27
//Number of Inventory slots
#define SKI_NUM_ARMS_DEALERS_INV_SLOTS 15
#define SKI_NUM_ARMS_DEALERS_INV_ROWS 3
#define SKI_NUM_ARMS_DEALERS_INV_COLS 5
//Inventory Slots size and offsets
#define SKI_INV_SLOT_WIDTH 67
#define SKI_INV_SLOT_HEIGHT 31
#define SKI_INV_HEIGHT SKI_INV_SLOT_HEIGHT - 7
#define SKI_INV_WIDTH 60
#define SKI_INV_PRICE_OFFSET_X 1
#define SKI_INV_PRICE_OFFSET_Y 24
#define SKI_INV_OFFSET_X 74
#define SKI_INV_OFFSET_Y 36
// the delay for glow cycling in glow areas, in millisecs
#define SKI_GLOW_DELAY 70
//Start Locations for the inventory boxes
#define SKI_ARMS_DEALERS_INV_START_X (SCREEN_X_OFFSET + 165)
#define SKI_ARMS_DEALERS_INV_START_Y (SCREEN_Y_OFFSET + 30)
#define SKI_ARMS_DEALERS_TRADING_INV_X (SCREEN_X_OFFSET + 91)
#define SKI_ARMS_DEALERS_TRADING_INV_Y (SCREEN_Y_OFFSET + 151)
#define SKI_ARMS_DEALERS_TRADING_INV_WIDTH 436
#define SKI_ARMS_DEALERS_TRADING_INV_HEIGHT 67
#define SKI_PLAYERS_TRADING_INV_X (SCREEN_X_OFFSET + 91)
#define SKI_PLAYERS_TRADING_INV_Y (SCREEN_Y_OFFSET + 266)
#define SKI_PLAYERS_TRADING_INV_HEIGHT 70
#define SKI_PLAYERS_TRADING_INV_WIDTH 440
#define SKI_ARMS_DEALER_TOTAL_COST_X (SCREEN_X_OFFSET + 16)
#define SKI_ARMS_DEALER_TOTAL_COST_Y (SCREEN_Y_OFFSET + 194)//191
#define SKI_ARMS_DEALER_TOTAL_COST_WIDTH 59
#define SKI_ARMS_DEALER_TOTAL_COST_HEIGHT 20
#define SKI_PLAYERS_TOTAL_VALUE_X (SCREEN_X_OFFSET + 16)
#define SKI_PLAYERS_TOTAL_VALUE_Y (SCREEN_Y_OFFSET + 310)//308
#define SKI_PLAYERS_TOTAL_VALUE_WIDTH 59
#define SKI_PLAYERS_TOTAL_VALUE_HEIGHT 20
#define SKI_TACTICAL_BACKGROUND_START_X (SCREEN_X_OFFSET + SKI_INTERFACE_WIDTH)
#define SKI_TACTICAL_BACKGROUND_START_Y 0
#define SKI_DROP_ITEM_TO_GROUND_START_X SKI_TACTICAL_BACKGROUND_START_X
#define SKI_DROP_ITEM_TO_GROUND_START_Y (SCREEN_Y_OFFSET + 262)
#define SKI_DROP_ITEM_TO_GROUND_TEXT_START_Y (SCREEN_Y_OFFSET + 262)
#define SKI_TACTICAL_BACKGROUND_START_WIDTH (SCREEN_WIDTH - SKI_TACTICAL_BACKGROUND_START_X)
#define SKI_TACTICAL_BACKGROUND_START_HEIGHT (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT)
#define SKI_ITEM_MOVEMENT_AREA_X (SCREEN_X_OFFSET + 85)
#define SKI_ITEM_MOVEMENT_AREA_Y (SCREEN_Y_OFFSET + 263)
#define SKI_ITEM_MOVEMENT_AREA_WIDTH (SCREEN_WIDTH - SKI_ITEM_MOVEMENT_AREA_X)
#define SKI_ITEM_MOVEMENT_AREA_HEIGHT (SCREEN_Y_OFFSET + 215)//72
#define SKI_DEALER_OFFER_AREA_Y (SCREEN_Y_OFFSET + 148)
#define SKI_ITEM_NUMBER_TEXT_OFFSET_X 50
#define SKI_ITEM_NUMBER_TEXT_OFFSET_Y 15
#define SKI_ITEM_NUMBER_TEXT_WIDTH 15
#define SKI_SUBTITLE_TEXT_SIZE 512
#define SKI_POSITION_SUBTITLES_Y (SCREEN_Y_OFFSET + INV_INTERFACE_HEIGHT)//100
#define SKI_SMALL_FACE_WIDTH 16
#define SKI_SMALL_FACE_HEIGHT 14
#define SKI_SMALL_FACE_OFFSET_X 52
#define SKI_SMALL_FACE_OFFSET_Y 17
#define SKI_ATTACHMENT_SYMBOL_X_OFFSET 56
#define SKI_ATTACHMENT_SYMBOL_Y_OFFSET 14
#define SKI_ATM_PANEL_X (SCREEN_X_OFFSET + 87)
#define SKI_ATM_PANEL_Y (SCREEN_Y_OFFSET + SKI_INTERFACE_HEIGHT)
#define SKI_ATM_PANEL_WIDTH 127
#define SKI_ATM_PANEL_HEIGHT 135
#define SKI_ATM_BUTTON_X SKI_ATM_PANEL_X + 23
#define SKI_ATM_BUTTON_Y SKI_ATM_PANEL_Y + 64
#define SKI_ATM_BUTTON_HEIGHT 15
#define SKI_ATM_NUM_BUTTON_WIDTH 15
#define SKI_ATM_SIDE_MENU_PANEL_START_X (SCREEN_X_OFFSET + 48)
#define SKI_TRANSFER_STRING_X SKI_ATM_PANEL_X + 22
#define SKI_TRANSFER_STRING_Y SKI_ATM_PANEL_Y + 50
#define SKI_TRANSFER_STRING_WIDTH 83
#define SKI_TRANSFER_STRING_HEIGHT 10
#define SKI_MERCS_MONEY_Y SKI_ATM_PANEL_Y + 11
#define SKI_MODE_TEXT_X SKI_TRANSFER_STRING_X
#define SKI_MODE_TEXT_Y SKI_ATM_PANEL_Y + 27
#define SKI_MODE_TEXT_WIDTH SKI_TRANSFER_STRING_WIDTH
#define SKI_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME 4
#define SKI_DEALERS_RANDOM_QUOTE_DELAY 15000
#define SKI_DEALERS_RANDOM_QUOTE_DELAY_INCREASE_RATE 5000
#define DELAY_FOR_SHOPKEEPER_IDLE_QUOTE 20000
#define CHANCE_FOR_SHOPKEEPER_IDLE_QUOTE 40
#define MAX_SUBOBJECTS_PER_OBJECT max( MAX_OBJECTS_PER_SLOT, ( 2 + MAX_ATTACHMENTS ) ) // (2nd part is main item, ammo/payload, and 4 attachments)
#define REALLY_BADLY_DAMAGED_THRESHOLD 30
#define REPAIR_DELAY_IN_HOURS 6
#define FLO_DISCOUNT_PERCENTAGE 10
////////////////////////////////////////////
//
// Global Variables
//
///////////////////////////////////////////
UINT32 guiMainTradeScreenImage;
UINT32 guiCornerWhereTacticalIsStillSeenImage; //This image is for where the corner of tactical is still seen through the shop keeper interface
//ATM:
//UINT32 guiSkiAtmImage;
BOOLEAN gfSKIScreenEntry = TRUE;
BOOLEAN gfSKIScreenExit = FALSE;
BOOLEAN gfUserHasRequestedToLeave = FALSE;
//BOOLEAN gfRedrawSkiScreen = TRUE;
BOOLEAN gfRenderScreenOnNextLoop = FALSE;
UINT8 gubSkiDirtyLevel = SKI_DIRTY_LEVEL0;
INT32 giSKIMessageBox=-1;
INT8 gbSelectedArmsDealerID = -1; //Contains the enum value for the currently selected arms dealer
//the quote that is in progress, in certain circumstances, we don't want queuing of related but different quotes
INT32 giShopKeepDialogueEventinProgress = - 1;
//OBJECTTYPE gpSkiItemPointer;
INVENTORY_IN_SLOT gMoveingItem;
OBJECTTYPE *gpHighLightedItemObject=NULL;
BOOLEAN gfResetShopKeepIdleQuote = FALSE;
BOOLEAN gfDoEvaluationAfterOpening = FALSE;
typedef struct
{
UINT32 uiNumDistinctInventoryItems;
UINT8 ubCurrentPage;
UINT8 ubNumberOfPages;
UINT8 ubFirstItemIndexOnPage;
} SELECTED_ARMS_DEALERS_STATS;
SELECTED_ARMS_DEALERS_STATS gSelectArmsDealerInfo;
//This pointer is used to store the inventory the arms dealer has for sale
INVENTORY_IN_SLOT *gpTempDealersInventory=NULL;
INVENTORY_IN_SLOT ArmsDealerOfferArea[ SKI_NUM_TRADING_INV_SLOTS ];
INVENTORY_IN_SLOT PlayersOfferArea[ SKI_NUM_TRADING_INV_SLOTS ];
OBJECTTYPE gSubObject[ MAX_SUBOBJECTS_PER_OBJECT ];
BOOLEAN gfHavePurchasedItemsFromTony = FALSE;
BOOLEAN gfDealerHasSaidTheEvaluateQuoteOnceThisSession=FALSE;
BOOLEAN gfAlreadySaidTooMuchToRepair = FALSE;
UINT32 guiRandomQuoteDelayTime=SKI_DEALERS_RANDOM_QUOTE_DELAY;
//Index for the shopkeepers face
INT32 giShopKeeperFaceIndex;
//Id for the popup box
INT32 giPopUpBoxId=-1;
BOOLEAN gfIsTheShopKeeperTalking;
// the glow for unwanted items
BOOLEAN fDeltaColorForShopkeepUnwanted = TRUE;
INT8 bShopKeepGlowIndex = 9;
BOOLEAN fDoShopkeepGlow = FALSE;
BOOLEAN gfRemindedPlayerToPickUpHisStuff = FALSE;
BOOLEAN gfDoneBusinessThisSession = FALSE;
// this is used within SKI exclusively, to handle small faces
UINT8 gubArrayOfEmployedMercs[ MAX_CHARACTER_COUNT ];
UINT32 guiSmallSoldiersFace[ MAX_CHARACTER_COUNT ];
UINT8 gubNumberMercsInArray;
//The subutitled text for what the merc is saying
CHAR16 gsShopKeeperTalkingText[ SKI_SUBTITLE_TEXT_SIZE ];
UINT16 gusPositionOfSubTitlesX=0;
// the transfer funds string
CHAR16 gzSkiAtmTransferString[ 32 ];
BOOLEAN gfExitSKIDueToMessageBox=FALSE;
OBJECTTYPE *pShopKeeperItemDescObject=NULL;
UINT32 guiNextFreeInvSlot;
BOOLEAN gfStartWithRepairsDelayedQuote = FALSE;
BOOLEAN gfPerformTransactionInProgress = FALSE;
BOOLEAN gfCommonQuoteUsedThisSession[ NUM_COMMON_SK_QUOTES ];
extern SOLDIERTYPE *gpSMCurrentMerc;
extern SOLDIERTYPE *gpItemDescSoldier;
extern MOUSE_REGION gItemDescAttachmentRegions[MAX_ATTACHMENTS];
extern MOUSE_REGION gInvDesc;
extern BOOLEAN gfSMDisableForItems;
extern OBJECTTYPE *gpItemDescObject;
extern void HandleShortCutExitState( void );
extern UINT8 gubSelectSMPanelToMerc;
extern INT32 giItemDescAmmoButton;
extern BOOLEAN BltVSurfaceUsingDD( HVSURFACE hDestVSurface, HVSURFACE hSrcVSurface, UINT32 fBltFlags, INT32 iDestX, INT32 iDestY, RECT *SrcRect );
extern UINT8 gubLastSpecialItemAddedAtElement;
//Enums for the various Atm modes
enum
{
SKI_ATM_DISABLED_MODE,
SKI_ATM_TAKE_MODE,
SKI_ATM_GIVE_MODE,
SKI_ATM_ERR_TAKE_MODE,
SKI_ATM_ERR_GIVE_MODE,
SKI_ATM_DISPLAY_PLAYERS_BALANCE,
};
UINT8 gubCurrentSkiAtmMode = SKI_ATM_DISABLED_MODE;
// Enums for possible evaluation results
enum
{
EVAL_RESULT_NORMAL,
EVAL_RESULT_OK_BUT_REALLY_DAMAGED,
EVAL_RESULT_DONT_HANDLE,
EVAL_RESULT_WORTHLESS,
EVAL_RESULT_NOT_DAMAGED,
EVAL_RESULT_NON_REPAIRABLE,
EVAL_RESULT_ROCKET_RIFLE,
NUM_EVAL_RESULTS
};
BOOLEAN gfEvalResultQuoteSaid[ NUM_EVAL_RESULTS ];
UINT32 guiLastTimeDealerSaidNormalEvaluationQuote = 0;
BOOLEAN gfSkiDisplayDropItemToGroundText = FALSE;
typedef struct
{
BOOLEAN fActive;
OBJECTTYPE ItemObject;
INT8 bPreviousInvPos;
} ITEM_TO_ADD_AFTER_SKI_OPEN;
ITEM_TO_ADD_AFTER_SKI_OPEN gItemToAdd;
//Page up buttons for the merchants
void BtnSKI_InvPageUpButtonCallback(GUI_BUTTON *btn,INT32 reason);
UINT32 guiSKI_InvPageUpButton;
INT32 guiSKI_InvPageUpButtonImage;
//Page down buttons for the merchants
void BtnSKI_InvPageDownButtonCallback(GUI_BUTTON *btn,INT32 reason);
UINT32 guiSKI_InvPageDownButton;
INT32 guiSKI_InvPageDownButtonImage;
/*
//Evaluate:
//Evaluate buttons
void BtnSKI_EvaluateButtonCallback(GUI_BUTTON *btn,INT32 reason);
UINT32 guiSKI_EvaluateButton;
INT32 guiSKI_EvaluateButtonImage;
*/
//Transaction buttons
void BtnSKI_TransactionButtonCallback(GUI_BUTTON *btn,INT32 reason);
UINT32 guiSKI_TransactionButton;
INT32 guiSKI_TransactionButtonImage;
//Done buttons
void BtnSKI_DoneButtonCallback(GUI_BUTTON *btn,INT32 reason);
UINT32 guiSKI_DoneButton;
INT32 guiSKI_DoneButtonImage;
//Atm buttons
void BtnSKI_AtmButtonCallback(GUI_BUTTON *btn,INT32 reason);
UINT32 guiSKI_AtmButton[ NUM_SKI_ATM_BUTTONS ];
INT32 guiSKI_AtmNumButtonImage;
INT32 guiSKI_AtmOkButtonImage;
INT32 guiSKI_AtmSideMenuButtonImage;
UINT32 guiItemCrossOut;
BOOLEAN gfDisplayNoRoomMsg = FALSE;
//Blanket the entire screen
MOUSE_REGION gSKI_EntireScreenMouseRegions;
MOUSE_REGION gDealersInventoryMouseRegions[ SKI_NUM_ARMS_DEALERS_INV_SLOTS ];
MOUSE_REGION gRepairmanInventorySmallFaceMouseRegions[ SKI_NUM_ARMS_DEALERS_INV_SLOTS ];
void SelectDealersInventoryRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
void SelectDealersInventoryMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
MOUSE_REGION gDealersOfferSlotsMouseRegions[ SKI_NUM_TRADING_INV_SLOTS ];
void SelectDealersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
void SelectDealersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
MOUSE_REGION gPlayersOfferSlotsMouseRegions[ SKI_NUM_TRADING_INV_SLOTS ];
void SelectPlayersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
void SelectPlayersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
MOUSE_REGION gDealersOfferSlotsSmallFaceMouseRegions[ SKI_NUM_TRADING_INV_SLOTS ];
MOUSE_REGION gPlayersOfferSlotsSmallFaceMouseRegions[ SKI_NUM_TRADING_INV_SLOTS ];
MOUSE_REGION gSkiInventoryMovementAreaMouseRegions;
//void SelectSkiInventoryMovementAreaRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
//Mouse region for the subtitles region when the merc is talking
MOUSE_REGION gShopKeeperSubTitleMouseRegion;
void ShopKeeperSubTitleRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
//ATM:
//MOUSE_REGION gShopKeeperCoverTacticalButtonMouseRegion;
MOUSE_REGION gArmsDealersFaceMouseRegions;
void SelectArmsDealersFaceRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
//Region to allow the user to drop items to the ground
MOUSE_REGION gArmsDealersDropItemToGroundMouseRegions;
void SelectArmsDealersDropItemToGroundRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
void SelectArmsDealersDropItemToGroundMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
////////////////////////////////////////////
//
// Local Function Prototypes
//
///////////////////////////////////////////
BOOLEAN EnterShopKeeperInterface();
BOOLEAN ExitShopKeeperInterface();
void HandleShopKeeperInterface();
BOOLEAN RenderShopKeeperInterface();
void GetShopKeeperInterfaceUserInput();
void DestroySkiInventorySlotMouseRegions( );
void CreateSkiInventorySlotMouseRegions( );
void InitializeShopKeeper( BOOLEAN fResetPage );
void CalculateFirstItemIndexOnPage( );
void DisplayArmsDealerCurrentInventoryPage( );
BOOLEAN DetermineArmsDealersSellingInventory( );
void StoreObjectsInNextFreeDealerInvSlot( UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, INT16 sSpecialItemElement, UINT8 ubHowMany, UINT8 ubOwner );
void AddItemsToTempDealerInventory(UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, INT16 sSpecialItemElement, UINT8 ubHowMany, UINT8 ubOwner );
BOOLEAN RepairIsDone(UINT16 usItemIndex, UINT8 ubElement);
UINT32 DisplayInvSlot( UINT8 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *ItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea );
void DisplayArmsDealerOfferArea();
INT8 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT8 bSlotIdInOtherLocation );
BOOLEAN RemoveItemFromArmsDealerOfferArea( INT8 bSlotId, BOOLEAN fKeepItem );
void SetSkiRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION* pRegion, UINT8 ubScreenArea );
void SetSkiFaceRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION* pRegion, UINT8 ubScreenArea );
void RestoreTacticalBackGround();
void DisplayPlayersOfferArea();
UINT32 CalcShopKeeperItemPrice( BOOLEAN fDealerSelling, BOOLEAN fUnitPriceOnly, UINT16 usItemID, FLOAT dModifier, OBJECTTYPE *pItemObject );
FLOAT ItemConditionModifier(UINT16 usItemIndex, INT16 bStatus);
BOOLEAN RemoveItemFromPlayersOfferArea( INT8 bSlotIdInOtherLocation );
//Evaluate:
//void EvaluateAllItemsInPlayersOfferArea( );
UINT32 CalculateTotalArmsDealerCost();
UINT32 CalculateTotalPlayersValue();
void MoveAllArmsDealersItemsInOfferAreaToPlayersOfferArea( );
void PerformTransaction( UINT32 uiMoneyFromPlayersAccount );
void MovePlayerOfferedItemsOfValueToArmsDealersInventory( );
INT8 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT8 ubSpotLocation, UINT8 ubWhere );
BOOLEAN RemoveItemFromDealersInventory( INVENTORY_IN_SLOT* pInvSlot, UINT8 ubSlot );
BOOLEAN InitShopKeepersFace( UINT8 ubMercID );
void DisplayTalkingArmsDealer();
BOOLEAN StartShopKeeperTalking( UINT16 usQuoteNum );
void HandleShopKeeperDialog( UINT8 ubInit );
BOOLEAN IsGunOrAmmoOfSameTypeSelected( OBJECTTYPE *pItemObject );
void RemoveShopKeeperSubTitledText();
BOOLEAN AreThereItemsInTheArmsDealersOfferArea( );
BOOLEAN AreThereItemsInThePlayersOfferArea( );
void ShutUpShopKeeper();
UINT8 CountNumberOfValuelessItemsInThePlayersOfferArea( );
UINT8 CountNumberOfItemsOfValueInThePlayersOfferArea( );
UINT8 CountNumberOfItemsInThePlayersOfferArea( );
UINT8 CountNumberOfItemsInTheArmsDealersOfferArea( );
INT8 GetSlotNumberForMerc( UINT8 ubProfile );
void RenderSkiAtmPanel();
void RemoveSkiAtmButtons();
void CreateSkiAtmButtons();
void AddNumberToSkiAtm( UINT8 ubNumber );
void HandleSkiAtmPanel( );
void DisplaySkiAtmTransferString();
void HandleSkiAtmPanelInput( UINT8 ubButtonPress );
void EnableDisableSkiAtmButtons();
void HandleCurrentModeText( UINT8 ubMode );
void ToggleSkiAtmButtons();
void HandleAtmOK();
void EnableDisableDealersInventoryPageButtons();
void EnableDisableEvaluateAndTransactionButtons();
BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( );
UINT32 CalculateHowMuchMoneyIsInPlayersOfferArea( );
void MovePlayersItemsToBeRepairedToArmsDealersInventory();
BOOLEAN RemoveRepairItemFromDealersOfferArea( INT8 bSlot );
INT8 GetInvSlotOfUnfullMoneyInMercInventory( SOLDIERTYPE *pSoldier );
void ClearPlayersOfferSlot( INT32 ubSlotToClear );
void ClearArmsDealerOfferSlot( INT32 ubSlotToClear );
void ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue );
BOOLEAN DoSkiMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback );
BOOLEAN WillShopKeeperRejectObjectsFromPlayer( INT8 bDealerId, INT8 bSlotId );
void CheckAndHandleClearingOfPlayerOfferArea( void );
void CrossOutUnwantedItems( void );
BOOLEAN CanShopkeeperOverrideDialogue( void );
INT16 GetNumberOfItemsInPlayerOfferArea( void );
void HandleCheckIfEnoughOnTheTable( void );
void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT8 ubPocket, UINT8 ubFromLocation );
void StartSKIDescriptionBox( void );
BOOLEAN ShopkeeperAutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNewItem );
void ShopkeeperAddItemToPool( INT16 sGridNo, OBJECTTYPE *pObject, INT8 bVisible, UINT8 ubLevel, UINT16 usFlags, INT8 bRenderZHeightAboveLevel );
void IfMercOwnedCopyItemToMercInv( INVENTORY_IN_SLOT *pInv );
void IfMercOwnedRemoveItemFromMercInv( INVENTORY_IN_SLOT *pInv );
void IfMercOwnedRemoveItemFromMercInv2( UINT8 ubOwnerProfileId, INT8 bOwnerSlotId );
void SplitComplexObjectIntoSubObjects( OBJECTTYPE *pComplexObject );
void CountSubObjectsInObject( OBJECTTYPE *pComplexObject, UINT8 *pubTotalSubObjects, UINT8 *pubRepairableSubObjects, UINT8 *pubNonRepairableSubObjects );
BOOLEAN AddObjectForEvaluation(OBJECTTYPE *pObject, UINT8 ubOwnerProfileId, INT8 bOwnerSlotId, BOOLEAN fFirstOne );
BOOLEAN OfferObjectToDealer( OBJECTTYPE *pComplexObject, UINT8 ubOwnerProfileId, INT8 bOwnerSlotId );
BOOLEAN SKITryToReturnInvToOwnerOrCurrentMerc( INVENTORY_IN_SLOT *pInv );
BOOLEAN SKITryToAddInvToMercsInventory( INVENTORY_IN_SLOT *pInv, SOLDIERTYPE *pSoldier );
void ExitSKIRequested();
void EvaluateItemAddedToPlayersOfferArea( INT8 bSlotID, BOOLEAN fFirstOne );
void ResetAllQuoteSaidFlags();
INVENTORY_IN_SLOT *GetPtrToOfferSlotWhereThisItemIs( UINT8 ubProfileID, INT8 bInvPocket );
void DealWithItemsStillOnTheTable();
void ReturnItemToPlayerSomehow( INVENTORY_IN_SLOT *pInvSlot, SOLDIERTYPE *pDropSoldier );
void GivePlayerSomeChange( UINT32 uiAmount );
void HandlePossibleRepairDelays();
BOOLEAN RepairmanFixingAnyItemsThatShouldBeDoneNow( UINT32 *puiHoursSinceOldestItemRepaired );
void DelayRepairsInProgressBy( UINT32 uiMinutesDelayed );
BOOLEAN CanTheDropItemToGroundStringBeDisplayed();
void DisplayTheSkiDropItemToGroundString();
UINT32 EvaluateInvSlot( INVENTORY_IN_SLOT *pInvSlot );
void BuildItemHelpTextString( CHAR16 sString[], INVENTORY_IN_SLOT *pInv, UINT8 ubScreenArea );
void BuildRepairTimeString( CHAR16 sString[], UINT32 uiTimeInMinutesToFixItem );
void BuildDoneWhenTimeString( CHAR16 sString[], UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubElement );
void DisableAllDealersInventorySlots( void );
void EnableAllDealersInventorySlots( void );
void DisableAllDealersOfferSlots( void );
void EnableAllDealersOfferSlots( void );
void HatchOutInvSlot( UINT16 usPosX, UINT16 usPosY );
extern BOOLEAN ItemIsARocketRifle( INT16 sItemIndex );
#ifdef JA2TESTVERSION
BOOLEAN gfTestDisplayDealerCash = FALSE;
void DisplayAllDealersCash();
#endif;
//ppp
//
// screen handler functions
//
UINT32 ShopKeeperScreenInit()
{
//Set so next time we come in, we can set up
gfSKIScreenEntry = TRUE;
return( TRUE );
}
UINT32 ShopKeeperScreenHandle()
{
StartFrameBufferRender();
if( gfSKIScreenEntry )
{
PauseGame();
if( !EnterShopKeeperInterface() )
{
gfSKIScreenExit = TRUE;
EnterTacticalScreen( );
return( SHOPKEEPER_SCREEN );
}
else
{
gfSKIScreenEntry = FALSE;
gfSKIScreenExit = FALSE;
}
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
gfRenderScreenOnNextLoop = TRUE;
InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
}
if( gfRenderScreenOnNextLoop )
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
RestoreBackgroundRects();
GetShopKeeperInterfaceUserInput();
// Check for any newly added items...
if ( gpSMCurrentMerc->fCheckForNewlyAddedItems )
{
// Startup any newly added items....
CheckForAnyNewlyAddedItems( gpSMCurrentMerc );
gpSMCurrentMerc->fCheckForNewlyAddedItems = FALSE;
}
HandleShopKeeperInterface();
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
RenderShopKeeperInterface();
fInterfacePanelDirty = DIRTYLEVEL2;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL0;
}
else if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL1 )
{
fInterfacePanelDirty = DIRTYLEVEL2;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL0;
}
// render buttons marked dirty
//ATM:
DisableSMPpanelButtonsWhenInShopKeeperInterface( FALSE );
RenderButtons( );
// render help
SaveBackgroundRects( );
RenderButtonsFastHelp( );
ExecuteBaseDirtyRectQueue();
EndFrameBufferRender();
if( gfSKIScreenExit )
{
ExitShopKeeperInterface();
gfSKIScreenExit = FALSE;
gfSKIScreenEntry = TRUE;
EnterTacticalScreen( );
UnPauseGame();
}
if ( gfDisplayNoRoomMsg )
{
// tell player there's not enough room in the player's offer area
// ARM: message is delayed because we need the mouse restriction to be in place BEFORE it comes up so it gets lifted/restored
DoSkiMessageBox( MSG_BOX_BASIC_STYLE, SKI_Text[ SKI_TEXT_NO_MORE_ROOM_IN_PLAYER_OFFER_AREA ], SHOPKEEPER_SCREEN, MSG_BOX_FLAG_OK, NULL );
gfDisplayNoRoomMsg = FALSE;
}
return( SHOPKEEPER_SCREEN );
}
UINT32 ShopKeeperScreenShutdown()
{
ShutDownArmsDealers();
return( TRUE );
}
//
//
//
BOOLEAN EnterShopKeeperInterface()
{
VOBJECT_DESC VObjectDesc;
UINT8 ubCnt;
CHAR8 zTemp[32];
VSURFACE_DESC vs_desc;
SOLDIERTYPE *pSoldier;
// make sure current merc is close enough and eligible to talk to the shopkeeper.
AssertMsg( CanMercInteractWithSelectedShopkeeper( MercPtrs[ gusSelectedSoldier ] ), "Selected merc can't interact with shopkeeper. Send save AM-1");
// Create a video surface to blt corner of the tactical screen that still shines through
vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE;
vs_desc.usWidth = SKI_TACTICAL_BACKGROUND_START_WIDTH;
vs_desc.usHeight = SKI_TACTICAL_BACKGROUND_START_HEIGHT;
vs_desc.ubBitDepth = 16;
if( !AddVideoSurface( &vs_desc, &guiCornerWhereTacticalIsStillSeenImage) )
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to create Surface where tactical map shows through" );
#endif
return( FALSE );
}
//Clear out all the save background rects
EmptyBackgroundRects( );
// WANNE 2
ShadowVideoSurfaceRect( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - INV_INTERFACE_HEIGHT );
if( gfExitSKIDueToMessageBox )
{
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
gfExitSKIDueToMessageBox = FALSE;
}
//Check to make sure the inventory is null ( should always be null if we are just coming in to the SKI )
Assert( gpTempDealersInventory == NULL );
//Reinitialize the team panel to be the SM panel
SetCurrentInterfacePanel( SM_PANEL );
SetCurrentTacticalPanelCurrentMerc( (UINT8)gusSelectedSoldier );
SetSMPanelCurrentMerc( (UINT8)gusSelectedSoldier );
// load the Main trade screen backgroiund image
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP("InterFace\\TradeScreen.sti", VObjectDesc.ImageFile);
if( !AddVideoObject(&VObjectDesc, &guiMainTradeScreenImage ))
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to load TradeScreen.sti" );
#endif
return( FALSE );
}
// load the Main trade screen background image
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP("InterFace\\itemcrossout.sti", VObjectDesc.ImageFile);
if( !AddVideoObject(&VObjectDesc, &guiItemCrossOut ))
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to load itemcrossout.sti" );
#endif
return( FALSE );
}
/*
ATM:
// load the Main trade screen backgroiund image
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP("InterFace\\TradeScreenAtm.sti", VObjectDesc.ImageFile);
CHECKF(AddVideoObject(&VObjectDesc, &guiSkiAtmImage ));
*/
//Create an array of all mercs (anywhere!) currently in the player's employ, and load their small faces
// This is to support showing of repair item owner's faces even when they're not in the sector, as long as they still work for player
gubNumberMercsInArray = 0;
for( ubCnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; ubCnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; ubCnt++ )
{
pSoldier = MercPtrs[ ubCnt ];
if( pSoldier->bActive && ( pSoldier->ubProfile != NO_PROFILE ) &&
!(pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) && !AM_A_ROBOT( pSoldier ) )
{
// remember whose face is in this slot
gubArrayOfEmployedMercs[ gubNumberMercsInArray ] = pSoldier->ubProfile;
//Create the string for the face file name
sprintf( zTemp, "FACES\\33FACE\\%02d.sti", gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex );
//While we are at it, add their small face
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
FilenameForBPP( zTemp, VObjectDesc.ImageFile);
if(!AddVideoObject(&VObjectDesc, &guiSmallSoldiersFace[ gubNumberMercsInArray ] ))
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to load %s", zTemp );
#endif
return( FALSE );
}
gubNumberMercsInArray++;
}
}
//Load the graphic for the arrow button
guiSKI_InvPageUpButtonImage = LoadButtonImage("INTERFACE\\TradeScrollArrows.sti", -1,0,-1,1,-1 );
guiSKI_InvPageDownButtonImage = UseLoadedButtonImage( guiSKI_InvPageUpButtonImage, -1,2,-1,3,-1 );
//Page up button for the merchant inventory
guiSKI_InvPageUpButton = QuickCreateButton( guiSKI_InvPageUpButtonImage, SKI_PAGE_UP_ARROWS_X, SKI_PAGE_UP_ARROWS_Y,
BUTTON_NEWTOGGLE, MSYS_PRIORITY_HIGHEST,
DEFAULT_MOVE_CALLBACK, BtnSKI_InvPageUpButtonCallback );
SpecifyDisabledButtonStyle( guiSKI_InvPageUpButton, DISABLED_STYLE_HATCHED );
//Page down button for the merchant inventory
guiSKI_InvPageDownButton = QuickCreateButton( guiSKI_InvPageDownButtonImage, SKI_PAGE_DOWN_ARROWS_X, SKI_PAGE_DOWN_ARROWS_Y,
BUTTON_NEWTOGGLE, MSYS_PRIORITY_HIGHEST,
DEFAULT_MOVE_CALLBACK, BtnSKI_InvPageDownButtonCallback );
SpecifyDisabledButtonStyle( guiSKI_InvPageDownButton, DISABLED_STYLE_HATCHED );
//Evaluate:
// guiSKI_EvaluateButtonImage = LoadButtonImage("INTERFACE\\TradeButtons.sti", -1,0,-1,1,-1 );
// guiSKI_TransactionButtonImage = UseLoadedButtonImage( guiSKI_EvaluateButtonImage, -1,0,-1,1,-1 );
guiSKI_TransactionButtonImage = LoadButtonImage("INTERFACE\\TradeButtons.sti", -1,0,-1,1,-1 );
guiSKI_DoneButtonImage = UseLoadedButtonImage( guiSKI_TransactionButtonImage, -1,0,-1,1,-1 );
/*
//Evaluate:
//Evaluate button
guiSKI_EvaluateButton = CreateIconAndTextButton( guiSKI_EvaluateButtonImage, SKI_Text[SKI_TEXT_EVALUATE], SKI_BUTTON_FONT,
SKI_BUTTON_COLOR, DEFAULT_SHADOW,
SKI_BUTTON_COLOR, DEFAULT_SHADOW,
TEXT_CJUSTIFIED,
SKI_EVALUATE_BUTTON_X, SKI_EVALUATE_BUTTON_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH,
DEFAULT_MOVE_CALLBACK, BtnSKI_EvaluateButtonCallback);
SpecifyDisabledButtonStyle( guiSKI_EvaluateButton, DISABLED_STYLE_HATCHED );
*/
//Transaction button
guiSKI_TransactionButton = CreateIconAndTextButton( guiSKI_TransactionButtonImage, SKI_Text[SKI_TEXT_TRANSACTION], SKI_BUTTON_FONT,
SKI_BUTTON_COLOR, DEFAULT_SHADOW,
SKI_BUTTON_COLOR, DEFAULT_SHADOW,
TEXT_CJUSTIFIED,
SKI_TRANSACTION_BUTTON_X, SKI_TRANSACTION_BUTTON_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH,
DEFAULT_MOVE_CALLBACK, BtnSKI_TransactionButtonCallback);
SpecifyDisabledButtonStyle( guiSKI_TransactionButton, DISABLED_STYLE_HATCHED );
//if the dealer repairs, use the repair fast help text for the transaction button
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
SetButtonFastHelpText( guiSKI_TransactionButton, SkiMessageBoxText[ SKI_REPAIR_TRANSACTION_BUTTON_HELP_TEXT ] );
else
SetButtonFastHelpText( guiSKI_TransactionButton, SkiMessageBoxText[ SKI_TRANSACTION_BUTTON_HELP_TEXT ] );
//Done button
guiSKI_DoneButton = CreateIconAndTextButton( guiSKI_DoneButtonImage, SKI_Text[SKI_TEXT_DONE], SKI_BUTTON_FONT,
SKI_BUTTON_COLOR, DEFAULT_SHADOW,
SKI_BUTTON_COLOR, DEFAULT_SHADOW,
TEXT_CJUSTIFIED,
SKI_DONE_BUTTON_X, SKI_DONE_BUTTON_Y, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH+10,
DEFAULT_MOVE_CALLBACK, BtnSKI_DoneButtonCallback);
SpecifyDisabledButtonStyle( guiSKI_DoneButton, DISABLED_STYLE_HATCHED );
SetButtonFastHelpText( guiSKI_DoneButton, SkiMessageBoxText[ SKI_DONE_BUTTON_HELP_TEXT ] );
//Blanket the entire screen
MSYS_DefineRegion( &gSKI_EntireScreenMouseRegions, 0, 0, (SCREEN_WIDTH - 1), (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT), MSYS_PRIORITY_HIGH-2,
CURSOR_NORMAL, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
MSYS_AddRegion( &gSKI_EntireScreenMouseRegions );
/*
//ATM:
//Blanket the tactical buttons where the ATM will go
MSYS_DefineRegion( &gShopKeeperCoverTacticalButtonMouseRegion, SKI_ATM_PANEL_X, SKI_ATM_PANEL_Y, (UINT16)(SKI_ATM_PANEL_X+SKI_ATM_PANEL_WIDTH), (UINT16)(SKI_ATM_PANEL_Y+SKI_ATM_PANEL_HEIGHT), MSYS_PRIORITY_HIGH-1,
CURSOR_NORMAL, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK);
MSYS_AddRegion( &gSKI_EntireScreenMouseRegions );
*/
//Create the mouse regions for the inventory slot
CreateSkiInventorySlotMouseRegions( );
//Create the mouse region to limit the movement of the item cursos
MSYS_DefineRegion( &gSkiInventoryMovementAreaMouseRegions, SKI_ITEM_MOVEMENT_AREA_X, SKI_ITEM_MOVEMENT_AREA_Y, (UINT16)(SKI_ITEM_MOVEMENT_AREA_X+SKI_ITEM_MOVEMENT_AREA_WIDTH), (UINT16)(SKI_ITEM_MOVEMENT_AREA_Y+SKI_ITEM_MOVEMENT_AREA_HEIGHT), MSYS_PRIORITY_HIGH-1,
CURSOR_NORMAL, MSYS_NO_CALLBACK, MSYS_NO_CALLBACK ); //SelectSkiInventoryMovementAreaRegionCallBack
MSYS_AddRegion( &gSkiInventoryMovementAreaMouseRegions );
//Disable the region that limits the movement of the cursor with the item
MSYS_DisableRegion( &gSkiInventoryMovementAreaMouseRegions );
//Create the mouse region for the shopkeeper's face
MSYS_DefineRegion( &gArmsDealersFaceMouseRegions, SKI_FACE_X, SKI_FACE_Y, (UINT16)(SKI_FACE_X+SKI_FACE_WIDTH), (UINT16)(SKI_FACE_Y+SKI_FACE_HEIGHT), MSYS_PRIORITY_HIGH-1,
CURSOR_NORMAL, MSYS_NO_CALLBACK, SelectArmsDealersFaceRegionCallBack );
MSYS_AddRegion( &gArmsDealersFaceMouseRegions );
//Create the atm button
//ATM:
// CreateSkiAtmButtons();
memset( ArmsDealerOfferArea, 0, sizeof( INVENTORY_IN_SLOT ) * SKI_NUM_TRADING_INV_SLOTS );
memset( PlayersOfferArea, 0, sizeof( INVENTORY_IN_SLOT ) * SKI_NUM_TRADING_INV_SLOTS );
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
HandlePossibleRepairDelays();
}
//Setup the currently selected arms dealer
InitializeShopKeeper( TRUE );
//Set the flag indicating that we are in the shop keeper interface
guiTacticalInterfaceFlags |= INTERFACE_SHOPKEEP_INTERFACE;
memset( &gMoveingItem, 0, sizeof( INVENTORY_IN_SLOT ) );
memset( &gfCommonQuoteUsedThisSession, FALSE, sizeof( gfCommonQuoteUsedThisSession ) );
//Init the shopkeepers face
InitShopKeepersFace( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID );
gfDoneBusinessThisSession = FALSE;
//Call this to set the fact that we just entered the screen
HandleShopKeeperDialog( 1 );
ResetAllQuoteSaidFlags();
//Reset the highlighted item pointer;
gpHighLightedItemObject = NULL;
//Reset
gfRemindedPlayerToPickUpHisStuff = FALSE;
gfUserHasRequestedToLeave = FALSE;
gubCurrentSkiAtmMode = SKI_ATM_DISABLED_MODE;
gfDisplayNoRoomMsg = FALSE;
//Disable the map radar region
MSYS_DisableRegion(&gRadarRegion);
gfDoEvaluationAfterOpening = FALSE;
if( gItemToAdd.fActive )
{
BOOLEAN fAddedOK = FALSE;
INT8 bSlotNum = gItemToAdd.bPreviousInvPos;
//if this is NOT a repair dealer or he is is but there is enough space in the player's offer area
// (you can't be out of space if it isn't a repairman, only they can fill it up with repaired items!)
if( ( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS ) ||
( CountNumberOfItemsInThePlayersOfferArea( ) < SKI_NUM_ARMS_DEALERS_INV_SLOTS ) )
{
// if we're supposed to store the original pocket #, but that pocket still holds more of these
if ( ( bSlotNum != -1 ) && ( gpSMCurrentMerc->inv[ bSlotNum ].ubNumberOfObjects > 0 ) )
{
// then we can't store the pocket #, because our system can't return stacked objects
bSlotNum = -1;
}
if ( OfferObjectToDealer( &(gItemToAdd.ItemObject), gpSMCurrentMerc->ubProfile, bSlotNum ) )
{
fAddedOK = TRUE;
}
}
if ( fAddedOK )
{
// evaluate it
gfDoEvaluationAfterOpening = TRUE;
}
else
{
//add the item back to the current PC into the slot it came from
CopyObj( &gItemToAdd.ItemObject, &Menptr[ gpSMCurrentMerc->ubID ].inv[ gItemToAdd.bPreviousInvPos ] );
}
//Clear the contents of the structure
memset( &gItemToAdd, 0, sizeof( ITEM_TO_ADD_AFTER_SKI_OPEN ) );
gItemToAdd.fActive = FALSE;
}
// Dirty the bottom panel
fInterfacePanelDirty = DIRTYLEVEL2;
gfDealerHasSaidTheEvaluateQuoteOnceThisSession = FALSE;
guiRandomQuoteDelayTime = SKI_DEALERS_RANDOM_QUOTE_DELAY;
pShopKeeperItemDescObject = NULL;
//Region to allow the user to drop items to the ground
MSYS_DefineRegion( &gArmsDealersDropItemToGroundMouseRegions, SKI_DROP_ITEM_TO_GROUND_START_X, SKI_DROP_ITEM_TO_GROUND_START_Y, SCREEN_WIDTH - 1, SCREEN_HEIGHT - INV_INTERFACE_HEIGHT, MSYS_PRIORITY_HIGH,
CURSOR_NORMAL, SelectArmsDealersDropItemToGroundMovementRegionCallBack, SelectArmsDealersDropItemToGroundRegionCallBack );
// CURSOR_NORMAL, MSYS_NO_CALLBACK, SelectArmsDealersDropItemToGroundRegionCallBack );
MSYS_AddRegion( &gArmsDealersDropItemToGroundMouseRegions );
gfSkiDisplayDropItemToGroundText = FALSE;
// by default re-enable calls to PerformTransaction()
gfPerformTransactionInProgress = FALSE;
return( TRUE );
}
BOOLEAN InitShopKeepersFace( UINT8 ubMercID )
{
SOLDIERTYPE *pSoldier = FindSoldierByProfileID( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID, FALSE );
if( pSoldier == NULL )
{
#ifdef JA2TESTVERSION
//Create the facial index
giShopKeeperFaceIndex = InitFace( ubMercID, NOBODY, FACE_BIGFACE );
#else
return( FALSE );
#endif
}
else
{
//Create the facial index
giShopKeeperFaceIndex = InitFace( ubMercID, pSoldier->ubID, FACE_BIGFACE );
}
SetAutoFaceActive( FRAME_BUFFER, FACE_AUTO_RESTORE_BUFFER, giShopKeeperFaceIndex, SKI_FACE_X, SKI_FACE_Y );
//Set it so the face cannot be set InActive
gFacesData[ giShopKeeperFaceIndex ].uiFlags |= FACE_INACTIVE_HANDLED_ELSEWHERE;
RenderAutoFace( giShopKeeperFaceIndex );
return(TRUE);
}
BOOLEAN ExitShopKeeperInterface()
{
UINT8 ubCnt;
if( gfExitSKIDueToMessageBox )
{
gfSKIScreenExit = FALSE;
// gfExitSKIDueToMessageBox = FALSE;
}
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
{
DeleteItemDescriptionBox( );
}
FreeMouseCursor();
//Delete the main shopkeep background
DeleteVideoObjectFromIndex( guiMainTradeScreenImage );
DeleteVideoObjectFromIndex( guiItemCrossOut );
DeleteVideoSurfaceFromIndex( guiCornerWhereTacticalIsStillSeenImage );
ShutUpShopKeeper();
//Delete the Atm backgorund
//ATM:
// DeleteVideoObjectFromIndex( guiSkiAtmImage );
UnloadButtonImage( guiSKI_InvPageUpButtonImage );
UnloadButtonImage( guiSKI_InvPageDownButtonImage );
UnloadButtonImage( guiSKI_TransactionButtonImage );
// UnloadButtonImage( guiSKI_EvaluateButtonImage );
UnloadButtonImage( guiSKI_DoneButtonImage );
//loop through the area and delete small faces
for(ubCnt=0; ubCnt<gubNumberMercsInArray; ubCnt++)
{
DeleteVideoObjectFromIndex( guiSmallSoldiersFace[ ubCnt ] );
}
RemoveButton( guiSKI_InvPageUpButton );
RemoveButton( guiSKI_InvPageDownButton );
//Evaluate:
// RemoveButton( guiSKI_EvaluateButton );
RemoveButton( guiSKI_TransactionButton );
RemoveButton( guiSKI_DoneButton );
MSYS_RemoveRegion( &gSKI_EntireScreenMouseRegions);
MSYS_RemoveRegion( &gSkiInventoryMovementAreaMouseRegions );
//ATM:
// MSYS_RemoveRegion( &gShopKeeperCoverTacticalButtonMouseRegion );
//Remove the region for the face
MSYS_RemoveRegion( &gArmsDealersFaceMouseRegions );
//Remove the Atm buttons
//ATM:
// RemoveSkiAtmButtons();
//Region to allow the user to drop items to the ground
MSYS_RemoveRegion( &gArmsDealersDropItemToGroundMouseRegions );
//Destroy the mouse regions for the inventory slots
DestroySkiInventorySlotMouseRegions( );
//if there is a temp inventory array, destroy it
if( gpTempDealersInventory )
{
MemFree( gpTempDealersInventory );
gpTempDealersInventory = NULL;
}
//Set the flag indicating that we are NOT in the shop keeper interface
guiTacticalInterfaceFlags &= ~INTERFACE_SHOPKEEP_INTERFACE;
//if there is a subtitles box up, remove it
RemoveShopKeeperSubTitledText();
//Get rid of the ShopKeeper face
DeleteFace( giShopKeeperFaceIndex );
//Enable the map region
MSYS_EnableRegion(&gRadarRegion);
gfSMDisableForItems = FALSE;
return( TRUE );
}
void HandleShopKeeperInterface()
{
UINT8 ubStatusOfSkiRenderDirtyFlag = gubSkiDirtyLevel;
INT32 iCounter = 0;
//if we are in the item desc panel, disable the buttons
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
{
DisableSMPpanelButtonsWhenInShopKeeperInterface( FALSE );
DisableButton( guiSKI_InvPageUpButton );
DisableButton( guiSKI_InvPageDownButton );
DisableButton( guiSKI_TransactionButton );
DisableButton( guiSKI_DoneButton );
//make sure the buttons dont render
// ButtonList[ guiSKI_InvPageUpButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
// ButtonList[ guiSKI_InvPageDownButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
ButtonList[ guiSKI_TransactionButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
ButtonList[ guiSKI_DoneButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
// make sure the shop keeper doesn't start talking ( reset the timing variable )
HandleShopKeeperDialog( 2 );
return;
}
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
fInterfacePanelDirty = DIRTYLEVEL2;
}
RenderTacticalInterface( );
if ( InItemStackPopup( ) )
{
if ( fInterfacePanelDirty == DIRTYLEVEL2 )
{
RenderItemStackPopup( TRUE );
}
else
{
RenderItemStackPopup( FALSE );
}
}
// handle check if enough on the table
HandleCheckIfEnoughOnTheTable( );
// Render view window
fInterfacePanelDirty = DIRTYLEVEL2;
RenderRadarScreen( );
if( fInterfacePanelDirty == DIRTYLEVEL2 )
{
fInterfacePanelDirty = DIRTYLEVEL0;
}
RenderClock( CLOCK_X, CLOCK_Y );
RenderTownIDString( );
//ATM:
// RenderSkiAtmPanel();
DisplayTalkingArmsDealer();
DisplayArmsDealerCurrentInventoryPage( );
DisplayArmsDealerOfferArea();
DisplayPlayersOfferArea();
EnableDisableEvaluateAndTransactionButtons();
MarkButtonsDirty( );
if( gfDoEvaluationAfterOpening )
{
BOOLEAN fFirstOne = TRUE;
gfDoEvaluationAfterOpening = FALSE;
for( iCounter = 0; iCounter < SKI_NUM_TRADING_INV_SLOTS; iCounter++ )
{
if( PlayersOfferArea[ iCounter ].fActive )
{
EvaluateItemAddedToPlayersOfferArea( ( INT8 ) iCounter, fFirstOne );
fFirstOne = FALSE;
}
}
gfAlreadySaidTooMuchToRepair = FALSE;
}
#ifdef JA2TESTVERSION
if ( gfTestDisplayDealerCash )
DisplayAllDealersCash();
#endif
//if the Ski dirty flag was changed to a lower value, make sure it is set properly
if( ubStatusOfSkiRenderDirtyFlag > gubSkiDirtyLevel )
gubSkiDirtyLevel = ubStatusOfSkiRenderDirtyFlag;
//if the merc is talking and there is an item currently being highlighted
// ( this gets rid of the item burning through the dealers text box )
if( gfIsTheShopKeeperTalking )
if( gpHighLightedItemObject != NULL || gubSkiDirtyLevel != SKI_DIRTY_LEVEL0 )
RenderMercPopUpBoxFromIndex( giPopUpBoxId, gusPositionOfSubTitlesX, SKI_POSITION_SUBTITLES_Y, FRAME_BUFFER);
//if we are to display the drop item to ground text
if( gfSkiDisplayDropItemToGroundText )
{
DisplayTheSkiDropItemToGroundString();
}
}
BOOLEAN RenderShopKeeperInterface()
{
HVOBJECT hPixHandle;
CHAR16 zMoney[128];
HVSURFACE hDestVSurface, hSrcVSurface;
SGPRect SrcRect;
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
{
return( TRUE );
}
// RenderSMPanel( &fDirty );
// RenderTacticalInterface( );
// Render view window
// RenderRadarScreen( );
//Get the main background screen graphic and blt it
GetVideoObject(&hPixHandle, guiMainTradeScreenImage );
BltVideoObject(FRAME_BUFFER, hPixHandle, 0,SKI_MAIN_BACKGROUND_X, SKI_MAIN_BACKGROUND_Y, VO_BLT_SRCTRANSPARENCY,NULL);
//Display the Title
DrawTextToScreen( SKI_Text[ SKI_TEXT_MERCHADISE_IN_STOCK ], SKI_MAIN_TITLE_X, SKI_MAIN_TITLE_Y, SKI_MAIN_TITLE_WIDTH, SKI_TITLE_FONT, SKI_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//Display the Repair cost text
DisplayWrappedString( SKI_TOTAL_COST_X, SKI_TOTAL_COST_Y, SKI_TOTAL_COST_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[ SKI_TEXT_REPAIR_COST ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED);
}
else
{
//Display the Total cost text
DisplayWrappedString( SKI_TOTAL_COST_X, SKI_TOTAL_COST_Y, SKI_TOTAL_COST_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[ SKI_TEXT_TOTAL_COST ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED);
}
//Display the total value text
DisplayWrappedString( SKI_TOTAL_VALUE_X, SKI_TOTAL_VALUE_Y, SKI_TOTAL_VALUE_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[ SKI_TEXT_TOTAL_VALUE ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
//Display the players current balance text
DisplayWrappedString( SKI_PLAYERS_CURRENT_BALANCE_X, SKI_PLAYERS_CURRENT_BALANCE_Y, SKI_PLAYERS_CURRENT_BALANCE_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SkiMessageBoxText[ SKI_PLAYERS_CURRENT_BALANCE ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
//Display the players current balance value
swprintf( zMoney, L"%d", LaptopSaveInfo.iCurrentBalance );
InsertCommasForDollarFigure( zMoney );
InsertDollarSignInToString( zMoney );
DrawTextToScreen( zMoney, SKI_PLAYERS_CURRENT_BALANCE_X, SKI_PLAYERS_CURRENT_BALANCE_OFFSET_TO_VALUE, SKI_PLAYERS_CURRENT_BALANCE_WIDTH, FONT10ARIAL, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, TRUE, CENTER_JUSTIFIED );
BlitBufferToBuffer( guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SKI_TACTICAL_BACKGROUND_START_X, SKI_TACTICAL_BACKGROUND_START_HEIGHT );
//At this point the background is pure, copy it to the save buffer
if( gfRenderScreenOnNextLoop )
{
// BlitBufferToBuffer( guiRENDERBUFFER, guiCornerWhereTacticalIsStillSeenImage, SKI_TACTICAL_BACKGROUND_START_X, SKI_TACTICAL_BACKGROUND_START_Y, SKI_TACTICAL_BACKGROUND_START_WIDTH, SKI_TACTICAL_BACKGROUND_START_HEIGHT );
GetVideoSurface( &hDestVSurface, guiCornerWhereTacticalIsStillSeenImage );
GetVideoSurface( &hSrcVSurface, guiSAVEBUFFER );
SrcRect.iLeft = SKI_TACTICAL_BACKGROUND_START_X;
SrcRect.iTop = SKI_TACTICAL_BACKGROUND_START_Y;
SrcRect.iRight = SKI_TACTICAL_BACKGROUND_START_X + SKI_TACTICAL_BACKGROUND_START_WIDTH;
SrcRect.iBottom = SKI_TACTICAL_BACKGROUND_START_Y + SKI_TACTICAL_BACKGROUND_START_HEIGHT;
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, SKI_TACTICAL_BACKGROUND_START_X, SKI_TACTICAL_BACKGROUND_START_Y, (RECT*)&SrcRect );
gfRenderScreenOnNextLoop = FALSE;
}
DisplayArmsDealerCurrentInventoryPage( );
DisplayArmsDealerOfferArea();
DisplayPlayersOfferArea();
//if the merc is talking and the screen has been dirtied
if( gfIsTheShopKeeperTalking )
RenderMercPopUpBoxFromIndex( giPopUpBoxId, gusPositionOfSubTitlesX, SKI_POSITION_SUBTITLES_Y, FRAME_BUFFER);
CrossOutUnwantedItems( );
//Render the clock and the town name
RenderClock( CLOCK_X, CLOCK_Y );
RenderTownIDString( );
// RenderTacticalInterface( );
// RenderSMPanel( &fDirty );
//Restore the tactical background that is visble behind the SKI panel
RestoreTacticalBackGround();
InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
return( TRUE );
}
void RestoreTacticalBackGround()
{
HVSURFACE hDestVSurface, hSrcVSurface;
SGPRect SrcRect;
GetVideoSurface( &hDestVSurface, guiRENDERBUFFER );
GetVideoSurface( &hSrcVSurface, guiCornerWhereTacticalIsStillSeenImage );
// WANNE 2
// Top
SrcRect.iLeft = SKI_TACTICAL_BACKGROUND_START_X; //0;
SrcRect.iTop = SKI_TACTICAL_BACKGROUND_START_Y; //0;
SrcRect.iRight = SKI_TACTICAL_BACKGROUND_START_WIDTH; //SKI_TACTICAL_BACKGROUND_START_WIDTH;
SrcRect.iBottom = SKI_TACTICAL_BACKGROUND_START_HEIGHT; //SKI_TACTICAL_BACKGROUND_START_HEIGHT;
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, SKI_TACTICAL_BACKGROUND_START_X, SKI_TACTICAL_BACKGROUND_START_Y, (RECT*)&SrcRect );
// WANNE 2
//InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
}
void GetShopKeeperInterfaceUserInput()
{
InputAtom Event;
POINT MousePos;
GetCursorPos(&MousePos);
ScreenToClient(ghWindow, &MousePos); // In window coords!
while( DequeueEvent( &Event ) )
{
// HOOK INTO MOUSE HOOKS
/* removed warning condition C4060 (jonathanl)
switch( Event.usEvent)
{
}
*/
if( !HandleTextInput( &Event ) && Event.usEvent == KEY_DOWN )
{
/*
//ATM:
//if the number entered was a number
if( (Event.usParam >= '0' ) && ( Event.usParam <= '9') )
{
UINT8 ubValue = 0;
ubValue = ( INT8 )( Event.usParam - '0' );
AddNumberToSkiAtm( ubValue );
}
*/
switch( Event.usParam )
{
case ESC:
// clean exits - does quotes, shuts up shopkeeper, etc.
ExitSKIRequested();
#ifdef JA2TESTVERSION
//Instant exit - doesn't clean up much
// gfSKIScreenExit = TRUE;
#endif
break;
case 'x':
if( Event.usKeyState & ALT_DOWN )
{
HandleShortCutExitState( );
}
break;
case SPACE:
{
UINT8 ubID;
DeleteItemDescriptionBox( );
// skip Robot and EPCs
ubID = FindNextActiveAndAliveMerc( gpSMCurrentMerc, FALSE, TRUE );
gubSelectSMPanelToMerc = ubID;
LocateSoldier( ubID, DONTSETLOCATOR );
// refresh background for player slots (in case item values change due to Flo's discount)
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
break;
#ifdef JA2TESTVERSION
case 'r':
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
break;
case 'i':
InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
break;
case 'd':
//Test key to toggle the display of the money each dealer has on hand
gfTestDisplayDealerCash ^= 1;
break;
#endif
}
}
}
}
#ifdef JA2TESTVERSION
void DisplayAllDealersCash()
{
INT8 bArmsDealer;
UINT16 usPosY=0;
CHAR16 zTemp[512];
UINT8 ubForeColor;
//loop through all the shopkeeper's and display their money
for( bArmsDealer=0; bArmsDealer<NUM_ARMS_DEALERS; bArmsDealer++ )
{
//Display the shopkeeper's name
DrawTextToScreen( gMercProfiles[ ArmsDealerInfo[ bArmsDealer ].ubShopKeeperID ].zNickname, SCREEN_X_OFFSET + 540, SCREEN_Y_OFFSET + usPosY, 0, FONT10ARIAL, SKI_TITLE_COLOR, FONT_MCOLOR_BLACK, TRUE, LEFT_JUSTIFIED );
//Display the arms dealer cash on hand
swprintf( zTemp, L"%d", gArmsDealerStatus[ bArmsDealer ].uiArmsDealersCash );
InsertCommasForDollarFigure( zTemp );
InsertDollarSignInToString( zTemp );
ubForeColor = ( UINT8 ) ( ( bArmsDealer == gbSelectedArmsDealerID ) ? SKI_BUTTON_COLOR : SKI_TITLE_COLOR );
DrawTextToScreen( zTemp, SCREEN_X_OFFSET + 590, SCREEN_Y_OFFSET + usPosY, 0, FONT10ARIAL, ubForeColor, FONT_MCOLOR_BLACK, TRUE, LEFT_JUSTIFIED );
usPosY += 17;
}
}
#endif
void BtnSKI_InvPageUpButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= BUTTON_CLICKED_ON;
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
btn->uiFlags &= (~BUTTON_CLICKED_ON );
if( gSelectArmsDealerInfo.ubCurrentPage > 1 )
{
gSelectArmsDealerInfo.ubCurrentPage--;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
EnableDisableDealersInventoryPageButtons();
}
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
}
void BtnSKI_InvPageDownButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= BUTTON_CLICKED_ON;
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
btn->uiFlags &= (~BUTTON_CLICKED_ON );
if( gSelectArmsDealerInfo.ubCurrentPage < gSelectArmsDealerInfo.ubNumberOfPages )
{
gSelectArmsDealerInfo.ubCurrentPage++;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
EnableDisableDealersInventoryPageButtons();
}
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
}
/*
//Evaluate:
void BtnSKI_EvaluateButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= BUTTON_CLICKED_ON;
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
btn->uiFlags &= (~BUTTON_CLICKED_ON );
ShutUpShopKeeper();
EvaluateAllItemsInPlayersOfferArea( );
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
}
*/
void BtnSKI_TransactionButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= BUTTON_CLICKED_ON;
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
btn->uiFlags &= (~BUTTON_CLICKED_ON );
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
// if not already doing it (multiple clicks can be queued up while shopkeeper is still talking)
if ( !gfPerformTransactionInProgress )
{
// shut him up
ShutUpShopKeeper();
giShopKeepDialogueEventinProgress = -1;
PerformTransaction( 0 );
}
}
}
void BtnSKI_DoneButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= BUTTON_CLICKED_ON;
}
if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
btn->uiFlags &= (~BUTTON_CLICKED_ON );
ExitSKIRequested();
}
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
void CreateSkiInventorySlotMouseRegions( )
{
UINT8 x,y,ubCnt;
UINT16 usPosX, usPosY;
// Create the mouse regions for the shopkeeper's inventory
usPosY = SKI_ARMS_DEALERS_INV_START_Y;
ubCnt=0;
for(y=0; y<SKI_NUM_ARMS_DEALERS_INV_ROWS; y++)
{
usPosX = SKI_ARMS_DEALERS_INV_START_X;
for(x=0; x<SKI_NUM_ARMS_DEALERS_INV_COLS; x++)
{
MSYS_DefineRegion( &gDealersInventoryMouseRegions[ ubCnt ], usPosX, usPosY, (INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + SKI_INV_SLOT_HEIGHT), MSYS_PRIORITY_HIGH,
CURSOR_NORMAL, SelectDealersInventoryMovementRegionCallBack, SelectDealersInventoryRegionCallBack );
MSYS_AddRegion( &gDealersInventoryMouseRegions[ubCnt] );
MSYS_SetRegionUserData( &gDealersInventoryMouseRegions[ ubCnt ], 0, ubCnt);
MSYS_SetRegionUserData( &gDealersInventoryMouseRegions[ ubCnt ], 1, ARMS_DEALER_INVENTORY );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//Small Faces
MSYS_DefineRegion( &gRepairmanInventorySmallFaceMouseRegions[ ubCnt ], (UINT16)(usPosX+SKI_SMALL_FACE_OFFSET_X), (UINT16)(usPosY), (INT16)(usPosX + SKI_SMALL_FACE_OFFSET_X + SKI_SMALL_FACE_WIDTH), (INT16)(usPosY+ SKI_SMALL_FACE_HEIGHT), MSYS_PRIORITY_HIGH+1,
CURSOR_NORMAL, NULL, NULL );
MSYS_AddRegion( &gRepairmanInventorySmallFaceMouseRegions[ ubCnt ] );
MSYS_SetRegionUserData( &gRepairmanInventorySmallFaceMouseRegions[ ubCnt ], 0, ubCnt );
MSYS_SetRegionUserData( &gRepairmanInventorySmallFaceMouseRegions[ ubCnt ], 1, ARMS_DEALER_INVENTORY );
}
usPosX += SKI_INV_OFFSET_X;
ubCnt++;
}
usPosY += SKI_INV_OFFSET_Y;
}
// Create the mouse regions for the shopkeeper's trading slots
usPosY = SKI_ARMS_DEALERS_TRADING_INV_Y;
ubCnt=0;
for(y=0; y<SKI_NUM_TRADING_INV_ROWS; y++)
{
usPosX = SKI_ARMS_DEALERS_TRADING_INV_X;
for(x=0; x<SKI_NUM_TRADING_INV_COLS; x++)
{
MSYS_DefineRegion( &gDealersOfferSlotsMouseRegions[ ubCnt ], usPosX, usPosY, (INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + SKI_INV_SLOT_HEIGHT), MSYS_PRIORITY_HIGH,
CURSOR_NORMAL, SelectDealersOfferSlotsMovementRegionCallBack, SelectDealersOfferSlotsRegionCallBack );
MSYS_AddRegion( &gDealersOfferSlotsMouseRegions[ubCnt] );
MSYS_SetRegionUserData( &gDealersOfferSlotsMouseRegions[ ubCnt ], 0, ubCnt);
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//Small Faces
MSYS_DefineRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ ubCnt ], (UINT16)(usPosX+SKI_SMALL_FACE_OFFSET_X), (UINT16)(usPosY), (INT16)(usPosX + SKI_SMALL_FACE_OFFSET_X + SKI_SMALL_FACE_WIDTH), (INT16)(usPosY+ SKI_SMALL_FACE_HEIGHT), MSYS_PRIORITY_HIGH+1,
CURSOR_NORMAL, SelectDealersOfferSlotsMovementRegionCallBack, SelectDealersOfferSlotsRegionCallBack );
MSYS_AddRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ubCnt] );
MSYS_SetRegionUserData( &gDealersOfferSlotsSmallFaceMouseRegions[ ubCnt ], 0, ubCnt);
MSYS_SetRegionUserData( &gDealersOfferSlotsSmallFaceMouseRegions[ ubCnt ], 1, ARMS_DEALER_OFFER_AREA );
}
usPosX += SKI_INV_OFFSET_X;
ubCnt++;
}
usPosY += SKI_INV_OFFSET_Y;
}
// Create the mouse regions for the Players trading slots
usPosY = SKI_PLAYERS_TRADING_INV_Y;
ubCnt=0;
for(y=0; y<SKI_NUM_TRADING_INV_ROWS; y++)
{
usPosX = SKI_PLAYERS_TRADING_INV_X;
for(x=0; x<SKI_NUM_TRADING_INV_COLS; x++)
{
//Trading Slots
MSYS_DefineRegion( &gPlayersOfferSlotsMouseRegions[ ubCnt ], usPosX, usPosY, (INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + SKI_INV_SLOT_HEIGHT), MSYS_PRIORITY_HIGH,
CURSOR_NORMAL, SelectPlayersOfferSlotsMovementRegionCallBack, SelectPlayersOfferSlotsRegionCallBack );
MSYS_AddRegion( &gPlayersOfferSlotsMouseRegions[ubCnt] );
MSYS_SetRegionUserData( &gPlayersOfferSlotsMouseRegions[ ubCnt ], 0, ubCnt);
/*
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_SetRegionUserData( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubCnt ], 1, PLAYERS_OFFER_AREA );
}
*/
//Small Faces
MSYS_DefineRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubCnt ], (UINT16)(usPosX+SKI_SMALL_FACE_OFFSET_X), (UINT16)(usPosY), (INT16)(usPosX + SKI_SMALL_FACE_OFFSET_X + SKI_SMALL_FACE_WIDTH), (INT16)(usPosY+ SKI_SMALL_FACE_HEIGHT), MSYS_PRIORITY_HIGH+1,
CURSOR_NORMAL, SelectPlayersOfferSlotsMovementRegionCallBack, SelectPlayersOfferSlotsRegionCallBack );
MSYS_AddRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ubCnt] );
MSYS_SetRegionUserData( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubCnt ], 0, ubCnt);
MSYS_SetRegionUserData( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubCnt ], 1, PLAYERS_OFFER_AREA );
usPosX += SKI_INV_OFFSET_X;
ubCnt++;
}
usPosY += SKI_INV_OFFSET_Y;
}
}
void DestroySkiInventorySlotMouseRegions( )
{
UINT8 i;
for(i=0; i<SKI_NUM_ARMS_DEALERS_INV_SLOTS; i++)
{
MSYS_RemoveRegion( &gDealersInventoryMouseRegions[ i ] );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_RemoveRegion( &gRepairmanInventorySmallFaceMouseRegions[ i ] );
}
}
for(i=0; i<SKI_NUM_TRADING_INV_SLOTS; i++)
{
MSYS_RemoveRegion( &gDealersOfferSlotsMouseRegions[ i ] );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_RemoveRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ i ] );
}
MSYS_RemoveRegion( &gPlayersOfferSlotsMouseRegions[ i ] );
MSYS_RemoveRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ i ] );
}
}
//Mouse Call back for the Arms traders inventory slot
void SelectDealersInventoryRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
INT8 ubLocation;
if( gpTempDealersInventory == NULL )
return;
ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
//if the selected slot is above any inventory we have, return
if( ubSelectedInvSlot >= gSelectArmsDealerInfo.uiNumDistinctInventoryItems )
return;
//if there are any items still there
if( gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects > 0 )
{
//If the item type has not already been placed
if( !( gpTempDealersInventory[ ubSelectedInvSlot ].uiFlags & ARMS_INV_ITEM_SELECTED ) )
{
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
// ignore left clicks on items under repair. Fully repaired items are moved out to player's slots automatically
}
else // not a repairman
{
ubLocation = AddItemToArmsDealerOfferArea( &gpTempDealersInventory[ ubSelectedInvSlot ], ubSelectedInvSlot );
//if the item was added to the Dealer Offer Area correctly
if( ubLocation != -1 )
{
//Set the flag indicating the item has been selected
gpTempDealersInventory[ ubSelectedInvSlot ].uiFlags |= ARMS_INV_ITEM_SELECTED;
//Specify the location the items went to
gpTempDealersInventory[ ubSelectedInvSlot ].ubLocationOfObject = ARMS_DEALER_OFFER_AREA;
gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation = ubLocation;
//if the shift key is being pressed, remove them all
if( gfKeyState[ SHIFT ] )
{
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects = 0;
}
else
{
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects --;
}
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
}
else // some of this item are already in dealer's offer area
{
UINT8 ubNumToMove;
//if the shift key is being pressed, remove them all
if( gfKeyState[ SHIFT ] )
{
ubNumToMove = gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects;
}
else
{
ubNumToMove = 1;
}
//Reduce the number in dealer's inventory
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects -= ubNumToMove;
//Increase the number in dealer's offer area
ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ubNumberOfObjects += ubNumToMove;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
}
else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
if( gpTempDealersInventory == NULL )
return;
ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
//if the selected slot is above any inventory we have, return
if( ubSelectedInvSlot >= gSelectArmsDealerInfo.uiNumDistinctInventoryItems )
return;
//DEF:
//bring up the item description box
if ( !InItemDescriptionBox( ) )
{
InitShopKeeperItemDescBox( &gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject, ubSelectedInvSlot, ARMS_DEALER_INVENTORY );
}
else
{
DeleteItemDescriptionBox( );
}
/*
//if the item has been seleceted
if( gpTempDealersInventory[ ubSelectedInvSlot ].uiFlags & ARMS_INV_ITEM_SELECTED )
{
//Check to see it there is more then 1 item in the location
if( ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ubNumberOfObjects > 0 )
{
//Increase the number in the dealer inventory
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects ++;
//Decrease the number in the dealer offer area
ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ubNumberOfObjects--;
//if there is nothing left in the arms dealer offer area
if( ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ubNumberOfObjects == 0 )
{
RemoveItemFromArmsDealerOfferArea( gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation, FALSE );
}
//redraw the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
*/
}
}
void SelectDealersInventoryMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
if( gpTempDealersInventory == NULL )
return;
if( ubSelectedInvSlot >= gSelectArmsDealerInfo.uiNumDistinctInventoryItems )
return;
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
{
//if there is nothing in the slot, exit
if( gpTempDealersInventory[ ubSelectedInvSlot ].fActive == FALSE )
return;
gpHighLightedItemObject = &gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject;
HandleCompatibleAmmoUI( gpSMCurrentMerc, -1, TRUE );
}
else if(iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
//if there is nothing in the slot, exit
if( gpTempDealersInventory[ ubSelectedInvSlot ].fActive == FALSE )
return;
gpHighLightedItemObject = NULL;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL1; //ddd
HandleCompatibleAmmoUI( gpSMCurrentMerc, -1, FALSE );
}
}
void SelectDealersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
{
//if there is nothing in the slot, exit
if( ArmsDealerOfferArea[ ubSelectedInvSlot ].fActive == FALSE )
return;
gpHighLightedItemObject = &ArmsDealerOfferArea[ ubSelectedInvSlot ].ItemObject;
HandleCompatibleAmmoUI( gpSMCurrentMerc, -1, TRUE );
}
else if(iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
//if there is nothing in the slot, exit
if( ArmsDealerOfferArea[ ubSelectedInvSlot ].fActive == FALSE )
return;
gpHighLightedItemObject = NULL;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL1;//ddd
HandleCompatibleAmmoUI( gpSMCurrentMerc, -1, FALSE );
}
}
void SelectPlayersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
{
//if there is nothing in the slot, exit
if( PlayersOfferArea[ ubSelectedInvSlot ].fActive == FALSE )
return;
gpHighLightedItemObject = &PlayersOfferArea[ ubSelectedInvSlot ].ItemObject;
HandleCompatibleAmmoUI( gpSMCurrentMerc, -1, TRUE );
}
else if(iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
//if there is nothing in the slot, exit
if( PlayersOfferArea[ ubSelectedInvSlot ].fActive == FALSE )
return;
gpHighLightedItemObject = NULL;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL1;//ddd
HandleCompatibleAmmoUI( gpSMCurrentMerc, -1, FALSE );
}
}
//Mouse Call back for the dealer's OFFER slot
void SelectDealersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP )
{
//if there is something here
if( ArmsDealerOfferArea[ ubSelectedInvSlot ].fActive )
{
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
// return item to player
RemoveRepairItemFromDealersOfferArea( ubSelectedInvSlot );
}
else
{
//bring up the item description box
if ( !InItemDescriptionBox( ) )
{
InitShopKeeperItemDescBox( &ArmsDealerOfferArea[ ubSelectedInvSlot ].ItemObject, ubSelectedInvSlot, ARMS_DEALER_OFFER_AREA );
}
else
{
DeleteItemDescriptionBox( );
}
}
}
}
else if( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP ) //MSYS_CALLBACK_REASON_LBUTTON_UP)
{
/*
//if the current merc is disabled for whatever reason
if( gfSMDisableForItems )
// the
return;
*/
//if there is something here
if( ArmsDealerOfferArea[ ubSelectedInvSlot ].fActive )
{
//if this is a repair dealer
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//if we don't have an item, pick one up
if( gMoveingItem.sItemIndex == 0 )
{
//if the dealer is a repair dealer, allow the player to pick up the item
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
BeginSkiItemPointer( ARMS_DEALER_OFFER_AREA, ubSelectedInvSlot, FALSE );
}
}
else
{
//swap what is in the cursor with what is in the player offer slot
INVENTORY_IN_SLOT TempSlot;
// if the slot is overloaded (holds more objects than we have room for valid statuses of)
if ( ArmsDealerOfferArea[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects > MAX_OBJECTS_PER_SLOT )
{
// then ignore the click - we can't do the swap, or anything very useful, because we can't allow overloaded
// items into the player's cursor - if he put them into a merc's inventory, the extra statuses are missing!
// At best, we could do some sort of message here.
return;
}
IfMercOwnedCopyItemToMercInv( &gMoveingItem );
memcpy( &TempSlot, &ArmsDealerOfferArea[ ubSelectedInvSlot ], sizeof( INVENTORY_IN_SLOT ) );
memcpy( &ArmsDealerOfferArea[ ubSelectedInvSlot ], &gMoveingItem, sizeof( INVENTORY_IN_SLOT ) );
memcpy( &gMoveingItem, &TempSlot, sizeof( INVENTORY_IN_SLOT ) );
IfMercOwnedRemoveItemFromMercInv( &gMoveingItem );
// Change mouse cursor
gpItemPointer = &gMoveingItem.ItemObject;
SetSkiCursor( EXTERN_CURSOR );
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
else //non-repairman
{
//if the shift key is being pressed, remove them all
if( gfKeyState[ SHIFT ] || ( ArmsDealerOfferArea[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects == 1 ) )
{
RemoveItemFromArmsDealerOfferArea( ubSelectedInvSlot, TRUE );//ArmsDealerOfferArea[ ubSelectedInvSlot ].bSlotIdInOtherLocation
}
else // multiple items there, SHIFT isn't being pressed
{
// remove only one at a time
ArmsDealerOfferArea[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects--;
gpTempDealersInventory[ ArmsDealerOfferArea[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ubNumberOfObjects++;
}
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
else // empty slot
{
//if the cursor has something in it
if( gMoveingItem.sItemIndex > 0 )
{
// we'd better talking to a repairman, cursor is locked out of this area while full for non-repairmen!
Assert( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS );
//Drop the item into the current slot
AddInventoryToSkiLocation( &gMoveingItem, ubSelectedInvSlot, ARMS_DEALER_OFFER_AREA );
//Reset the cursor
SetSkiCursor( CURSOR_NORMAL );
//refresh the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
}
}
//Mouse Call back for the Players OFFER slot
void SelectPlayersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
UINT8 ubSelectedInvSlot = (UINT8)MSYS_GetRegionUserData( pRegion, 0 );
INT8 bAddedToSlotID = -1;
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
//if the cursor has no item in it
if( gMoveingItem.sItemIndex == 0 )
{
//if there is nothing here, return
if( PlayersOfferArea[ ubSelectedInvSlot ].fActive == FALSE )
return;
// pick it up into the cursor
BeginSkiItemPointer( PLAYERS_OFFER_AREA, ubSelectedInvSlot, FALSE );
}
else // we have something in the cursor
{
//Drop the item into the current slot
// AddObjectToSkiLocation( &gpSkiItemPointer, ubSelectedInvSlot, PLAYERS_OFFER_AREA );
//if there is something already there
if( PlayersOfferArea[ ubSelectedInvSlot ].fActive )
{
//swap what is in the cursor with what is in the player offer slot
INVENTORY_IN_SLOT TempSlot;
// if the slot is overloaded (holds more objects than we have room for valid statuses of)
if ( PlayersOfferArea[ ubSelectedInvSlot ].ItemObject.ubNumberOfObjects > MAX_OBJECTS_PER_SLOT )
{
// then ignore the click - we can't do the swap, or anything very useful, because we can't allow overloaded
// items into the player's cursor - if he put them into a merc's inventory, the extra statuses are missing!
// At best, we could do some sort of message here.
return;
}
IfMercOwnedCopyItemToMercInv( &gMoveingItem );
memcpy( &TempSlot, &PlayersOfferArea[ ubSelectedInvSlot ], sizeof( INVENTORY_IN_SLOT ) );
memcpy( &PlayersOfferArea[ ubSelectedInvSlot ], &gMoveingItem, sizeof( INVENTORY_IN_SLOT ) );
memcpy( &gMoveingItem, &TempSlot, sizeof( INVENTORY_IN_SLOT ) );
IfMercOwnedRemoveItemFromMercInv( &gMoveingItem );
// Change mouse cursor
gpItemPointer = &gMoveingItem.ItemObject;
SetSkiCursor( EXTERN_CURSOR );
//if the item we are adding is money
if( Item[ PlayersOfferArea[ ubSelectedInvSlot ].sItemIndex ].usItemClass == IC_MONEY )
{
//Since money is always evaluated
PlayersOfferArea[ ubSelectedInvSlot ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
PlayersOfferArea[ ubSelectedInvSlot ].uiItemPrice = PlayersOfferArea[ ubSelectedInvSlot ].ItemObject.bMoneyStatus;
}
}
else // slot is empty
{
// if the item has already been evaluated, or has just been purchased
if ( ( gMoveingItem.uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_BEEN_EVALUATED ) ||
( gMoveingItem.uiFlags & ARMS_INV_JUST_PURCHASED ) )
{
//place the item that is in the player's hand into this player offer area slot
bAddedToSlotID = AddInventoryToSkiLocation( &gMoveingItem, ubSelectedInvSlot, PLAYERS_OFFER_AREA );
Assert ( bAddedToSlotID != -1 );
}
else
{
// this splits complex items for repairs. Also puts things into the first free POA slot
OfferObjectToDealer( &gMoveingItem.ItemObject, gMoveingItem.ubIdOfMercWhoOwnsTheItem, gMoveingItem.bSlotIdInOtherLocation );
}
//Reset the cursor
SetSkiCursor( CURSOR_NORMAL );
}
//Dirty the interface
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
else if(iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) //MSYS_CALLBACK_REASON_LBUTTON_UP)
{
//if the box is active
if( PlayersOfferArea[ ubSelectedInvSlot ].fActive )
{
RemoveItemFromPlayersOfferArea( ubSelectedInvSlot );
/*
item description
else
{
if ( !InItemDescriptionBox( ) )
{
InitItemDescriptionBox( gpSMCurrentMerc, (UINT8)PlayersOfferArea[ ubSelectedInvSlot ].bSlotIdInOtherLocation, 214, 1 + INV_INTERFACE_START_Y, 0 );
}
else
{
DeleteItemDescriptionBox( );
}
}
*/
}
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
void SelectSkiInventoryMovementAreaRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
}
}
void EnterShopKeeperInterfaceScreen( UINT8 ubArmsDealer )
{
//Get Dealer ID from from merc Id
gbSelectedArmsDealerID = GetArmsDealerIDFromMercID( ubArmsDealer );
if( gbSelectedArmsDealerID == -1 )
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to find Arms Dealer ID From Merc ID #%d", ubArmsDealer );
#endif
gfSKIScreenExit = TRUE;
}
LeaveTacticalScreen( SHOPKEEPER_SCREEN );
}
void InitializeShopKeeper( BOOLEAN fResetPage )
{
// update time player last dealt with him
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiTimePlayerLastInSKI = GetWorldTotalMin();
//Get the number of distinct items in the inventory
gSelectArmsDealerInfo.uiNumDistinctInventoryItems = CountDistinctItemsInArmsDealersInventory( gbSelectedArmsDealerID );
// If there are any items in the dealer's inventory
if( gSelectArmsDealerInfo.uiNumDistinctInventoryItems > 0 )
{
//Create the shopkeeper's temp inventory
DetermineArmsDealersSellingInventory( );
/* No longer necessary. ARM
//Some of the number might have changed in DetermineArmsDealersSellingInventory(), recalc the values
gSelectArmsDealerInfo.uiNumDistinctInventoryItems = CountDistinctItemsInArmsDealersInventory( gbSelectedArmsDealerID );
*/
}
gSelectArmsDealerInfo.ubNumberOfPages = (UINT8)( gSelectArmsDealerInfo.uiNumDistinctInventoryItems / SKI_NUM_ARMS_DEALERS_INV_SLOTS );
if( gSelectArmsDealerInfo.uiNumDistinctInventoryItems % 15 != 0 )
gSelectArmsDealerInfo.ubNumberOfPages += 1;
//Should we reset the current inventory page being displayed
if( gSelectArmsDealerInfo.uiNumDistinctInventoryItems == 0 )
gSelectArmsDealerInfo.ubCurrentPage = 0;
else
{
if( fResetPage )
{
if( gSelectArmsDealerInfo.uiNumDistinctInventoryItems == 0 )
gSelectArmsDealerInfo.ubCurrentPage = 0;
else
gSelectArmsDealerInfo.ubCurrentPage = 1;
}
//or if the current page will be an invalid page ( before the first, and after the last )
else if( gSelectArmsDealerInfo.ubCurrentPage < 0 || gSelectArmsDealerInfo.ubCurrentPage > gSelectArmsDealerInfo.ubNumberOfPages )
{
gSelectArmsDealerInfo.ubCurrentPage = 1;
}
else if( gSelectArmsDealerInfo.uiNumDistinctInventoryItems != 0 )
gSelectArmsDealerInfo.ubCurrentPage = 1;
}
//if there is no inventory
if( gSelectArmsDealerInfo.uiNumDistinctInventoryItems == 0 )
{
gSelectArmsDealerInfo.ubCurrentPage = 0;
gSelectArmsDealerInfo.ubNumberOfPages = 0;
//disable the page up/down buttons
DisableButton( guiSKI_InvPageUpButton );
DisableButton( guiSKI_InvPageDownButton );
return;
}
else
{
//enable the page up/down buttons
EnableButton( guiSKI_InvPageUpButton );
EnableButton( guiSKI_InvPageDownButton );
}
EnableDisableDealersInventoryPageButtons();
}
void CalculateFirstItemIndexOnPage( )
{
gSelectArmsDealerInfo.ubFirstItemIndexOnPage = ( gSelectArmsDealerInfo.ubCurrentPage -1 ) * SKI_NUM_ARMS_DEALERS_INV_SLOTS;
}
void DisplayArmsDealerCurrentInventoryPage( )
{
CHAR16 zTemp[32];
UINT16 uiFontHeight;
UINT16 usCnt=0;
UINT16 usPosX, usPosY;
UINT8 sItemCount=0;
BOOLEAN fDisplayHatchOnItem=FALSE;
usPosX = SKI_ARMS_DEALERS_INV_START_X;
usPosY = SKI_ARMS_DEALERS_INV_START_Y;
//if there is any inventory
if( gpTempDealersInventory != NULL )
{
if( gubSkiDirtyLevel != SKI_DIRTY_LEVEL0 )
{
//Calculate the item that is at the top of the list
CalculateFirstItemIndexOnPage( );
//Restore the background before blitting the text back on
RestoreExternBackgroundRect( SKI_PAGE_X, SKI_PAGE_Y, SKI_PAGE_WIDTH, SKI_PAGE_HEIGHT );
//Restore the pristine region
RestoreExternBackgroundRect( SKI_ARMS_DEALERS_INV_START_X, SKI_ARMS_DEALERS_INV_START_Y, 370, 107 );
//Display the current inventory page
DrawTextToScreen( SKI_Text[ SKI_TEXT_PAGE ], SKI_PAGE_X, (UINT16)(SKI_PAGE_Y+3), SKI_PAGE_WIDTH, SKI_LABEL_FONT, SKI_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
//Display the Current Page number
uiFontHeight = GetFontHeight( SKI_LABEL_FONT );
swprintf( zTemp, L"%d/%d", gSelectArmsDealerInfo.ubCurrentPage, gSelectArmsDealerInfo.ubNumberOfPages );
DrawTextToScreen( zTemp, SKI_PAGE_X, (UINT16)(SKI_PAGE_Y+uiFontHeight+6), SKI_PAGE_WIDTH, SKI_LABEL_FONT, SKI_TITLE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
}
//Display all the items for the current page
for( usCnt=gSelectArmsDealerInfo.ubFirstItemIndexOnPage; ( ( usCnt<gSelectArmsDealerInfo.uiNumDistinctInventoryItems ) && ( sItemCount < SKI_NUM_ARMS_DEALERS_INV_SLOTS ) ); usCnt++ )
{
//if the item is still in the inventory
if( gpTempDealersInventory[ usCnt ].sItemIndex != 0 )
{
// hatch it out if region is disabled
if ( !( gDealersInventoryMouseRegions[ sItemCount ].uiFlags & MSYS_REGION_ENABLED ) )
{
fDisplayHatchOnItem = TRUE;
}
//if the dealer repairs
else if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//if the item is damaged
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].uiFlags & ARMS_INV_ITEM_NOT_REPAIRED_YET )
fDisplayHatchOnItem = TRUE;
else
fDisplayHatchOnItem = FALSE;
}
else // non-repairman
{
// check if none left
if ( gpTempDealersInventory[ usCnt ].ItemObject.ubNumberOfObjects == 0 )
{
fDisplayHatchOnItem = TRUE;
}
else
{
fDisplayHatchOnItem = FALSE;
}
}
// Display the inventory slot
DisplayInvSlot( (UINT8)usCnt, gpTempDealersInventory[ usCnt ].sItemIndex, usPosX, usPosY,
&gpTempDealersInventory[ usCnt ].ItemObject,
fDisplayHatchOnItem,
ARMS_DEALER_INVENTORY );
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
SetSkiRegionHelpText( &gpTempDealersInventory[ usCnt ], &gDealersInventoryMouseRegions[sItemCount], ARMS_DEALER_INVENTORY );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
SetSkiFaceRegionHelpText( &gpTempDealersInventory[ usCnt ], &gRepairmanInventorySmallFaceMouseRegions[sItemCount], ARMS_DEALER_INVENTORY );
}
}
sItemCount++;
usPosX += SKI_INV_OFFSET_X;
//if we are on to the next row
if( !( sItemCount % SKI_NUM_ARMS_DEALERS_INV_COLS ) )
{
usPosX = SKI_ARMS_DEALERS_INV_START_X;
usPosY += SKI_INV_OFFSET_Y;
}
}
}
}
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
//This handles the remaining (empty) slots, resetting Fast Help text, and hatching out disabled ones
while ( sItemCount < SKI_NUM_ARMS_DEALERS_INV_SLOTS )
{
SetSkiRegionHelpText( NULL, &gDealersInventoryMouseRegions[ sItemCount ], ARMS_DEALER_INVENTORY );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
SetSkiFaceRegionHelpText( NULL, &gRepairmanInventorySmallFaceMouseRegions[ sItemCount ], ARMS_DEALER_INVENTORY );
}
// hatch it out if region is disabled
if ( !( gDealersInventoryMouseRegions[ sItemCount ].uiFlags & MSYS_REGION_ENABLED ) )
{
HatchOutInvSlot( usPosX, usPosY );
}
sItemCount++;
usPosX += SKI_INV_OFFSET_X;
//if we are on to the next row
if( !( sItemCount % SKI_NUM_ARMS_DEALERS_INV_COLS ) )
{
usPosX = SKI_ARMS_DEALERS_INV_START_X;
usPosY += SKI_INV_OFFSET_Y;
}
}
}
}
UINT32 DisplayInvSlot( UINT8 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *pItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea )
{
CHAR16 zTemp[64];
HVOBJECT hVObject;
HVOBJECT hPixHandle;
INVTYPE *pItem;
ETRLEObject *pTrav;
UINT32 usHeight, usWidth;
INT16 sCenX, sCenY;
UINT8 sItemCount=0;
BOOLEAN fHighlighted = IsGunOrAmmoOfSameTypeSelected( pItemObject );
BOOLEAN fDisplayMercFace=FALSE;
UINT8 ubMercID=0;
UINT32 uiItemCost=0;
BOOLEAN fPrintRepaired = FALSE;
//if the item is not highlighted, and we are not rerendering the screen
if( !( fHighlighted || gubSkiDirtyLevel != SKI_DIRTY_LEVEL0 ) )
return( 0 );
//
// if( fHighlighted )
// gubSkiDirtyLevel = SKI_DIRTY_LEVEL1;
//Display the item graphic, and price
pItem = &Item[ usItemIndex ];
GetVideoObject( &hVObject, GetInterfaceGraphicForItem( pItem ) );
pTrav = &(hVObject->pETRLEObject[ pItem->ubGraphicNum ] );
usHeight = (UINT32)pTrav->usHeight;
usWidth = (UINT32)pTrav->usWidth;
sCenX = usPosX + 7 + (INT16)( abs( (long) (SKI_INV_WIDTH - 3 - usWidth) ) / 2 ) - pTrav->sOffsetX;
sCenY = usPosY + (INT16)( abs( (long) (SKI_INV_HEIGHT - usHeight) ) / 2 ) - pTrav->sOffsetY;
//Restore the background region
RestoreExternBackgroundRect( usPosX, usPosY, SKI_INV_SLOT_WIDTH, SKI_INV_HEIGHT );
//blt the shadow of the item
if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), pItem->ubGraphicNum, sCenX-2, sCenY+2);
//blt the item
BltVideoObjectOutlineFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), pItem->ubGraphicNum, sCenX, sCenY, Get16BPPColor( FROMRGB( 255, 255, 255 ) ), fHighlighted );
//Display the status of the item
DrawItemUIBarEx( pItemObject, 0, (INT16)(usPosX+2), (INT16)(usPosY+2+20), 2, 20, Get16BPPColor( FROMRGB( 140, 136, 119 ) ), Get16BPPColor( FROMRGB( 140, 136, 119 ) ), TRUE, guiRENDERBUFFER );//guiSAVEBUFFER
//Display the Items Cost
if( ubItemArea == PLAYERS_OFFER_AREA )
{
//if the item has value
if( PlayersOfferArea[ ubSlotNum ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE )
{
uiItemCost = PlayersOfferArea[ ubSlotNum ].uiItemPrice;
}
//if the item belongs to a merc
if( PlayersOfferArea[ ubSlotNum ].ubIdOfMercWhoOwnsTheItem != NO_PROFILE )
{
//Display the face of the merc
fDisplayMercFace = TRUE;
ubMercID = PlayersOfferArea[ ubSlotNum ].ubIdOfMercWhoOwnsTheItem;
}
// if the item has just been repaired
if ( PlayersOfferArea[ ubSlotNum ].uiFlags & ARMS_INV_ITEM_REPAIRED )
{
fPrintRepaired = TRUE;
}
}
else if( ubItemArea == ARMS_DEALER_INVENTORY )
{
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS )
{
if( fHatchedOut && pItemObject->ubNumberOfObjects == 0 )
{
uiItemCost = 0;
}
else
{
// show the UNIT price, not the total value of all if stacked
uiItemCost = CalcShopKeeperItemPrice( DEALER_SELLING, TRUE, usItemIndex, ArmsDealerInfo[ gbSelectedArmsDealerID ].dSellModifier, pItemObject );
}
}
else // UNDER REPAIR
{
UINT8 ubElement;
UINT32 uiTimeInMinutesToFixItem=0;
//display the length of time needed to repair the item
uiItemCost = 0;
//Get the length of time needed to fix the item
Assert( gpTempDealersInventory[ ubSlotNum ].sSpecialItemElement != -1);
ubElement = (UINT8) gpTempDealersInventory[ ubSlotNum ].sSpecialItemElement;
BuildDoneWhenTimeString( zTemp, gbSelectedArmsDealerID, usItemIndex, ubElement );
DrawTextToScreen( zTemp, (UINT16)(usPosX+SKI_INV_PRICE_OFFSET_X), (UINT16)(usPosY+SKI_INV_PRICE_OFFSET_Y), SKI_INV_SLOT_WIDTH, SKI_ITEM_DESC_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
//if the item belongs to a merc
if( gpTempDealersInventory[ ubSlotNum ].ubIdOfMercWhoOwnsTheItem != NO_PROFILE )
{
//Display the face of the merc
fDisplayMercFace = TRUE;
ubMercID = gpTempDealersInventory[ ubSlotNum ].ubIdOfMercWhoOwnsTheItem;
}
}
}
else // DEALER'S OFFER AREA
{
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//if the dealer repairs, there is an item here, therefore display the items owner's face
fDisplayMercFace = TRUE;
ubMercID = ArmsDealerOfferArea[ ubSlotNum ].ubIdOfMercWhoOwnsTheItem;
uiItemCost = CalculateObjectItemRepairCost( gbSelectedArmsDealerID, pItemObject );
}
else
uiItemCost = CalcShopKeeperItemPrice( DEALER_SELLING, FALSE, usItemIndex, ArmsDealerInfo[ gbSelectedArmsDealerID ].dSellModifier, pItemObject );
}
//if the item has a price, display it
if( uiItemCost != 0 )
{
swprintf( zTemp, L"%d", uiItemCost );
InsertCommasForDollarFigure( zTemp );
InsertDollarSignInToString( zTemp );
DrawTextToScreen( zTemp, (UINT16)(usPosX+SKI_INV_PRICE_OFFSET_X), (UINT16)(usPosY+SKI_INV_PRICE_OFFSET_Y), SKI_INV_SLOT_WIDTH, SKI_ITEM_DESC_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
}
//if the there is more then 1 or if the item is stackable and some of it has been bought and only 1 remains
// if( pItemObject->ubNumberOfObjects > 1 || Item[ usItemIndex ].usItemClass == IC_AMMO )
// if( pItemObject->ubNumberOfObjects > 1 || Item[ usItemIndex ].ubPerPocket > 1 )
if( ( pItemObject->ubNumberOfObjects > 1 ) ||
( ( pItemObject->ubNumberOfObjects == 1 ) && DealerItemIsSafeToStack( usItemIndex ) &&
( ubItemArea == ARMS_DEALER_INVENTORY ) && ( gpTempDealersInventory[ ubSlotNum ].uiFlags & ARMS_INV_ITEM_SELECTED ) ) )
{
swprintf( zTemp, L"x%d", pItemObject->ubNumberOfObjects );
DrawTextToScreen( zTemp, (UINT16)(usPosX+SKI_ITEM_NUMBER_TEXT_OFFSET_X), (UINT16)(usPosY+SKI_ITEM_NUMBER_TEXT_OFFSET_Y), SKI_ITEM_NUMBER_TEXT_WIDTH, SKIT_NUMBER_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED );
}
//if we are to display the face
if( fDisplayMercFace )
{
INT8 iFaceSlot = GetSlotNumberForMerc( ubMercID );
// if still in player's employ
if ( iFaceSlot != -1 )
{
//Get and blit the face
GetVideoObject(&hPixHandle, guiSmallSoldiersFace[ iFaceSlot ] );
BltVideoObject(FRAME_BUFFER, hPixHandle, 0,(UINT16)(usPosX+SKI_SMALL_FACE_OFFSET_X), (UINT16)(usPosY), VO_BLT_SRCTRANSPARENCY,NULL);//SKI_SMALL_FACE_OFFSET_Y
}
}
//if the item has attachments
if( ItemHasAttachments( pItemObject ) )
{
//Display the '*' in the bottom right corner of the square
swprintf( zTemp, L"*" );
DrawTextToScreen( zTemp, (UINT16)(usPosX+SKI_ATTACHMENT_SYMBOL_X_OFFSET), (UINT16)(usPosY+SKI_ATTACHMENT_SYMBOL_Y_OFFSET), 0, TINYFONT1, FONT_GREEN, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED );
}
// Display 'JAMMED' if it's jammed
if ( pItemObject->bGunAmmoStatus < 0 )
{
swprintf( zTemp, TacticalStr[ JAMMED_ITEM_STR ] );
VarFindFontCenterCoordinates( usPosX, usPosY, SKI_INV_SLOT_WIDTH, SKI_INV_HEIGHT, TINYFONT1, &sCenX, &sCenY, zTemp );
DrawTextToScreen( zTemp, sCenX, sCenY, SKI_INV_SLOT_WIDTH, TINYFONT1, FONT_RED, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED );
}
else if ( fPrintRepaired )
{
swprintf( zTemp, SKI_Text[ SKI_TEXT_REPAIRED ] );
VarFindFontCenterCoordinates( usPosX, usPosY, SKI_INV_SLOT_WIDTH, SKI_INV_HEIGHT, TINYFONT1, &sCenX, &sCenY, zTemp );
DrawTextToScreen( zTemp, sCenX, sCenY, SKI_INV_SLOT_WIDTH, TINYFONT1, FONT_RED, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED );
}
if( fHatchedOut )
{
HatchOutInvSlot( usPosX, usPosY );
}
InvalidateRegion( usPosX, usPosY, usPosX+SKI_INV_SLOT_WIDTH, usPosY+SKI_INV_SLOT_HEIGHT );
return( uiItemCost );
}
BOOLEAN DetermineArmsDealersSellingInventory( )
{
UINT16 usItemIndex;
UINT8 ubElement;
DEALER_SPECIAL_ITEM *pSpecialItem;
BOOLEAN fAddSpecialItem;
SPECIAL_ITEM_INFO SpclItemInfo;
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("DEF: DetermineArmsDealer") );
//if there is an old inventory, delete it
if( gpTempDealersInventory )
{
MemFree( gpTempDealersInventory );
gpTempDealersInventory = NULL;
}
//allocate memory to hold the inventory in memory
gpTempDealersInventory = (INVENTORY_IN_SLOT *) MemAlloc( sizeof( INVENTORY_IN_SLOT ) * gSelectArmsDealerInfo.uiNumDistinctInventoryItems );
if( gpTempDealersInventory == NULL )
{
Assert( 0 );
return(FALSE);
}
memset( gpTempDealersInventory, 0, sizeof( INVENTORY_IN_SLOT ) * gSelectArmsDealerInfo.uiNumDistinctInventoryItems );
guiNextFreeInvSlot = 0;
//loop through the dealer's permanent inventory items, adding them all to the temp inventory list
for( usItemIndex=1; usItemIndex<MAXITEMS; usItemIndex++)
{
if ( Item[usItemIndex].usItemClass == 0 )
break;
//if the arms dealer has some of the inventory
if( gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].ubTotalItems > 0)
{
// if there are any items in perfect condition
if( gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].ubPerfectItems > 0 )
{
// create just ONE dealer inventory box for them all.
// create item info describing a perfect item
SetSpecialItemInfoToDefaults( &SpclItemInfo );
// no special element index - it's "perfect"
AddItemsToTempDealerInventory(usItemIndex, &SpclItemInfo, -1, gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].ubPerfectItems, NO_PROFILE );
}
// add all active special items
for( ubElement=0; ubElement< gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].ubElementsAlloced; ubElement++ )
{
pSpecialItem = &(gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].SpecialItem[ ubElement ]);
if ( pSpecialItem->fActive )
{
fAddSpecialItem = TRUE;
//if the item is in for repairs
if( pSpecialItem->Info.bItemCondition < 0 )
{
//if the repairs are done
if( pSpecialItem->uiRepairDoneTime <= GetWorldTotalMin() )
{
if (RepairIsDone( usItemIndex, ubElement ))
{
// don't add it here, it was put in the player's area
fAddSpecialItem = FALSE;
}
else
{
gpTempDealersInventory[ guiNextFreeInvSlot ].uiFlags |= ARMS_INV_ITEM_REPAIRED;
}
}
else
{
gpTempDealersInventory[ guiNextFreeInvSlot ].uiFlags |= ARMS_INV_ITEM_NOT_REPAIRED_YET;
}
}
if ( fAddSpecialItem )
{
UINT8 ubOwner;
if ( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS )
{
// no merc is the owner
ubOwner = NO_PROFILE;
}
else
{
// retain owner so we can display this
ubOwner = pSpecialItem->ubOwnerProfileId;
}
AddItemsToTempDealerInventory( usItemIndex, &(pSpecialItem->Info), ubElement, 1, ubOwner );
}
}
}
}
}
// if more than one item is in inventory
if ( guiNextFreeInvSlot > 1 )
{
// repairmen sort differently from merchants
if ( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
// sort this list by object category, and by ascending price within each category
qsort( (void*)gpTempDealersInventory, (size_t)guiNextFreeInvSlot, sizeof( INVENTORY_IN_SLOT ), RepairmanItemQsortCompare );
}
else
{
// sort this list by object category, and by ascending price within each category
qsort( (void*)gpTempDealersInventory, (size_t)guiNextFreeInvSlot, sizeof( INVENTORY_IN_SLOT ), ArmsDealerItemQsortCompare );
}
}
return( TRUE );
}
void AddItemsToTempDealerInventory(UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, INT16 sSpecialItemElement, UINT8 ubHowMany, UINT8 ubOwner )
{
UINT8 ubCnt;
Assert( ubHowMany > 0 );
Assert( pSpclItemInfo != NULL );
// if there's just one of them
if ( ubHowMany == 1 )
{
// it gets its own box, obviously
StoreObjectsInNextFreeDealerInvSlot( usItemIndex, pSpclItemInfo, sSpecialItemElement, 1, ubOwner );
}
else // more than one
{
// if the items can be stacked
// NOTE: This test must match the one inside CountDistinctItemsInArmsDealersInventory() exactly!
if ( DealerItemIsSafeToStack( usItemIndex ) )
{
// then we can store them all together in the same box safely, even if there's more than MAX_OBJECTS_PER_SLOT
StoreObjectsInNextFreeDealerInvSlot( usItemIndex, pSpclItemInfo, sSpecialItemElement, ubHowMany, ubOwner );
}
else
{
// non-stacking items must be stored in one / box , because each may have unique fields besides bStatus[]
// Example: guns all have ammo, ammo type, etc. We need these uniquely represented for pricing & manipulation
for ( ubCnt = 0; ubCnt < ubHowMany; ubCnt++ )
{
StoreObjectsInNextFreeDealerInvSlot( usItemIndex, pSpclItemInfo, sSpecialItemElement, 1, ubOwner );
}
}
}
}
void StoreObjectsInNextFreeDealerInvSlot( UINT16 usItemIndex, SPECIAL_ITEM_INFO *pSpclItemInfo, INT16 sSpecialItemElement, UINT8 ubHowMany, UINT8 ubOwner )
{
INVENTORY_IN_SLOT *pDealerInvSlot;
// make sure we have the room (memory allocated for it)
Assert( guiNextFreeInvSlot < gSelectArmsDealerInfo.uiNumDistinctInventoryItems );
pDealerInvSlot = &(gpTempDealersInventory[ guiNextFreeInvSlot ]);
guiNextFreeInvSlot++;
pDealerInvSlot->fActive = TRUE;
pDealerInvSlot->sItemIndex = usItemIndex;
pDealerInvSlot->sSpecialItemElement = sSpecialItemElement;
pDealerInvSlot->ubIdOfMercWhoOwnsTheItem = ubOwner;
pDealerInvSlot->bSlotIdInOtherLocation = -1;
// Create the item object ( with no more than MAX_OBJECTS_PER_SLOT )
// can't use the real #, because CreateItems() will blindly set the bStatus for however many we tell it, beyond 8
MakeObjectOutOfDealerItems( usItemIndex, pSpclItemInfo, &(pDealerInvSlot->ItemObject), ( UINT8 ) min( ubHowMany, MAX_OBJECTS_PER_SLOT ) );
if ( ubHowMany > MAX_OBJECTS_PER_SLOT )
{
// HACK: Override ItemObject->ubNumberOfObjects (1-8) with the REAL # of items in this box.
// Note that this makes it an illegal OBJECTTYPE, since there ubHowMany can easily be more than MAX_OBJECTS_PER_SLOT,
// so there's no room to store the status of all of them one. But we only so this for perfect items, so
// we don't care, it works & saves us a lot hassles here. Just be careful using the damn things!!! You can't just
// pass them off the most functions in Items.C(), use ShopkeeperAutoPlaceObject() and ShopkeeperAddItemToPool() instead.
pDealerInvSlot->ItemObject.ubNumberOfObjects = ubHowMany;
}
}
BOOLEAN RepairIsDone(UINT16 usItemIndex, UINT8 ubElement)
{
INVENTORY_IN_SLOT RepairItem;
INT8 bSlotNum;
UINT8 ubCnt;
// make a new shopkeeper invslot item out of it
memset( &RepairItem, 0, sizeof( INVENTORY_IN_SLOT ) );
RepairItem.fActive = TRUE;
RepairItem.sItemIndex = usItemIndex;
// set the owner of the item. Slot is always -1 of course.
RepairItem.ubIdOfMercWhoOwnsTheItem = gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].SpecialItem[ ubElement ].ubOwnerProfileId;
RepairItem.bSlotIdInOtherLocation = -1;
// Create the item object
MakeObjectOutOfDealerItems( usItemIndex, &( gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].SpecialItem[ ubElement ].Info ), &RepairItem.ItemObject, 1 );
if ( CanDealerRepairItem( gbSelectedArmsDealerID, RepairItem.ItemObject.usItem ) )
{
// make its condition 100%
RepairItem.ItemObject.bStatus[ 0 ] = 100;
}
// max condition of all permanent attachments on it
for ( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
{
if ( RepairItem.ItemObject.usAttachItem[ ubCnt ] != NONE )
{
/* ARM: Can now repair with removeable attachments still attached...
// If the attachment is a permanent one
if ( Item[ RepairItem.ItemObject.usAttachItem[ ubCnt ] ].fFlags & ITEM_INSEPARABLE )
*/
if ( CanDealerRepairItem( gbSelectedArmsDealerID, RepairItem.ItemObject.usAttachItem[ ubCnt ] ) )
{
// fix it up
RepairItem.ItemObject.bAttachStatus[ ubCnt ] = 100;
}
}
}
// if the item is imprinted (by anyone, even player's mercs), and it's Fredo repairing it
if ( /*( gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ].SpecialItem[ ubElement ].Info.ubImprintID == (NO_PROFILE + 1) ) && */
( gbSelectedArmsDealerID == ARMS_DEALER_FREDO ) )
{
// then reset the imprinting!
RepairItem.ItemObject.ubImprintID = NO_PROFILE;
}
//try to add the item to the players offer area
bSlotNum = AddItemToPlayersOfferArea( RepairItem.ubIdOfMercWhoOwnsTheItem, &RepairItem, -1 );
// if there wasn't room for it
if( bSlotNum == -1 )
{
// then we have to treat it like it's not done yet!
return(FALSE);
}
PlayersOfferArea[ bSlotNum ].uiFlags |= ARMS_INV_ITEM_REPAIRED;
// Remove the repaired item from the dealer's permanent inventory list
RemoveSpecialItemFromArmsDealerInventoryAtElement( gbSelectedArmsDealerID, usItemIndex, ubElement );
// one less slot is needed. Don't bother ReMemAllocating, though
gSelectArmsDealerInfo.uiNumDistinctInventoryItems--;
// there was room to add it to player's area
return(TRUE);
}
void DrawHatchOnInventory( UINT32 uiSurface, UINT16 usPosX, UINT16 usPosY, UINT16 usWidth, UINT16 usHeight )
{
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES;
SGPRect ClipRect;
static UINT8 Pattern[8][8] =
{
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1,
1,0,1,0,1,0,1,0,
0,1,0,1,0,1,0,1
};
ClipRect.iLeft = usPosX;
ClipRect.iRight = usPosX + usWidth;
ClipRect.iTop = usPosY;
ClipRect.iBottom = usPosY + usHeight;
pDestBuf = LockVideoSurface( uiSurface, &uiDestPitchBYTES );
Blt16BPPBufferPixelateRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, Pattern );
UnLockVideoSurface( uiSurface );
}
UINT32 CalcShopKeeperItemPrice( BOOLEAN fDealerSelling, BOOLEAN fUnitPriceOnly, UINT16 usItemID, FLOAT dModifier, OBJECTTYPE *pItemObject )
{
UINT8 ubCnt;
UINT32 uiUnitPrice = 0;
UINT32 uiTotalPrice = 0;
UINT8 ubItemsToCount = 0;
UINT8 ubItemsNotCounted = 0;
UINT32 uiDiscountValue;
// UINT32 uiDifFrom10 = 0;
// add up value of the main item(s), exact procedure depends on its item class
switch ( Item [ usItemID ].usItemClass )
{
case IC_GUN:
// add value of the gun
uiUnitPrice += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, usItemID, fDealerSelling ) *
ItemConditionModifier(usItemID, pItemObject->bGunStatus) *
dModifier );
// if any ammo is loaded
if( pItemObject->usGunAmmoItem != NONE)
{
// if it's regular ammo
if( Item[ pItemObject->usGunAmmoItem ].usItemClass == IC_AMMO )
{
// add value of its remaining ammo
uiUnitPrice += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, pItemObject->usGunAmmoItem, fDealerSelling ) *
ItemConditionModifier(pItemObject->usGunAmmoItem, pItemObject->ubGunShotsLeft) *
dModifier );
}
else // assume it's attached ammo (mortar shells, grenades)
{
// add its value (uses normal status 0-100)
uiUnitPrice += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, pItemObject->usGunAmmoItem, fDealerSelling ) *
ItemConditionModifier(pItemObject->usGunAmmoItem, pItemObject->bGunAmmoStatus) *
dModifier );
}
}
// if multiple guns are stacked, we've only counted the first one
ubItemsNotCounted = pItemObject->ubNumberOfObjects - 1;
break;
case IC_AMMO:
//Madd: quick fix for negative prices at Tony's
// this must handle overloaded objects from dealer boxes!
if ( pItemObject->ubNumberOfObjects <= MAX_OBJECTS_PER_SLOT )
{
// legal amount, count them all normally (statuses could be different)
ubItemsToCount = pItemObject->ubNumberOfObjects;
ubItemsNotCounted = 0;
// in this situation, uiUnitPrice will actually be the sum of the values of ALL the multiple objects
}
else
{
// overloaded amount, count just the first, the others must all be identical
ubItemsToCount = 1;
ubItemsNotCounted = pItemObject->ubNumberOfObjects - 1;
}
// add the value of each magazine (multiple mags may have vastly different #bullets left)
for (ubCnt = 0; ubCnt < ubItemsToCount; ubCnt++ )
{
// for bullets, ItemConditionModifier will convert the #ShotsLeft into a percentage
uiUnitPrice += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, usItemID, fDealerSelling ) *
ItemConditionModifier(usItemID, pItemObject->ubShotsLeft[ubCnt]) *
dModifier );
if ( fUnitPriceOnly )
{
// want price for only one of them. All statuses must be the same in order to use this flag!
break;
}
}
break;
default:
// this must handle overloaded objects from dealer boxes!
if ( pItemObject->ubNumberOfObjects <= MAX_OBJECTS_PER_SLOT )
{
// legal amount, count them all normally (statuses could be different)
ubItemsToCount = pItemObject->ubNumberOfObjects;
ubItemsNotCounted = 0;
// in this situation, uiUnitPrice will actually be the sum of the values of ALL the multiple objects
}
else
{
// overloaded amount, count just the first, the others must all be identical
ubItemsToCount = 1;
ubItemsNotCounted = pItemObject->ubNumberOfObjects - 1;
}
// add the value of each magazine (multiple mags may have vastly different #bullets left)
for (ubCnt = 0; ubCnt < ubItemsToCount; ubCnt++ )
{
// for bullets, ItemConditionModifier will convert the #ShotsLeft into a percentage
uiUnitPrice += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, usItemID, fDealerSelling ) *
ItemConditionModifier(usItemID, pItemObject->bStatus[ ubCnt ]) *
dModifier );
if ( fUnitPriceOnly )
{
// want price for only one of them. All statuses must be the same in order to use this flag!
break;
}
}
break;
}
// loop through any attachments and add in their price
for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++)
{
if( pItemObject->usAttachItem[ ubCnt ] != NONE )
{
// add value of this particular attachment
uiUnitPrice += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, pItemObject->usAttachItem[ ubCnt ], fDealerSelling ) *
ItemConditionModifier(pItemObject->usAttachItem[ ubCnt ], pItemObject->bAttachStatus[ ubCnt ]) *
dModifier );
}
}
// if Flo is doing the dealin' and wheelin'
if ( gpSMCurrentMerc->ubProfile == FLO )
{
// if it's a GUN or AMMO (but not Launchers, and all attachments and payload is included)
switch ( Item [ usItemID ].usItemClass )
{
case IC_GUN:
case IC_AMMO:
uiDiscountValue = ( uiUnitPrice * FLO_DISCOUNT_PERCENTAGE ) / 100;
// she gets a discount! Read her M.E.R.C. profile to understand why
if ( fDealerSelling )
{
// she buys for less...
uiUnitPrice -= uiDiscountValue;
}
else
{
// and sells for more!
uiUnitPrice += uiDiscountValue;
}
break;
}
}
// if it's the dealer selling this, make sure the item is worth at least $1
// if he is buying this from a player, then we allow a value of 0, since that has a special "worthless" quote #18
if( fDealerSelling && ( uiUnitPrice == 0 ) )
{
uiUnitPrice = 1;
}
/*
//if the price is not diviseble by 10, make it so
uiDifFrom10 = 10 - uiUnitPrice % 10;
if( uiDifFrom10 != 0 && uiDifFrom10 != 10 )
{
uiUnitPrice += uiDifFrom10;
}
*/
// we're always count the first one
uiTotalPrice = uiUnitPrice;
// if NOT pricing just one
if ( !fUnitPriceOnly )
{
// add value of all that weren't already counted
uiTotalPrice += ( ubItemsNotCounted * uiUnitPrice );
}
return( uiTotalPrice );
}
FLOAT ItemConditionModifier(UINT16 usItemIndex, INT16 bStatus)
{
FLOAT dConditionModifier = 1.0f;
//if the item is ammo, the condition modifier is based on how many shots are left
if( Item[ usItemIndex ].usItemClass == IC_AMMO )
{
// # bullets left / max magazine capacity
dConditionModifier = ( bStatus / (FLOAT) Magazine[ Item[ usItemIndex ].ubClassIndex ].ubMagSize );
}
else // non-ammo
{
// handle non-ammo payloads in jammed guns as if they weren't
if ( bStatus < 0 )
{
bStatus *= -1;
}
// an item at 100% is worth full price...
// if ( Item[ usItemIndex ].fFlags & ITEM_REPAIRABLE )
if ( Item[ usItemIndex ].repairable )
{
// a REPAIRABLE item at 0% is still worth 50% of its full price, not 0%
dConditionModifier = 0.5f + ( bStatus / (FLOAT)200 );
}
else
{
// an UNREPAIRABLE item is worth precisely its condition percentage
dConditionModifier = bStatus / (FLOAT)100;
}
}
return( dConditionModifier );
}
void DisplayArmsDealerOfferArea()
{
INT16 sCnt, sCount;
CHAR16 zTemp[32];
UINT32 uiTotalCost;
UINT16 usPosX, usPosY;
BOOLEAN fDisplayHatchOnItem;
usPosX = SKI_ARMS_DEALERS_TRADING_INV_X;
usPosY = SKI_ARMS_DEALERS_TRADING_INV_Y;
if( gubSkiDirtyLevel != SKI_DIRTY_LEVEL0 )
{
//Restore the area before blitting the new data on
RestoreExternBackgroundRect( usPosX, usPosY, SKI_ARMS_DEALERS_TRADING_INV_WIDTH, SKI_ARMS_DEALERS_TRADING_INV_HEIGHT );
}
sCount = 0;
//Display all the items that are in the Arms traders offered area
uiTotalCost = 0;
for( sCnt=0; sCnt<SKI_NUM_TRADING_INV_SLOTS; sCnt++)
{
if( ArmsDealerOfferArea[ sCnt ].fActive )
{
// hatch it out if region is disabled
if ( !( gDealersOfferSlotsMouseRegions[ sCnt ].uiFlags & MSYS_REGION_ENABLED ) )
{
fDisplayHatchOnItem = TRUE;
}
else if( ArmsDealerOfferArea[ sCnt ].uiFlags & ARMS_INV_ITEM_SELECTED )
{
fDisplayHatchOnItem = TRUE;
}
else
fDisplayHatchOnItem = FALSE;
// Display the inventory slot
uiTotalCost += DisplayInvSlot( (UINT8)sCnt, ArmsDealerOfferArea[ sCnt ].sItemIndex, usPosX, usPosY,
&ArmsDealerOfferArea[ sCnt ].ItemObject,
fDisplayHatchOnItem,
ARMS_DEALER_OFFER_AREA );
}
else // empty
{
// hatch it out if region is disabled
if ( !( gDealersOfferSlotsMouseRegions[ sCnt ].uiFlags & MSYS_REGION_ENABLED ) )
{
HatchOutInvSlot( usPosX, usPosY );
}
}
usPosX += SKI_INV_OFFSET_X;
sCount++;
//if we are on to the next row
if( !( sCount % SKI_NUM_TRADING_INV_COLS ) )
{
usPosX = SKI_ARMS_DEALERS_TRADING_INV_X;
usPosY += SKI_INV_OFFSET_Y;
}
}
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
//
//Display the Total cost text and number
//
//Restore the previous area
RestoreExternBackgroundRect( SKI_ARMS_DEALER_TOTAL_COST_X, SKI_ARMS_DEALER_TOTAL_COST_Y, SKI_ARMS_DEALER_TOTAL_COST_WIDTH, SKI_ARMS_DEALER_TOTAL_COST_HEIGHT );
//Display the total cost text
swprintf( zTemp, L"%d", uiTotalCost );
InsertCommasForDollarFigure( zTemp );
InsertDollarSignInToString( zTemp );
DrawTextToScreen( zTemp, SKI_ARMS_DEALER_TOTAL_COST_X, (UINT16)(SKI_ARMS_DEALER_TOTAL_COST_Y+5), SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
}
}
INT8 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT8 bSlotIdInOtherLocation )
{
INT8 bCnt;
for( bCnt=0; bCnt<SKI_NUM_TRADING_INV_SLOTS; bCnt++)
{
//if there are no items here, copy the data in
if( ArmsDealerOfferArea[bCnt].fActive == FALSE )
{
//Copy the inventory items
memcpy( &ArmsDealerOfferArea[bCnt], pInvSlot, sizeof( INVENTORY_IN_SLOT ) );
//if the shift key is being pressed, add them all
if( gfKeyState[ SHIFT ] )
ArmsDealerOfferArea[bCnt].ItemObject.ubNumberOfObjects = pInvSlot->ItemObject.ubNumberOfObjects;
//If there was more then 1 item, reduce it to only 1 item moved
else if( pInvSlot->ItemObject.ubNumberOfObjects > 1 )
ArmsDealerOfferArea[bCnt].ItemObject.ubNumberOfObjects = 1;
//Remember where the item came from
ArmsDealerOfferArea[bCnt].bSlotIdInOtherLocation = bSlotIdInOtherLocation;
ArmsDealerOfferArea[bCnt].ubIdOfMercWhoOwnsTheItem = pInvSlot->ubIdOfMercWhoOwnsTheItem;
ArmsDealerOfferArea[bCnt].fActive = TRUE;
SetSkiRegionHelpText( &ArmsDealerOfferArea[bCnt], &gDealersOfferSlotsMouseRegions[ bCnt ], ARMS_DEALER_OFFER_AREA );
SetSkiFaceRegionHelpText( &ArmsDealerOfferArea[bCnt], &gDealersOfferSlotsSmallFaceMouseRegions[ bCnt ], ARMS_DEALER_OFFER_AREA );
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
return( bCnt );
}
}
return( -1 );
}
BOOLEAN RemoveItemFromArmsDealerOfferArea( INT8 bSlotId, BOOLEAN fKeepItem )
{
// UINT16 usCnt;
//Loop through all the slot to see if the requested one is here
// for( usCnt=0; usCnt<SKI_NUM_TRADING_INV_SLOTS; usCnt++)
{
//if this is the requested slot
if( ArmsDealerOfferArea[bSlotId].fActive )//bSlotIdInOtherLocation == bSlotIdInOtherLocation )
{
//if there are more then 1 item
// if( ArmsDealerOfferArea[ usCnt ].ItemObject.ubNumberOfObjects > 1 )
if( fKeepItem )
{
gpTempDealersInventory[ ArmsDealerOfferArea[bSlotId].bSlotIdInOtherLocation ].ItemObject.ubNumberOfObjects += ArmsDealerOfferArea[ bSlotId ].ItemObject.ubNumberOfObjects;
}
//Clear the flag that hatches out the item
gpTempDealersInventory[ ArmsDealerOfferArea[bSlotId].bSlotIdInOtherLocation ].uiFlags &= ~ARMS_INV_ITEM_SELECTED;
ClearArmsDealerOfferSlot( bSlotId );
return( TRUE );
}
}
return( FALSE );
}
void SetSkiRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION *pRegion, UINT8 ubScreenArea )
{
CHAR16 zHelpText[ 512 ];
Assert( pRegion );
BuildItemHelpTextString( zHelpText, pInv, ubScreenArea );
SetRegionFastHelpText( pRegion, zHelpText );
SetRegionHelpEndCallback( pRegion, SkiHelpTextDoneCallBack );
}
void SetSkiFaceRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION *pRegion, UINT8 ubScreenArea )
{
CHAR16 zTempText[ 512 ];
CHAR16 zHelpText[ 512 ];
Assert( pRegion );
//if the item isn't NULL, and is owned by a merc
if( ( pInv != NULL ) && ( pInv->ubIdOfMercWhoOwnsTheItem != NO_PROFILE ) )
{
BuildItemHelpTextString( zTempText, pInv, ubScreenArea );
// add who owns it
swprintf( zHelpText, L"%s%s %s", gMercProfiles[ pInv->ubIdOfMercWhoOwnsTheItem ].zNickname, pMessageStrings[ MSG_DASH_S ], zTempText );
}
else
{
zHelpText[ 0 ] = '\0';
}
SetRegionFastHelpText( pRegion, zHelpText );
SetRegionHelpEndCallback( pRegion, SkiHelpTextDoneCallBack );
}
void SkiHelpTextDoneCallBack( void )
{
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
INT8 AddItemToPlayersOfferArea( UINT8 ubProfileID, INVENTORY_IN_SLOT* pInvSlot, INT8 bSlotIdInOtherLocation )
{
INT8 bCnt;
//if we are to check for a previous slot
if( bSlotIdInOtherLocation != -1 )
{
//if the item has already been added somewhere. don't add it again
if( GetPtrToOfferSlotWhereThisItemIs( ubProfileID, bSlotIdInOtherLocation ) != NULL )
return( -1 );
}
//look for the first free slot
for( bCnt=0; bCnt<SKI_NUM_TRADING_INV_SLOTS; bCnt++)
{
//if there are no items here, copy the data in
if( PlayersOfferArea[bCnt].fActive == FALSE )
{
memcpy( &PlayersOfferArea[bCnt], pInvSlot, sizeof( INVENTORY_IN_SLOT ) );
PlayersOfferArea[bCnt].fActive = TRUE;
//Specify the owner of the merc
PlayersOfferArea[bCnt].ubIdOfMercWhoOwnsTheItem = ubProfileID;
PlayersOfferArea[bCnt].bSlotIdInOtherLocation = bSlotIdInOtherLocation;
IfMercOwnedCopyItemToMercInv( &(PlayersOfferArea[bCnt]) );
SetSkiRegionHelpText( &PlayersOfferArea[bCnt], &gPlayersOfferSlotsMouseRegions[ bCnt ], PLAYERS_OFFER_AREA );
SetSkiFaceRegionHelpText( &PlayersOfferArea[bCnt], &gPlayersOfferSlotsSmallFaceMouseRegions[ bCnt ], PLAYERS_OFFER_AREA );
//if the item we are adding is money
if( Item[ PlayersOfferArea[ bCnt ].sItemIndex ].usItemClass == IC_MONEY )
{
//Since money is always evaluated
PlayersOfferArea[ bCnt ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
PlayersOfferArea[ bCnt ].uiItemPrice = PlayersOfferArea[ bCnt ].ItemObject.uiMoneyAmount;
}
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
return( bCnt );
}
}
return( -1 );
}
BOOLEAN RemoveItemFromPlayersOfferArea( INT8 bSlot )
{
//if the item doesn't have a duplicate copy in its owner merc's inventory slot
if( PlayersOfferArea[ bSlot ].bSlotIdInOtherLocation == -1 )
{
if ( !SKITryToReturnInvToOwnerOrCurrentMerc( &( PlayersOfferArea[ bSlot ] ) ) )
{
//failed to add item, inventory probably filled up or item is unowned and current merc ineligible
return( FALSE );
}
}
// Clear the contents
ClearPlayersOfferSlot( bSlot );
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL1;
return( TRUE );
}
void DisplayPlayersOfferArea()
{
INT16 sCnt, sCount;
CHAR16 zTemp[32];
UINT32 uiTotalCost;
UINT16 usPosX, usPosY;
BOOLEAN fDisplayHatchOnItem=FALSE;
usPosX = SKI_PLAYERS_TRADING_INV_X;
usPosY = SKI_PLAYERS_TRADING_INV_Y;
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
//Restore the area before blitting the new data on
RestoreExternBackgroundRect( SKI_PLAYERS_TRADING_INV_X, SKI_PLAYERS_TRADING_INV_Y, SKI_PLAYERS_TRADING_INV_WIDTH, SKI_PLAYERS_TRADING_INV_HEIGHT );
}
sCount = 0;
//Display all the items that are in the Players offered area
uiTotalCost = 0;
for( sCnt=0; sCnt<SKI_NUM_TRADING_INV_SLOTS; sCnt++)
{
if( PlayersOfferArea[ sCnt ].fActive )
{
//if the item is money
if( Item[ PlayersOfferArea[ sCnt ].sItemIndex ].usItemClass == IC_MONEY )
{
//get an updated status from the amount in the pocket
if( PlayersOfferArea[ sCnt ].bSlotIdInOtherLocation != -1 && PlayersOfferArea[ sCnt ].ubIdOfMercWhoOwnsTheItem != NO_PROFILE )
{
INT16 sSoldierID;
sSoldierID = GetSoldierIDFromMercID( PlayersOfferArea[ sCnt ].ubIdOfMercWhoOwnsTheItem );
Assert(sSoldierID != -1);
PlayersOfferArea[ sCnt ].ItemObject.uiMoneyAmount = Menptr[ sSoldierID ].inv[ PlayersOfferArea[ sCnt ].bSlotIdInOtherLocation ].uiMoneyAmount;
PlayersOfferArea[ sCnt ].uiItemPrice = PlayersOfferArea[ sCnt ].ItemObject.uiMoneyAmount;
}
}
else // not money
{
//if non-repairman
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS )
{
// don't evaluate anything he wouldn't buy!
if( WillShopKeeperRejectObjectsFromPlayer( gbSelectedArmsDealerID, ( INT8 ) sCnt ) == FALSE )
{
// skip purchased items!
if ( !( PlayersOfferArea[ sCnt ].uiFlags & ARMS_INV_JUST_PURCHASED ) )
{
// re-evaluate the value of the item (needed for Flo's discount handling)
EvaluateInvSlot( &( PlayersOfferArea[ sCnt ] ) );
}
}
}
}
// hatch it out if it hasn't been evaluated or just purchased
// fDisplayHatchOnItem = ( PlayersOfferArea[ sCnt ].uiFlags & ( ARMS_INV_PLAYERS_ITEM_HAS_BEEN_EVALUATED | ARMS_INV_JUST_PURCHASED ) ) == 0;
// Display the inventory slot
DisplayInvSlot( (UINT8)sCnt, PlayersOfferArea[ sCnt ].sItemIndex, usPosX, usPosY,
&PlayersOfferArea[ sCnt ].ItemObject,
fDisplayHatchOnItem,
PLAYERS_OFFER_AREA );
if( PlayersOfferArea[ sCnt ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE )
uiTotalCost += PlayersOfferArea[ sCnt ].uiItemPrice;
}
usPosX += SKI_INV_OFFSET_X;
sCount++;
//if we are on to the next row
if( !( sCount % SKI_NUM_TRADING_INV_COLS ) )
{
usPosX = SKI_ARMS_DEALERS_TRADING_INV_X;
usPosY += SKI_INV_OFFSET_Y;
}
}
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
{
//
//Display the Total value text and number
//
//Restore the previous area
RestoreExternBackgroundRect( SKI_PLAYERS_TOTAL_VALUE_X, SKI_PLAYERS_TOTAL_VALUE_Y, SKI_PLAYERS_TOTAL_VALUE_WIDTH, SKI_PLAYERS_TOTAL_VALUE_HEIGHT );
//Display the total cost text
swprintf( zTemp, L"%d", uiTotalCost );
InsertCommasForDollarFigure( zTemp );
InsertDollarSignInToString( zTemp );
DrawTextToScreen( zTemp, SKI_PLAYERS_TOTAL_VALUE_X, (UINT16)(SKI_PLAYERS_TOTAL_VALUE_Y+5), SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
}
CrossOutUnwantedItems( );
}
INVENTORY_IN_SLOT *GetPtrToOfferSlotWhereThisItemIs( UINT8 ubProfileID, INT8 bInvPocket )
{
UINT8 ubCnt = 0;
for( ubCnt = 0; ubCnt < SKI_NUM_TRADING_INV_SLOTS; ubCnt++ )
{
if( ( PlayersOfferArea[ ubCnt ].bSlotIdInOtherLocation == bInvPocket ) &&
( PlayersOfferArea[ ubCnt ].ubIdOfMercWhoOwnsTheItem == ubProfileID ) &&
( PlayersOfferArea[ ubCnt ].ItemObject.ubNumberOfObjects != 0 ) )
{
return( &( PlayersOfferArea[ ubCnt ] ) );
}
if( ( ArmsDealerOfferArea[ ubCnt ].bSlotIdInOtherLocation == bInvPocket ) &&
( ArmsDealerOfferArea[ ubCnt ].ubIdOfMercWhoOwnsTheItem == ubProfileID ) &&
( ArmsDealerOfferArea[ ubCnt ].ItemObject.ubNumberOfObjects != 0 ) )
{
return( &( ArmsDealerOfferArea[ ubCnt ] ) );
}
}
// not found (perfectly valid result)
return( NULL );
}
BOOLEAN ShouldSoldierDisplayHatchOnItem( UINT8 ubProfileID, INT16 sSlotNum )
{
INVENTORY_IN_SLOT *pInvSlot = NULL;
pInvSlot = GetPtrToOfferSlotWhereThisItemIs( ubProfileID, ( INT8 ) sSlotNum );
if( pInvSlot == NULL )
// not found in either offer area
return( FALSE );
else
// found it, display it hatched out
return( TRUE );
}
UINT32 CalculateTotalArmsDealerCost()
{
UINT32 uiCnt;
UINT32 uiTotal=0;
for( uiCnt=0; uiCnt<SKI_NUM_TRADING_INV_SLOTS; uiCnt++)
{
if( ArmsDealerOfferArea[ uiCnt ].fActive )
{
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
uiTotal += CalculateObjectItemRepairCost( gbSelectedArmsDealerID, &( ArmsDealerOfferArea[ uiCnt ].ItemObject ) );
else
uiTotal += CalcShopKeeperItemPrice( DEALER_SELLING, FALSE, ArmsDealerOfferArea[ uiCnt ].sItemIndex, ArmsDealerInfo[ gbSelectedArmsDealerID ].dSellModifier, &ArmsDealerOfferArea[uiCnt].ItemObject );
}
}
return( uiTotal );
}
UINT32 CalculateTotalPlayersValue()
{
UINT8 ubCnt;
UINT32 uiTotal = 0;
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
if( ( PlayersOfferArea[ ubCnt ].fActive ) && ( PlayersOfferArea[ ubCnt ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE ) )
{
//Calculate a price for the item
if( Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass == IC_MONEY )
uiTotal += PlayersOfferArea[ ubCnt ].ItemObject.uiMoneyAmount;
else
uiTotal += PlayersOfferArea[ ubCnt ].uiItemPrice;
}
}
return( uiTotal );
}
void PerformTransaction( UINT32 uiMoneyFromPlayersAccount )
{
UINT32 uiPlayersTotalMoneyValue = CalculateTotalPlayersValue() + uiMoneyFromPlayersAccount;
UINT32 uiArmsDealersItemsCost = CalculateTotalArmsDealerCost();
UINT32 uiMoneyInPlayersOfferArea = CalculateHowMuchMoneyIsInPlayersOfferArea( );
INT32 iChangeToGiveToPlayer = 0;
UINT32 uiAvailablePlayerOfferSlots;
//if the player has already requested to leave, get out
if( gfUserHasRequestedToLeave )
return;
// handle bribing... if the player is giving the dealer money, without buying anything
if( IsMoneyTheOnlyItemInThePlayersOfferArea( ) && CountNumberOfItemsInTheArmsDealersOfferArea( ) == 0 )
{
// accept/refuse money (varies by dealer according to ACCEPTS_GIFTS flag)
StartShopKeeperTalking( SK_QUOTES_DEALER_OFFERED_MONEY_AS_A_GIFT );
// if the arms dealer is the kind of person who accepts gifts
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].uiFlags & ARMS_DEALER_ACCEPTS_GIFTS )
{
//Move all the players evaluated items to the dealer (also adds it to dealer's cash)
MovePlayerOfferedItemsOfValueToArmsDealersInventory();
DealerGetsBribed( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID, uiMoneyInPlayersOfferArea );
}
}
else // not a bribe
{
//if the dealer is not a repairman
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS )
{
uiAvailablePlayerOfferSlots = ( SKI_NUM_TRADING_INV_SLOTS - CountNumberOfValuelessItemsInThePlayersOfferArea( ) );
// always reserve an empty slot for change. We can't tell for sure whether player is getting change because that
// could depend on how many items he's trying to buy won't fit - he could only be getting change because of that!
if ( uiAvailablePlayerOfferSlots > 0 )
{
uiAvailablePlayerOfferSlots--;
}
//if there is NOT enough room in the players offer area
if( CountNumberOfItemsInTheArmsDealersOfferArea( ) > uiAvailablePlayerOfferSlots )
{
// tell player there's not enough room in the player's offer area
DoSkiMessageBox( MSG_BOX_BASIC_STYLE, SKI_Text[ SKI_TEXT_NO_MORE_ROOM_IN_PLAYER_OFFER_AREA ], SHOPKEEPER_SCREEN, MSG_BOX_FLAG_OK, NULL );
return;
}
}
//if the player doesn't have enough money to pay for what he's buying
if( uiArmsDealersItemsCost > uiPlayersTotalMoneyValue )
{
//if the player doesn't have enough money in his account to pay the rest
if( uiArmsDealersItemsCost > uiPlayersTotalMoneyValue + LaptopSaveInfo.iCurrentBalance )
{
// tell player he can't possibly afford this
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 6,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SKIP_A_FRAME, 0,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 0, ( uiArmsDealersItemsCost - ( LaptopSaveInfo.iCurrentBalance + uiPlayersTotalMoneyValue ) ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
}
else
{
// player doesn't have enough on the table, but can pay for it from his balance
/// ask player if wants to subtract the shortfall directly from his balance
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SKIP_A_FRAME, 0,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 6,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
if( uiPlayersTotalMoneyValue )
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 1, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
else
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 2, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
}
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 7,0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
gfResetShopKeepIdleQuote = TRUE;
// disable further calls to PerformTransaction() until callback calls us again to free this flag
gfPerformTransactionInProgress = TRUE;
return;
}
// to get this far, player should have the money needed!
Assert( uiPlayersTotalMoneyValue >= uiArmsDealersItemsCost );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//Make sure there is enough money in the Player's offer area to cover the repair charge
if( ( uiMoneyFromPlayersAccount + uiMoneyInPlayersOfferArea ) >= uiArmsDealersItemsCost )
{
//Move all the players evaluated items to the dealer ( For a repairman, this means just: get rid of the money )
MovePlayerOfferedItemsOfValueToArmsDealersInventory();
//if the arms dealer is the type of person to give change
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].uiFlags & ARMS_DEALER_GIVES_CHANGE )
{
//determine the amount of change to give
iChangeToGiveToPlayer = ( uiMoneyFromPlayersAccount + uiMoneyInPlayersOfferArea ) - uiArmsDealersItemsCost;
//if there is change
if( iChangeToGiveToPlayer > 0 )
{
GivePlayerSomeChange( iChangeToGiveToPlayer );
if( uiArmsDealersItemsCost > 0 )
{
StartShopKeeperTalking( SK_QUOTES_PLAYER_HAS_TOO_MUCH_MONEY_FOR_TRANSACTION );
}
}
else
StartShopKeeperTalking( SK_QUOTES_PLAYER_HAS_EXACTLY_ENOUGH_MONEY_FOR_TRANSACTION );
}
// move the offered items to the repairman's inventory
MovePlayersItemsToBeRepairedToArmsDealersInventory();
}
else
{
//the player doesn't have enough money
return;
}
}
else // non-repairman
{
// DON'T include uiMoneyFromPlayersAccount in change given to player. The only way this can happen is if he agrees
// to subtract from his balance, but there isn't enough room. In that case, the cost of items not transfered is
// used to reduce his balance deduction instead (not here, in the calling function).
iChangeToGiveToPlayer = CalculateTotalPlayersValue() - uiArmsDealersItemsCost;
//if the arms dealer buys stuff
if( ( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_BUYS_ONLY ) ||
( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_BUYS_SELLS ) )
{
// but the dealer can't afford this transaction
if( iChangeToGiveToPlayer > ( INT32 ) gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash )
{
// HACK HACK HACK: We forgot to write/record quote 27 for Jake, so he ALWAYS must have enough money!
if ( gbSelectedArmsDealerID != ARMS_DEALER_JAKE )
{
// no deal - dealer can't afford it
StartShopKeeperTalking( SK_QUOTES_CANT_AFFORD_TO_BUY_OR_TOO_MUCH_TO_REPAIR );
gfResetShopKeepIdleQuote = TRUE;
return;
}
}
}
//Move all the player's evaluated items to the dealer
MovePlayerOfferedItemsOfValueToArmsDealersInventory();
//Move all dealers offered items to the player
MoveAllArmsDealersItemsInOfferAreaToPlayersOfferArea( );
//if the arms dealer is the type of person to give change
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].uiFlags & ARMS_DEALER_GIVES_CHANGE )
{
if( iChangeToGiveToPlayer > 0 )
{
GivePlayerSomeChange( iChangeToGiveToPlayer );
/*
//Remove the change the arms dealer is returning to the player
if( ( gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash - uiChangeToGiveToPlayer ) >= 0 )
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash -= uiChangeToGiveToPlayer;
else
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash = 0;
*/
if( uiArmsDealersItemsCost == 0 )
{
StartShopKeeperTalking( SK_QUOTES_PLAYER_HAS_EXACTLY_ENOUGH_MONEY_FOR_TRANSACTION );
}
else
{
StartShopKeeperTalking( SK_QUOTES_PLAYER_HAS_TOO_MUCH_MONEY_FOR_TRANSACTION );
}
}
else if( iChangeToGiveToPlayer == 0 )
StartShopKeeperTalking( SK_QUOTES_PLAYER_HAS_EXACTLY_ENOUGH_MONEY_FOR_TRANSACTION );
}
//if the arms dealer is tony
if( gbSelectedArmsDealerID == ARMS_DEALER_TONY )
gfHavePurchasedItemsFromTony = TRUE;
//if the arms dealer is Howard( 125), set fact 222
if( gbSelectedArmsDealerID == ARMS_DEALER_HOWARD )
SetFactTrue( 222 );
}
// add cash transfered from player's account directly to dealer's cash balance
if( uiMoneyFromPlayersAccount > 0 )
{
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash += uiMoneyFromPlayersAccount;
}
//Redraw the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
gfDoneBusinessThisSession = TRUE;
//The shopkeeper's inventory has changed, reinitialize
InitializeShopKeeper( FALSE );
}
gfResetShopKeepIdleQuote = TRUE;
return;
}
void MoveAllArmsDealersItemsInOfferAreaToPlayersOfferArea( )
{
//for all items in the dealers items offer area
UINT32 uiCnt;
UINT32 uiTotal=0;
INT8 bSlotID=0;
//loop through all the slots in the shopkeeper's offer area
for( uiCnt=0; uiCnt<SKI_NUM_TRADING_INV_SLOTS; uiCnt++)
{
//if there is an item here
if( ArmsDealerOfferArea[ uiCnt ].fActive )
{
bSlotID = AddItemToPlayersOfferArea( NO_PROFILE, &ArmsDealerOfferArea[ uiCnt ], -1 );
if( bSlotID != -1 )
{
PlayersOfferArea[ bSlotID ].uiFlags |= ARMS_INV_JUST_PURCHASED;
//if the player has just purchased a VIDEO_CAMERA from Franz Hinkle
if( ( gbSelectedArmsDealerID == ARMS_DEALER_FRANZ ) && ( ArmsDealerOfferArea[ uiCnt ].sItemIndex == VIDEO_CAMERA ) )
{
// set a special flag
gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags |= ARMS_DEALER_FLAG__FRANZ_HAS_SOLD_VIDEO_CAMERA_TO_PLAYER;
}
}
//Remove the items out of the dealers inventory
RemoveItemFromDealersInventory( &ArmsDealerOfferArea[ uiCnt ], (UINT8)ArmsDealerOfferArea[ uiCnt ].bSlotIdInOtherLocation );
//Remove the items from the Shopkeepers Offer area
if( !RemoveItemFromArmsDealerOfferArea( (UINT8)uiCnt, FALSE ) )//ArmsDealerOfferArea[uiCnt].bSlotIdInOtherLocation
Assert( 0 );
if( ArmsDealerOfferArea[uiCnt].fActive )
Assert(0);
}
}
//loop through all the slots in the shopkeeper's offer area
for( uiCnt=0; uiCnt<SKI_NUM_TRADING_INV_SLOTS; uiCnt++)
{
if( ArmsDealerOfferArea[uiCnt].fActive )
Assert(0);
}
}
BOOLEAN RemoveItemFromDealersInventory( INVENTORY_IN_SLOT* pInvSlot, UINT8 ubSlot )
{
INT16 sInvSlot;
INT16 sItemID;
SPECIAL_ITEM_INFO SpclItemInfo;
sInvSlot = ubSlot;
// sInvSlot = ( gSelectArmsDealerInfo.ubCurrentPage - 1 ) * SKI_NUM_ARMS_DEALERS_INV_SLOTS + ubSlot;
//Remove all of this item out of the specified inventory slot
sItemID = gpTempDealersInventory[ sInvSlot ].sItemIndex;
SetSpecialItemInfoFromObject( &SpclItemInfo, &(pInvSlot->ItemObject) );
RemoveItemFromArmsDealerInventory( gbSelectedArmsDealerID, sItemID, &SpclItemInfo, pInvSlot->ItemObject.ubNumberOfObjects );
gfResetShopKeepIdleQuote = TRUE;
return( TRUE );
}
void MovePlayerOfferedItemsOfValueToArmsDealersInventory()
{
UINT32 uiCnt;
//loop through all the slots in the players offer area
for( uiCnt=0; uiCnt<SKI_NUM_TRADING_INV_SLOTS; uiCnt++)
{
//if there is an item here
if( PlayersOfferArea[ uiCnt ].fActive )
{
// and it has value
if( PlayersOfferArea[ uiCnt ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE )
{
//Remove the item from the owner merc's inventory
IfMercOwnedRemoveItemFromMercInv( &(PlayersOfferArea[ uiCnt ]) );
//if the item is money
if( Item[ PlayersOfferArea[ uiCnt ].sItemIndex ].usItemClass == IC_MONEY )
{
//add the money to the dealers 'cash'
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash += PlayersOfferArea[ uiCnt ].ItemObject.uiMoneyAmount;
}
else
{
//if the dealer doesn't strictly buy items from the player, give the item to the dealer
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_BUYS_ONLY )
{
// item cease to be merc-owned during this operation
AddObjectToArmsDealerInventory( gbSelectedArmsDealerID, &( PlayersOfferArea[ uiCnt ].ItemObject ) );
}
}
//erase the item from the player's offer area
ClearPlayersOfferSlot( uiCnt );
}
}
}
gfResetShopKeepIdleQuote = TRUE;
}
void BeginSkiItemPointer( UINT8 ubSource, INT8 bSlotNum, BOOLEAN fOfferToDealerFirst )
{
SGPRect Rect;
OBJECTTYPE TempObject;
/*
// If we are already moving an item
if ( gMoveingItem.sItemIndex != 0 )
{
return;
}
*/
switch( ubSource )
{
case ARMS_DEALER_INVENTORY:
//Should never get in here
Assert( 0 );
return;
break;
case ARMS_DEALER_OFFER_AREA:
//Get the item from the slot.
memcpy( &gMoveingItem, &ArmsDealerOfferArea[ bSlotNum ], sizeof( INVENTORY_IN_SLOT ) );
IfMercOwnedRemoveItemFromMercInv( &gMoveingItem );
//remove the item from the slot
ClearArmsDealerOfferSlot( bSlotNum );
//Restrict the cursor to the arms dealer offer area, players offer area and the players inventory
Rect.iLeft = 0;//SKI_ITEM_MOVEMENT_AREA_X;
Rect.iTop = SKI_DEALER_OFFER_AREA_Y;
Rect.iRight = SKI_ITEM_MOVEMENT_AREA_X + SKI_ITEM_MOVEMENT_AREA_WIDTH;
Rect.iBottom = SKI_ITEM_MOVEMENT_AREA_Y + SKI_ITEM_MOVEMENT_AREA_HEIGHT;
gpItemPointer = &gMoveingItem.ItemObject;
//if there is an owner of the item
if( gMoveingItem.ubIdOfMercWhoOwnsTheItem != -1 )
{
gpItemPointerSoldier = FindSoldierByProfileID( gMoveingItem.ubIdOfMercWhoOwnsTheItem, TRUE );
//make sure the soldier is not null
if( gpItemPointerSoldier == NULL )
{
gpItemPointerSoldier = gpSMCurrentMerc;
}
}
else
gpItemPointerSoldier = gpSMCurrentMerc;
break;
case PLAYERS_OFFER_AREA:
//Get the item from the slot.
memcpy( &gMoveingItem, &PlayersOfferArea[ bSlotNum ], sizeof( INVENTORY_IN_SLOT ) );
// if the slot is overloaded (holds more objects than we have room for valid statuses of)
if ( PlayersOfferArea[ bSlotNum ].ItemObject.ubNumberOfObjects > MAX_OBJECTS_PER_SLOT )
{
// allow only MAX_OBJECTS_PER_SLOT of those objects to be picked up at a time
// (sure it kind of sucks, but it's a lot easier than handling overloaded cursor objects in Interface Items!
gMoveingItem.ItemObject.ubNumberOfObjects = MAX_OBJECTS_PER_SLOT;
// decrease the number objects left in the slot by that much instead of deleting it
PlayersOfferArea[ bSlotNum ].ItemObject.ubNumberOfObjects -= MAX_OBJECTS_PER_SLOT;
}
else // completely legal object
{
// NOTE: a merc-owned object can never be "overloaded", so no problem here
IfMercOwnedRemoveItemFromMercInv( &gMoveingItem );
//remove the item from the slot
ClearPlayersOfferSlot( bSlotNum );
}
//Restrict the cursor to the players offer area and the players inventory
Rect.iLeft = 0;//SKI_ITEM_MOVEMENT_AREA_X;
Rect.iTop = SKI_ITEM_MOVEMENT_AREA_Y;
Rect.iRight = SKI_ITEM_MOVEMENT_AREA_X + SKI_ITEM_MOVEMENT_AREA_WIDTH;
Rect.iBottom = SKI_ITEM_MOVEMENT_AREA_Y + SKI_ITEM_MOVEMENT_AREA_HEIGHT;
gpItemPointer = &gMoveingItem.ItemObject;
//if there is an owner of the item
if( gMoveingItem.ubIdOfMercWhoOwnsTheItem != -1 )
{
gpItemPointerSoldier = FindSoldierByProfileID( gMoveingItem.ubIdOfMercWhoOwnsTheItem, TRUE );
//make sure the soldier is not null
if( gpItemPointerSoldier == NULL )
{
gpItemPointerSoldier = gpSMCurrentMerc;
}
}
else
gpItemPointerSoldier = gpSMCurrentMerc;
break;
case PLAYERS_INVENTORY:
// better be a valid merc pocket index, or -1
Assert( ( bSlotNum >= -1 ) && ( bSlotNum < NUM_INV_SLOTS ) );
// if we're supposed to store the original pocket #, but that pocket still holds more of these
if ( ( bSlotNum != -1 ) && ( gpSMCurrentMerc->inv[ bSlotNum ].ubNumberOfObjects > 0 ) )
{
// then we can't store the pocket #, because our system can't return stacked objects
bSlotNum = -1;
}
// First try to evaluate the item immediately like any other left-click on a merc's inventory slot would be. Only
// if that doesn't work (because there isn't enough room in the player's offer area), the item is picked up into
// the cursor, and may then get placed into the player's offer area directly, but it will NOT get evaluated that
// way, and so has no possibility of entering the dealer's inventory (where complex items aren't permitted).
if ( fOfferToDealerFirst && OfferObjectToDealer( gpItemPointer, gpSMCurrentMerc->ubProfile, bSlotNum ) )
{
//Reset the cursor
SetSkiCursor( CURSOR_NORMAL );
}
else // not supposed to offer it, or dealer has no more room
{
// store the current contents of the cursor in a temporary object structure.
// We have to do this before memsetting gMoveingItem, 'cause during swaps, gpItemPointer == &gMoveingItem.ItemObject!
CopyObj( gpItemPointer, &TempObject );
//ARM: The memset was previously commented out, in order to preserve the owning merc's inv slot # during a swap of
// items in an inventory slot. However, that leads to other bugs: if you picked the thing you're swapping in from
// a restricted inv slot (headgear, vest, etc.), the item swapped out will end up belonging to an illegal slot, and
// return there with a right click on it in the player's offer area. So now ALL items picked up here are unowned.
memset( &gMoveingItem, 0, sizeof( INVENTORY_IN_SLOT ) );
//Get the item from the pointer
memcpy( &gMoveingItem.ItemObject, &TempObject, sizeof( OBJECTTYPE ) );
gMoveingItem.fActive = TRUE;
gMoveingItem.sItemIndex = TempObject.usItem;
gMoveingItem.ubLocationOfObject = ubSource;
// By necessity, these items don't belong to a slot (so you can't return them via a right click),
// because it would be too much work to handle attachments, members of a stack, or even items swapped out of slots.
gMoveingItem.ubIdOfMercWhoOwnsTheItem = gpSMCurrentMerc->ubProfile;
gMoveingItem.bSlotIdInOtherLocation = bSlotNum;
//Restrict the cursor to the players offer area and the players inventory
Rect.iLeft = 0;//SKI_ITEM_MOVEMENT_AREA_X;
Rect.iTop = SKI_ITEM_MOVEMENT_AREA_Y;
Rect.iRight = SKI_ITEM_MOVEMENT_AREA_X + SKI_ITEM_MOVEMENT_AREA_WIDTH;
Rect.iBottom = SKI_ITEM_MOVEMENT_AREA_Y + SKI_ITEM_MOVEMENT_AREA_HEIGHT;
gpItemPointer = &gMoveingItem.ItemObject;
gpItemPointerSoldier = gpSMCurrentMerc;
}
break;
}
// if we have something in hand
if ( gpItemPointer != NULL )
{
//make sure the soldier is not null
Assert( gpItemPointerSoldier != NULL );
// Set mouse
SetSkiCursor( EXTERN_CURSOR );
//Enable the region that limits the movement of the cursor with the item
MSYS_EnableRegion( &gSkiInventoryMovementAreaMouseRegions );
RestrictMouseCursor( &Rect );
DisableAllDealersInventorySlots();
if ( ubSource != ARMS_DEALER_OFFER_AREA )
{
DisableAllDealersOfferSlots();
}
gfResetShopKeepIdleQuote = TRUE;
}
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
void RestrictSkiMouseCursor()
{
SGPRect Rect;
Rect.iLeft = 0;//SKI_ITEM_MOVEMENT_AREA_X;
Rect.iTop = SKI_ITEM_MOVEMENT_AREA_Y;
Rect.iRight = SKI_ITEM_MOVEMENT_AREA_X + SKI_ITEM_MOVEMENT_AREA_WIDTH;
Rect.iBottom = SKI_ITEM_MOVEMENT_AREA_Y + SKI_ITEM_MOVEMENT_AREA_HEIGHT;
RestrictMouseCursor( &Rect );
}
void SetSkiCursor( UINT16 usCursor )
{
UINT8 ubCnt;
//if we are setting up an item as a cursor
if( usCursor == EXTERN_CURSOR )
{
// EnableSMPanelButtons( FALSE, FALSE );
// if the current merc is in range
if( !gfSMDisableForItems )
{
// hatch out unavailable merc inventory slots
ReevaluateItemHatches( gpSMCurrentMerc, FALSE );
}
// Set mouse
guiExternVo = GetInterfaceGraphicForItem( &(Item[ gMoveingItem.sItemIndex ]) );
gusExternVoSubIndex = Item[ gMoveingItem.sItemIndex ].ubGraphicNum;
SetCurrentCursorFromDatabase( EXTERN_CURSOR );
MSYS_ChangeRegionCursor( &gSMPanelRegion, usCursor );
MSYS_ChangeRegionCursor( &gSKI_EntireScreenMouseRegions, usCursor );
MSYS_ChangeRegionCursor( &gArmsDealersDropItemToGroundMouseRegions, usCursor );
MSYS_SetCurrentCursor( usCursor );
//if the item desc window is up
if( gInvDesc.uiFlags & MSYS_REGION_EXISTS )
MSYS_ChangeRegionCursor( &gInvDesc, usCursor );
for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++)
{
if( gItemDescAttachmentRegions[ubCnt].uiFlags & MSYS_REGION_EXISTS )
MSYS_ChangeRegionCursor( &gItemDescAttachmentRegions[ubCnt], usCursor );
}
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
MSYS_ChangeRegionCursor( &gPlayersOfferSlotsMouseRegions[ ubCnt], usCursor );
MSYS_ChangeRegionCursor( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubCnt], usCursor );
MSYS_ChangeRegionCursor( &gDealersOfferSlotsMouseRegions[ ubCnt], usCursor );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_ChangeRegionCursor( &gDealersOfferSlotsSmallFaceMouseRegions[ ubCnt], usCursor );
}
}
MSYS_ChangeRegionCursor( &gSkiInventoryMovementAreaMouseRegions, usCursor );
}
//else we are restoring the old cursor
else
{
memset( &gMoveingItem, 0, sizeof( INVENTORY_IN_SLOT ) );
// gpSkiItemPointer = NULL;
gpItemPointer = NULL;
DisableTacticalTeamPanelButtons( FALSE );
// EnableSMPanelButtons( TRUE, FALSE );
// CheckForDisabledForGiveItem( );
// if the current merc is in range
if( !gfSMDisableForItems )
{
// make all merc inventory slots available again
ReevaluateItemHatches( gpSMCurrentMerc, TRUE );
}
MSYS_ChangeRegionCursor( &gSMPanelRegion, usCursor );
MSYS_ChangeRegionCursor( &gSKI_EntireScreenMouseRegions, usCursor );
MSYS_ChangeRegionCursor( &gArmsDealersDropItemToGroundMouseRegions, usCursor );
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
MSYS_ChangeRegionCursor( &gPlayersOfferSlotsMouseRegions[ ubCnt ], usCursor );
MSYS_ChangeRegionCursor( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubCnt ], usCursor );
MSYS_ChangeRegionCursor( &gDealersOfferSlotsMouseRegions[ ubCnt ], usCursor );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_ChangeRegionCursor( &gDealersOfferSlotsSmallFaceMouseRegions[ ubCnt ], usCursor );
}
}
//if the item desc window is up
if( gInvDesc.uiFlags & MSYS_REGION_EXISTS )
MSYS_ChangeRegionCursor( &gInvDesc, usCursor );
for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++)
{
if( gItemDescAttachmentRegions[ubCnt].uiFlags & MSYS_REGION_EXISTS )
MSYS_ChangeRegionCursor( &gItemDescAttachmentRegions[ubCnt], usCursor );
}
MSYS_ChangeRegionCursor( &gSkiInventoryMovementAreaMouseRegions, usCursor );
MSYS_SetCurrentCursor( usCursor );
SetCurrentCursorFromDatabase( usCursor );
FreeMouseCursor();
EnableAllDealersInventorySlots();
EnableAllDealersOfferSlots();
//Disable the region that limits the movement of the cursor with the item
MSYS_DisableRegion( &gSkiInventoryMovementAreaMouseRegions );
}
SetCurrentCursorFromDatabase( usCursor );
// make sure disabled slot hatching gets updated when items picked up / dropped
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
INT8 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT8 ubSpotLocation, UINT8 ubWhere )
{
INT8 bSlotAddedTo = -1;
switch( ubWhere )
{
case ARMS_DEALER_INVENTORY:
case PLAYERS_INVENTORY:
// not used this way
Assert( 0 );
return( bSlotAddedTo );
break;
case ARMS_DEALER_OFFER_AREA:
//If we can add the item into the slot that was clicked on
if( ArmsDealerOfferArea[ ubSpotLocation ].fActive == FALSE )
{
memcpy( &ArmsDealerOfferArea[ ubSpotLocation ], pInv, sizeof( INVENTORY_IN_SLOT ) );
IfMercOwnedCopyItemToMercInv( pInv );
SetSkiRegionHelpText( &ArmsDealerOfferArea[ ubSpotLocation ], &gDealersOfferSlotsMouseRegions[ ubSpotLocation ], ARMS_DEALER_OFFER_AREA );
SetSkiFaceRegionHelpText( &ArmsDealerOfferArea[ ubSpotLocation ], &gDealersOfferSlotsSmallFaceMouseRegions[ ubSpotLocation ], ARMS_DEALER_OFFER_AREA );
bSlotAddedTo = ubSpotLocation;
}
else
{
bSlotAddedTo = AddItemToArmsDealerOfferArea( pInv, -1 );
}
break;
case PLAYERS_OFFER_AREA:
//If we can add the item into the slot that was clicked on
if( PlayersOfferArea[ ubSpotLocation ].fActive == FALSE )
{
// put it down in that player offer area slot
memcpy( &PlayersOfferArea[ ubSpotLocation ], pInv, sizeof( INVENTORY_IN_SLOT ) );
IfMercOwnedCopyItemToMercInv( pInv );
//if the item is money
if( Item[ PlayersOfferArea[ ubSpotLocation ].sItemIndex ].usItemClass == IC_MONEY )
{
//Since money is always evaluated
PlayersOfferArea[ ubSpotLocation ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
PlayersOfferArea[ ubSpotLocation ].uiItemPrice = PlayersOfferArea[ ubSpotLocation ].ItemObject.uiMoneyAmount;
}
SetSkiRegionHelpText( &PlayersOfferArea[ ubSpotLocation ], &gPlayersOfferSlotsMouseRegions[ ubSpotLocation ], PLAYERS_OFFER_AREA );
SetSkiFaceRegionHelpText( &PlayersOfferArea[ ubSpotLocation ], &gPlayersOfferSlotsSmallFaceMouseRegions[ ubSpotLocation ], PLAYERS_OFFER_AREA );
bSlotAddedTo = ubSpotLocation;
}
// else if( )
// {
//check to see the type we are adding is the same as the type that is already there
// }
else // that slot is full
{
// add it elsewhere
bSlotAddedTo = AddItemToPlayersOfferArea( pInv->ubIdOfMercWhoOwnsTheItem, pInv, pInv->bSlotIdInOtherLocation );
}
break;
}
//Redraw the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL1;
gfResetShopKeepIdleQuote = TRUE;
fInterfacePanelDirty = DIRTYLEVEL2;
return( bSlotAddedTo );
}
void DisplayTalkingArmsDealer()
{
static BOOLEAN fWasTheMercTalking= FALSE;
// static UINT32 uiLastTime=0;
// UINT32 uiCurTime = GetJA2Clock();
// static UINT32 uiMinimumLengthForTalkingText;
//Make sure the Dealers doesn't get disabled
gFacesData[ giShopKeeperFaceIndex ].fDisabled = FALSE;
HandleDialogue();
//Gets handled when we render the tactical interface
HandleAutoFaces( );
HandleTalkingAutoFaces( );
HandleShopKeeperDialog( 0 );
gfIsTheShopKeeperTalking = gFacesData[ giShopKeeperFaceIndex ].fTalking;
//if the merc just started talking
// if( gfIsTheShopKeeperTalking && !fWasTheMercTalking )
{
}
//if the merc is talking
if( gfIsTheShopKeeperTalking )
fWasTheMercTalking = TRUE;
//if the merc just finished talking
if( !gfIsTheShopKeeperTalking && fWasTheMercTalking )
{
RemoveShopKeeperSubTitledText();
fWasTheMercTalking = FALSE;
}
}
void HandleShopKeeperDialog( UINT8 ubInit )
{
UINT32 uiCurTime = GetJA2Clock();
static UINT32 uiLastTime = 0;
static UINT32 uiLastTimeSpoke = 0;
static INT8 bSpeech = -1;
if( ubInit >= 1 )
{
uiLastTime = GetJA2Clock();
}
if( ubInit == 1 )
{
// special: if it's Arnie, and we have stuff in for repairs, but it's not fixed yet, use a different opening quote!
if ( ( gbSelectedArmsDealerID == ARMS_DEALER_ARNIE ) && RepairmanIsFixingItemsButNoneAreDoneYet( ARNIE ) )
{
bSpeech = ARNIE_QUOTE_NOT_REPAIRED_YET;
}
// if repairs were delayed
if ( gfStartWithRepairsDelayedQuote )
{
bSpeech = FREDO_PERKO_SORRY_REPAIR_DELAYED;
gfStartWithRepairsDelayedQuote = FALSE;
// treat this as having done business - the player WAS here for a good reason, and it's the dealers fault...
gfDoneBusinessThisSession = TRUE;
}
else
{
bSpeech = SK_QUOTES_PLAYER_FIRST_ENTERS_SKI;
}
return;
}
//if its the first time in
if( bSpeech != -1 )
{
if( ( uiCurTime - uiLastTime ) > 800 )
{
uiLastTimeSpoke = GetJA2Clock();
StartShopKeeperTalking( bSpeech );
bSpeech = -1;
uiLastTime = GetJA2Clock();
}
}
//Handle Idle converstions
if( gfIsTheShopKeeperTalking )
{
uiLastTime = uiCurTime;
}
//if the player has requested to leave
else if( gfUserHasRequestedToLeave && ( giShopKeepDialogueEventinProgress == -1 ) )
{
// to see if the player has finished talking
if( !gFacesData[ giShopKeeperFaceIndex ].fTalking )
{
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 5, 0, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
}
DealWithItemsStillOnTheTable();
}
else
{
// Determine if the shopkeeper should say a quote
if( ( uiCurTime - uiLastTime ) > ( guiRandomQuoteDelayTime + Random( guiRandomQuoteDelayTime ) ) )
{
//Only say it occasionally
if( Chance ( 35 ) )
{
INT16 sRandomQuoteToUse = -1;
// first check if one of the situation warrants one of the more precise quotes
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
// if there are items in the arms dealer's offer area (must be awaiting repairs)
if ( CountNumberOfItemsInTheArmsDealersOfferArea() > 0)
{
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_ITEMS_CHOSEN_TO_SELL_OR_REPAIR;
}
}
else // non-repairman
{
// if there is any items in the player's area with value to this dealer other than just money
if ( ( CalculateTotalPlayersValue() - CalculateHowMuchMoneyIsInPlayersOfferArea( ) ) > 0 )
{
// if the player has also selected some items for purchase
if ( CountNumberOfItemsInTheArmsDealersOfferArea() > 0 )
{
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_ITEMS_CHOSEN_TO_TRADE;
}
else
{
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_ITEMS_CHOSEN_TO_SELL_OR_REPAIR;
}
}
}
// if neither of the more precise quotes fit, or 33 percent of the time anyways
if ( ( sRandomQuoteToUse == -1 ) || Chance( 33 ) )
{
if( Chance ( 50 ) )
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_PLAYER_DECIDING_1;
else
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_PLAYER_DECIDING_2;
}
Assert( sRandomQuoteToUse != -1 );
Assert( sRandomQuoteToUse < NUM_COMMON_SK_QUOTES );
if ( !gfCommonQuoteUsedThisSession[ sRandomQuoteToUse ] )
{
StartShopKeeperTalking( (UINT16) sRandomQuoteToUse );
gfCommonQuoteUsedThisSession[ sRandomQuoteToUse ] = TRUE;
//increase the random quote delay
guiRandomQuoteDelayTime += SKI_DEALERS_RANDOM_QUOTE_DELAY_INCREASE_RATE;
}
}
uiLastTime = GetJA2Clock();
}
}
}
BOOLEAN StartShopKeeperTalking( UINT16 usQuoteNum )
{
BOOLEAN fSuccess;
// if already in the process of leaving, don't start any additional quotes
if ( gfSKIScreenExit || gfRemindedPlayerToPickUpHisStuff || gfUserHasRequestedToLeave )
{
return( FALSE );
}
// post event to mark shopkeeper dialogue in progress
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 3, usQuoteNum, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
// post quote dialogue
fSuccess = CharacterDialogue( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID, usQuoteNum, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI, FALSE, FALSE );
// post event to mark shopkeeper dialogue as ended
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 4, usQuoteNum, 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
if ( !fSuccess )
{
return( FALSE );
}
gfResetShopKeepIdleQuote = TRUE;
return( TRUE );
}
BOOLEAN IsGunOrAmmoOfSameTypeSelected( OBJECTTYPE *pItemObject )
{
//if there is no item selected, return
if( gpHighLightedItemObject == NULL )
return( FALSE );
//if the item is ammo
if( Item[ gpHighLightedItemObject->usItem ].usItemClass == IC_AMMO )
{
//if there is a gun
if( Item[ pItemObject->usItem ].usItemClass == IC_GUN )
{
//of the same caliber
if( Weapon[ pItemObject->usItem ].ubCalibre == Magazine[ Item[ gpHighLightedItemObject->usItem ].ubClassIndex ].ubCalibre )
{
return( TRUE );
}
}
}
//else if the item is a gun
else if( Item[ gpHighLightedItemObject->usItem ].usItemClass == IC_GUN )
{
//if there is a gun
if( Item[ pItemObject->usItem ].usItemClass == IC_AMMO )
{
//of the same caliber
if( Weapon[ gpHighLightedItemObject->usItem ].ubCalibre == Magazine[ Item[ pItemObject->usItem ].ubClassIndex ].ubCalibre )
{
return( TRUE );
}
}
}
//if the highlighted object is an attachment
// if( Item[ pItemObject->usItem ].fFlags & ITEM_ATTACHMENT )
if( Item[ pItemObject->usItem ].attachment )
{
if( ValidAttachment( pItemObject->usItem, gpHighLightedItemObject->usItem ) )
return( TRUE );
}
else
{
if( ValidAttachment( gpHighLightedItemObject->usItem, pItemObject->usItem ) )
return( TRUE );
}
return( FALSE );
}
void InitShopKeeperSubTitledText( STR16 pString )
{
//Clear the contents of the subtitle text
memset( gsShopKeeperTalkingText, 0, SKI_SUBTITLE_TEXT_SIZE );
#ifdef TAIWANESE
swprintf( gsShopKeeperTalkingText, L"%s", pString );
#else
swprintf( gsShopKeeperTalkingText, L"\"%s\"", pString );
#endif
//Now setup the popup box
if( gGameSettings.fOptions[ TOPTION_SUBTITLES ] )
{
UINT16 usActualWidth=0;
UINT16 usActualHeight=0;
SET_USE_WINFONTS( TRUE );
SET_WINFONT( giSubTitleWinFont );
giPopUpBoxId = PrepareMercPopupBox( giPopUpBoxId, BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gsShopKeeperTalkingText, 300, 0, 0, 0, &usActualWidth, &usActualHeight);
SET_USE_WINFONTS( FALSE );
// gusPositionOfSubTitlesX = ( 640 - usActualWidth ) / 2 ;
//position it to start under the guys face
gusPositionOfSubTitlesX = 13 + SCREEN_X_OFFSET;
RenderMercPopUpBoxFromIndex( giPopUpBoxId, gusPositionOfSubTitlesX, SKI_POSITION_SUBTITLES_Y, FRAME_BUFFER);
//check to make sure the region is not already initialized
if( !( gShopKeeperSubTitleMouseRegion.uiFlags & MSYS_REGION_EXISTS ) )
{
MSYS_DefineRegion( &gShopKeeperSubTitleMouseRegion, gusPositionOfSubTitlesX, SKI_POSITION_SUBTITLES_Y, (INT16)(gusPositionOfSubTitlesX + usActualWidth), (INT16)(SKI_POSITION_SUBTITLES_Y + usActualHeight), MSYS_PRIORITY_HIGH,
CURSOR_NORMAL, MSYS_NO_CALLBACK, ShopKeeperSubTitleRegionCallBack );
MSYS_AddRegion( &gShopKeeperSubTitleMouseRegion );
}
//redraw the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
void RemoveShopKeeperSubTitledText()
{
if( giPopUpBoxId == -1 )
return;
if( RemoveMercPopupBoxFromIndex( giPopUpBoxId ) )
{
giPopUpBoxId = -1;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
//Get rid of the subtitles region
if( gGameSettings.fOptions[ TOPTION_SUBTITLES ] )
MSYS_RemoveRegion( &gShopKeeperSubTitleMouseRegion );
}
}
BOOLEAN AreThereItemsInTheArmsDealersOfferArea( )
{
UINT8 ubCnt;
//loop through the players offer area and see if there are any items there
for( ubCnt = 0; ubCnt < SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if is an item here
if( ArmsDealerOfferArea[ ubCnt ].fActive )
{
return( TRUE );
}
}
return( FALSE );
}
BOOLEAN AreThereItemsInThePlayersOfferArea( )
{
UINT8 ubCnt;
//loop through the players offer area and see if there are any items there
for( ubCnt = 0; ubCnt < SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if is an item here
if( PlayersOfferArea[ ubCnt ].fActive )
{
return( TRUE );
}
}
return( FALSE );
}
//Mouse Call back for the Arms traders inventory slot
void ShopKeeperSubTitleRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP || iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
{
ShutUpShopKeeper();
}
}
//Mouse Call back for the Arms delaers face
void SelectArmsDealersFaceRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP || iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
{
ShutUpShopKeeper();
}
}
void ShutUpShopKeeper()
{
// RemoveShopKeeperSubTitledText();
ShutupaYoFace( giShopKeeperFaceIndex );
gfIsTheShopKeeperTalking = FALSE;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
UINT8 CountNumberOfValuelessItemsInThePlayersOfferArea( )
{
UINT8 ubCnt;
UINT8 ubCount=0;
//loop through the players offer area and see if there are any items there
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if is an item here
if( PlayersOfferArea[ubCnt].fActive )
{
//and if it has no value
if( !( PlayersOfferArea[ubCnt].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE ) )
{
ubCount++;
}
}
}
return( ubCount );
}
UINT8 CountNumberOfItemsOfValueInThePlayersOfferArea( )
{
UINT8 ubCnt;
UINT8 ubCount=0;
//loop through the players offer area and see if there are any items there
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if is an item here
if( PlayersOfferArea[ubCnt].fActive )
{
//and if it has not been evaluated
if( PlayersOfferArea[ubCnt].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE )
{
ubCount++;
}
}
}
return( ubCount );
}
UINT8 CountNumberOfItemsInThePlayersOfferArea( )
{
UINT8 ubCnt;
UINT8 ubItemCount=0;
//loop through the player's offer area and see if there are any items there
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if is an item here
if( PlayersOfferArea[ubCnt].fActive )
{
ubItemCount++;
}
}
return( ubItemCount );
}
UINT8 CountNumberOfItemsInTheArmsDealersOfferArea( )
{
UINT8 ubCnt;
UINT8 ubItemCount=0;
//loop through the dealer's offer area and see if there are any items there
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if is an item here
if( ArmsDealerOfferArea[ubCnt].fActive )
{
ubItemCount++;
}
}
return( ubItemCount );
}
INT8 GetSlotNumberForMerc( UINT8 ubProfile )
{
INT8 bCnt;
for( bCnt = 0; bCnt < gubNumberMercsInArray; bCnt++ )
{
if( gubArrayOfEmployedMercs[ bCnt ] == ubProfile )
return( bCnt );
}
// not found - not currently working for the player
return( -1 );
}
void RenderSkiAtmPanel()
{
// HVOBJECT hPixHandle;
//Get the Atm background panel graphic and blt it
// GetVideoObject(&hPixHandle, guiSkiAtmImage );
// BltVideoObject(FRAME_BUFFER, hPixHandle, 0,SKI_ATM_PANEL_X, SKI_ATM_PANEL_Y, VO_BLT_SRCTRANSPARENCY,NULL);
}
void CreateSkiAtmButtons()
{
UINT16 usPosX, usPosY;
UINT8 ubCount=0;
UINT8 ubCnt;
guiSKI_AtmNumButtonImage = LoadButtonImage("INTERFACE\\TradeScreenAtm.sti", 1,2,-1,3,-1 );
guiSKI_AtmOkButtonImage = UseLoadedButtonImage( guiSKI_AtmNumButtonImage, 4,5,-1,6,-1 );
guiSKI_AtmSideMenuButtonImage = UseLoadedButtonImage( guiSKI_AtmNumButtonImage, 7,8,-1,9,-1 );
//Create the number buttons
usPosX = SKI_ATM_BUTTON_X;
usPosY = SKI_ATM_BUTTON_Y;
ubCount=0;
for( ubCnt=SKI_ATM_1; ubCnt<=SKI_ATM_9;ubCnt++)
{
guiSKI_AtmButton[ubCnt] = CreateIconAndTextButton( guiSKI_AtmNumButtonImage, SkiAtmText[ubCnt], SKI_ATM_BUTTON_FONT,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
TEXT_CJUSTIFIED,
usPosX, usPosY, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH+2,
DEFAULT_MOVE_CALLBACK, BtnSKI_AtmButtonCallback );
SpecifyDisabledButtonStyle( guiSKI_AtmButton[ubCnt], DISABLED_STYLE_SHADED );
MSYS_SetBtnUserData(guiSKI_AtmButton[ubCnt], 0, ubCnt );
ubCount++;
usPosX += SKI_ATM_NUM_BUTTON_WIDTH;
if( ( ubCount % 3 ) == 0 )
{
usPosX = SKI_ATM_BUTTON_X;
usPosY += SKI_ATM_BUTTON_HEIGHT;
}
}
//Create the zero button
usPosX = SKI_ATM_BUTTON_X;
guiSKI_AtmButton[SKI_ATM_0] = CreateIconAndTextButton( guiSKI_AtmOkButtonImage, SkiAtmText[SKI_ATM_0], SKI_ATM_BUTTON_FONT,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
TEXT_CJUSTIFIED,
usPosX, usPosY, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH+2,
DEFAULT_MOVE_CALLBACK, BtnSKI_AtmButtonCallback );
MSYS_SetBtnUserData(guiSKI_AtmButton[SKI_ATM_0], 0, SKI_ATM_0 );
//Create the ok button
usPosX = SKI_ATM_BUTTON_X + SKI_ATM_NUM_BUTTON_WIDTH + 8;
guiSKI_AtmButton[SKI_ATM_OK] = CreateIconAndTextButton( guiSKI_AtmOkButtonImage, SkiAtmText[SKI_ATM_OK], SKI_ATM_BUTTON_FONT,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
TEXT_CJUSTIFIED,
usPosX, usPosY, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH+2,
DEFAULT_MOVE_CALLBACK, BtnSKI_AtmButtonCallback );
MSYS_SetBtnUserData(guiSKI_AtmButton[SKI_ATM_OK], 0, SKI_ATM_OK );
//Create the side menu text buttons
usPosX = SKI_ATM_BUTTON_X + SKI_ATM_SIDE_MENU_PANEL_START_X;
usPosY = SKI_ATM_BUTTON_Y;
for( ubCnt=SKI_ATM_TAKE; ubCnt<=SKI_ATM_CLEAR;ubCnt++ )
{
guiSKI_AtmButton[ubCnt] = CreateIconAndTextButton( guiSKI_AtmSideMenuButtonImage, SkiAtmText[ubCnt], SKI_ATM_BUTTON_FONT,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
SKI_ATM_BUTTON_COLOR, NO_SHADOW,
TEXT_CJUSTIFIED,
usPosX, usPosY, BUTTON_TOGGLE, MSYS_PRIORITY_HIGH+2,
DEFAULT_MOVE_CALLBACK, BtnSKI_AtmButtonCallback );
MSYS_SetBtnUserData(guiSKI_AtmButton[ubCnt], 0, ubCnt );
usPosY += SKI_ATM_BUTTON_HEIGHT;
}
//Enable/disable the appropriate buttons
//ATM:
// EnableDisableSkiAtmButtons();
}
void RemoveSkiAtmButtons()
{
UINT8 ubCnt;
//Remove atm images
UnloadButtonImage( guiSKI_AtmNumButtonImage );
UnloadButtonImage( guiSKI_AtmOkButtonImage );
UnloadButtonImage( guiSKI_AtmSideMenuButtonImage );
//Remove the atm buttons
for( ubCnt=0; ubCnt<NUM_SKI_ATM_BUTTONS;ubCnt++)
{
RemoveButton( guiSKI_AtmButton[ubCnt] );
}
}
void BtnSKI_AtmButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
{
btn->uiFlags |= BUTTON_CLICKED_ON;
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
if(reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
{
UINT8 ubButton = (UINT8) MSYS_GetBtnUserData( btn, 0 );
btn->uiFlags &= (~BUTTON_CLICKED_ON );
//ATM:
// HandleSkiAtmPanelInput( ubButton );
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
}
}
void HandleSkiAtmPanel( )
{
//Dispaly the appropriate text for the the curret atm mode
HandleCurrentModeText( gubCurrentSkiAtmMode );
//Display Atm transfer string
DisplaySkiAtmTransferString();
ToggleSkiAtmButtons();
}
void HandleSkiAtmPanelInput( UINT8 ubButtonPress )
{
//switch on the current mode
switch( ubButtonPress )
{
case SKI_ATM_1:
case SKI_ATM_2:
case SKI_ATM_3:
case SKI_ATM_4:
case SKI_ATM_5:
case SKI_ATM_6:
case SKI_ATM_7:
case SKI_ATM_8:
case SKI_ATM_9:
case SKI_ATM_0:
AddNumberToSkiAtm( ubButtonPress );
break;
case SKI_ATM_OK:
{
HandleAtmOK();
break;
}
case SKI_ATM_TAKE:
gubCurrentSkiAtmMode = SKI_ATM_TAKE_MODE;
EnableDisableSkiAtmButtons();
break;
case SKI_ATM_GIVE:
gubCurrentSkiAtmMode = SKI_ATM_GIVE_MODE;
EnableDisableSkiAtmButtons();
break;
case SKI_ATM_CANCEL:
memset( gzSkiAtmTransferString, 0, 32 );
gubCurrentSkiAtmMode = SKI_ATM_DISABLED_MODE;
EnableDisableSkiAtmButtons();
break;
case SKI_ATM_CLEAR:
memset( gzSkiAtmTransferString, 0, 32 );
break;
default:
Assert( 0 );
}
}
void HandleAtmOK()
{
INT32 iAmountToTransfer;
BOOLEAN fOkToClear=FALSE;
//Get the amount to transfer
swscanf( gzSkiAtmTransferString, L"%d", &iAmountToTransfer );
if( iAmountToTransfer == 0 )
return;
//if we are in an error mode
if( gubCurrentSkiAtmMode == SKI_ATM_ERR_TAKE_MODE )
gubCurrentSkiAtmMode = SKI_ATM_TAKE_MODE;
else if( gubCurrentSkiAtmMode == SKI_ATM_ERR_GIVE_MODE )
gubCurrentSkiAtmMode = SKI_ATM_GIVE_MODE;
//if we are in either the give or take mode, exit
if( gubCurrentSkiAtmMode != SKI_ATM_TAKE_MODE && gubCurrentSkiAtmMode != SKI_ATM_GIVE_MODE )
return;
//if we are taking money
if( gubCurrentSkiAtmMode == SKI_ATM_TAKE_MODE )
{
//are we trying to take more then the merc has
if( iAmountToTransfer > GetFundsOnMerc( gpSMCurrentMerc ) )
{
UINT32 uiFundsOnCurrentMerc = GetFundsOnMerc( gpSMCurrentMerc );
if( uiFundsOnCurrentMerc == 0 )
memset( gzSkiAtmTransferString, 0, 32 );
else
{
//Set the amount to transfer
swprintf( gzSkiAtmTransferString, L"%d", uiFundsOnCurrentMerc );
}
gubCurrentSkiAtmMode = SKI_ATM_ERR_TAKE_MODE;
HandleCurrentModeText( gubCurrentSkiAtmMode );
}
else
{
TransferFundsFromMercToBank( gpSMCurrentMerc, iAmountToTransfer );
fOkToClear=TRUE;
}
}
else if( gubCurrentSkiAtmMode == SKI_ATM_GIVE_MODE )
{
//are we tring to take more then we have?
if( iAmountToTransfer > LaptopSaveInfo.iCurrentBalance )
{
if( LaptopSaveInfo.iCurrentBalance == 0 )
memset( gzSkiAtmTransferString, 0, 32 );
else
{
//Set the amount to transfer
swprintf( gzSkiAtmTransferString, L"%d", LaptopSaveInfo.iCurrentBalance );
}
gubCurrentSkiAtmMode = SKI_ATM_ERR_GIVE_MODE;
HandleCurrentModeText( gubCurrentSkiAtmMode );
}
else
{
TransferFundsFromBankToMerc( gpSMCurrentMerc, iAmountToTransfer );
fOkToClear=TRUE;
}
}
if( fOkToClear )
{
gubCurrentSkiAtmMode = SKI_ATM_DISABLED_MODE;
EnableDisableSkiAtmButtons();
memset( gzSkiAtmTransferString, 0, 32 );
}
//Redraw the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
void AddNumberToSkiAtm( UINT8 ubNumber )
{
CHAR16 zTemp[16];
//make sure to durt the panel
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
//if the mode is an error mode
if( gubCurrentSkiAtmMode == SKI_ATM_ERR_TAKE_MODE )
{
gubCurrentSkiAtmMode = SKI_ATM_TAKE_MODE;
HandleCurrentModeText( gubCurrentSkiAtmMode );
}
//else if the mode was
else if( gubCurrentSkiAtmMode == SKI_ATM_ERR_GIVE_MODE )
{
gubCurrentSkiAtmMode = SKI_ATM_GIVE_MODE;
HandleCurrentModeText( gubCurrentSkiAtmMode );
}
//if we are not in the correct mode, return
if( gubCurrentSkiAtmMode != SKI_ATM_TAKE_MODE && gubCurrentSkiAtmMode != SKI_ATM_GIVE_MODE )
return;
//make sure we arent going over the numbers max size
if( wcslen( gzSkiAtmTransferString ) >= 9 )
return;
//if its the first number being added and the number is a zero
if( gzSkiAtmTransferString[0] == L'\0' && ubNumber == SKI_ATM_0 )
return;
swprintf( zTemp, L"%d", ubNumber );
//add the number to the current amount
wcscat( gzSkiAtmTransferString, zTemp );
}
void DisplaySkiAtmTransferString()
{
CHAR16 zSkiAtmTransferString[ 32 ];
UINT32 uiMoney;
//Erase the background behind the string
ColorFillVideoSurfaceArea( FRAME_BUFFER, SKI_TRANSFER_STRING_X, SKI_TRANSFER_STRING_Y, SKI_TRANSFER_STRING_X+SKI_TRANSFER_STRING_WIDTH, SKI_TRANSFER_STRING_Y+SKI_TRANSFER_STRING_HEIGHT, Get16BPPColor( FROMRGB( 0, 0, 0 ) ) );
wcscpy( zSkiAtmTransferString, gzSkiAtmTransferString );
InsertCommasForDollarFigure( zSkiAtmTransferString );
InsertDollarSignInToString( zSkiAtmTransferString );
//Display the transfer string
DrawTextToScreen( zSkiAtmTransferString, SKI_TRANSFER_STRING_X, SKI_TRANSFER_STRING_Y, SKI_TRANSFER_STRING_WIDTH, SKI_ATM_BUTTON_FONT, FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED );
//
//Get and Display the money on the merc
//
uiMoney = GetFundsOnMerc( gpSMCurrentMerc );
swprintf( zSkiAtmTransferString, L"%d", uiMoney );
InsertCommasForDollarFigure( zSkiAtmTransferString );
InsertDollarSignInToString( zSkiAtmTransferString );
DrawTextToScreen( zSkiAtmTransferString, SKI_TRANSFER_STRING_X, SKI_MERCS_MONEY_Y, SKI_TRANSFER_STRING_WIDTH, SKI_ATM_BUTTON_FONT, FONT_MCOLOR_WHITE, FONT_MCOLOR_BLACK, FALSE, RIGHT_JUSTIFIED );
}
void EnableDisableSkiAtmButtons()
{
UINT8 ubCnt;
switch( gubCurrentSkiAtmMode )
{
case SKI_ATM_DISABLED_MODE:
//Disable number positions
for( ubCnt=SKI_ATM_0; ubCnt<=SKI_ATM_9; ubCnt++)
DisableButton( guiSKI_AtmButton[ubCnt] );
DisableButton( guiSKI_AtmButton[SKI_ATM_OK] );
DisableButton( guiSKI_AtmButton[SKI_ATM_CANCEL] );
DisableButton( guiSKI_AtmButton[SKI_ATM_CLEAR] );
EnableButton( guiSKI_AtmButton[ SKI_ATM_TAKE ] );
EnableButton( guiSKI_AtmButton[ SKI_ATM_GIVE ] );
break;
case SKI_ATM_TAKE_MODE:
//Make sure the numbers are not disbaled
for( ubCnt=SKI_ATM_0; ubCnt<=SKI_ATM_9; ubCnt++)
EnableButton( guiSKI_AtmButton[ubCnt] );
//enable other
EnableButton( guiSKI_AtmButton[SKI_ATM_OK] );
EnableButton( guiSKI_AtmButton[SKI_ATM_CANCEL] );
EnableButton( guiSKI_AtmButton[SKI_ATM_CLEAR] );
break;
case SKI_ATM_GIVE_MODE:
//Make sure the numbers are not disbaled
for( ubCnt=SKI_ATM_0; ubCnt<=SKI_ATM_9; ubCnt++)
EnableButton( guiSKI_AtmButton[ubCnt] );
EnableButton( guiSKI_AtmButton[SKI_ATM_OK] );
EnableButton( guiSKI_AtmButton[SKI_ATM_CANCEL] );
EnableButton( guiSKI_AtmButton[SKI_ATM_CLEAR] );
break;
default:
Assert( 0 );
break;
}
}
void HandleCurrentModeText( UINT8 ubMode )
{
CHAR16 zTemp[128];
CHAR16 zMoney[128];
static UINT32 uiLastTime=0;
UINT32 uiCurTime=GetJA2Clock();
static UINT8 ubLastMode=0;
static UINT8 ubDisplayMode=0;
if( ubMode != ubLastMode )
{
uiLastTime = uiCurTime;
ubLastMode = ubMode;
ubDisplayMode = ubMode;
}
else
{
//if the current mode is an error mode
if( ubLastMode != SKI_ATM_ERR_TAKE_MODE && ubLastMode != SKI_ATM_ERR_GIVE_MODE )
{
//has the timer gone off?
if( ( uiCurTime - uiLastTime ) > DELAY_PER_MODE_CHANGE_IN_ATM )
{
//display the players current balance
//if the modes are the same, change to display the players balance
if( ubLastMode == ubMode )
if( ubMode == ubDisplayMode )
ubMode = SKI_ATM_DISPLAY_PLAYERS_BALANCE;
ubDisplayMode = ubMode;
uiLastTime = GetJA2Clock();
}
else
ubMode = ubDisplayMode;
}
}
//if the current mode is an error mode
if( ubLastMode == SKI_ATM_ERR_TAKE_MODE || ubLastMode == SKI_ATM_ERR_GIVE_MODE )
{
//if it is time to get rid of the error message
if( ( uiCurTime - uiLastTime ) > DELAY_PER_MODE_CHANGE_IN_ATM )
{
if( ubLastMode == SKI_ATM_ERR_TAKE_MODE )
{
ubLastMode = SKI_ATM_TAKE_MODE;
gubCurrentSkiAtmMode = ubLastMode;
}
else
{
ubLastMode = SKI_ATM_GIVE_MODE;
gubCurrentSkiAtmMode = ubLastMode;
}
}
}
switch( ubMode )
{
case SKI_ATM_DISABLED_MODE:
wcscpy( zTemp, gzSkiAtmText[ SKI_ATM_MODE_TEXT_SELECT_MODE ] );
break;
case SKI_ATM_TAKE_MODE:
//if the player has selected any money yet
if( gzSkiAtmTransferString[0] == L'\0' )
wcscpy( zTemp, gzSkiAtmText[ SKI_ATM_MODE_TEXT_ENTER_AMOUNT ] );
else
wcscpy( zTemp, gzSkiAtmText[ SKI_ATM_MODE_TEXT_SELECT_FROM_MERC ] );
break;
case SKI_ATM_GIVE_MODE:
//if the player has selected any money yet
if( gzSkiAtmTransferString[0] == L'\0' )
wcscpy( zTemp, gzSkiAtmText[ SKI_ATM_MODE_TEXT_ENTER_AMOUNT ] );
else
wcscpy( zTemp, gzSkiAtmText[ SKI_ATM_MODE_TEXT_SELECT_TO_MERC ] );
break;
case SKI_ATM_ERR_TAKE_MODE:
case SKI_ATM_ERR_GIVE_MODE:
wcscpy( zTemp, gzSkiAtmText[ SKI_ATM_MODE_TEXT_SELECT_INUSUFFICIENT_FUNDS ] );
break;
case SKI_ATM_DISPLAY_PLAYERS_BALANCE:
swprintf( zMoney, L"%d", LaptopSaveInfo.iCurrentBalance );
InsertCommasForDollarFigure( zMoney );
InsertDollarSignInToString( zMoney );
swprintf( zTemp, L"%s: %s", gzSkiAtmText[ SKI_ATM_MODE_TEXT_BALANCE ], zMoney );
break;
}
DisplayWrappedString( SKI_MODE_TEXT_X, SKI_MODE_TEXT_Y, SKI_MODE_TEXT_WIDTH, 2, SKI_ATM_BUTTON_FONT, FONT_MCOLOR_WHITE, zTemp, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED);
//invalidate the atm panel area
InvalidateRegion( SKI_ATM_PANEL_X, SKI_ATM_PANEL_Y, SKI_ATM_PANEL_X+SKI_ATM_PANEL_WIDTH, SKI_ATM_PANEL_Y+SKI_ATM_PANEL_HEIGHT );
}
void ToggleSkiAtmButtons()
{
switch( gubCurrentSkiAtmMode )
{
case SKI_ATM_DISABLED_MODE:
ButtonList[ guiSKI_AtmButton[SKI_ATM_TAKE] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ guiSKI_AtmButton[SKI_ATM_GIVE] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ guiSKI_AtmButton[SKI_ATM_CANCEL] ]->uiFlags &= ~BUTTON_CLICKED_ON;
break;
case SKI_ATM_TAKE_MODE:
case SKI_ATM_ERR_TAKE_MODE:
ButtonList[ guiSKI_AtmButton[SKI_ATM_GIVE] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ guiSKI_AtmButton[SKI_ATM_CANCEL] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ guiSKI_AtmButton[SKI_ATM_TAKE] ]->uiFlags |= BUTTON_CLICKED_ON;
break;
case SKI_ATM_GIVE_MODE:
case SKI_ATM_ERR_GIVE_MODE:
ButtonList[ guiSKI_AtmButton[SKI_ATM_TAKE] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ guiSKI_AtmButton[SKI_ATM_CANCEL] ]->uiFlags &= ~BUTTON_CLICKED_ON;
ButtonList[ guiSKI_AtmButton[SKI_ATM_GIVE] ]->uiFlags |= BUTTON_CLICKED_ON;
break;
}
}
void EnableDisableDealersInventoryPageButtons()
{
//if we are on the first page, disable the page up arrow
if( gSelectArmsDealerInfo.ubCurrentPage <= 1 )
{
DisableButton( guiSKI_InvPageUpButton );
}
else
{
EnableButton( guiSKI_InvPageUpButton );
}
//if we are on the last page, disable the page down button
if( gSelectArmsDealerInfo.ubCurrentPage == gSelectArmsDealerInfo.ubNumberOfPages )
{
DisableButton( guiSKI_InvPageDownButton );
}
else
{
EnableButton( guiSKI_InvPageDownButton );
}
}
void EnableDisableEvaluateAndTransactionButtons()
{
UINT8 ubCnt;
BOOLEAN fItemsHere=FALSE;
BOOLEAN fItemEvaluated=FALSE;
UINT32 uiArmsDealerTotalCost = CalculateTotalArmsDealerCost();
UINT32 uiPlayersOfferAreaTotalCost = CalculateTotalPlayersValue();
UINT32 uiPlayersOfferAreaTotalMoney = CalculateHowMuchMoneyIsInPlayersOfferArea( );
//loop through the players offer area
//loop through all the items in the players offer area and determine if they can be sold here.
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if there is an item here
if( PlayersOfferArea[ ubCnt ].fActive )
{
fItemsHere = TRUE;
//if the item has value
if( PlayersOfferArea[ ubCnt ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE )
{
//if the item isnt money ( which is always evaluated )
if( Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass != IC_MONEY )
fItemEvaluated = TRUE;
//else if it is not a repair dealer, and the item is money
else if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS && Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass == IC_MONEY )
fItemEvaluated = TRUE;
}
}
//if the dealer is a repair dealer
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//if there is an item here, the item has to have been evaluated
if( ArmsDealerOfferArea[ ubCnt ].fActive )
{
fItemEvaluated = TRUE;
}
}
}
/*
//Evaluate:
//if there is an item present
if( fItemsHere )
{
EnableButton( guiSKI_EvaluateButton );
}
else
{
DisableButton( guiSKI_EvaluateButton );
}
*/
//if there are evaluated items here
if( fItemEvaluated )
{
// //and if the players offer area value exceeds the shopkeeper's area
// if( uiPlayersOfferAreaTotalCost >= uiArmsDealerTotalCost )
EnableButton( guiSKI_TransactionButton );
// else
// DisableButton( guiSKI_TransactionButton );
/*
//if the only item in the players offer area is money, and there is nothing in the dealers offer area
if( IsMoneyTheOnlyItemInThePlayersOfferArea( ) && uiArmsDealerTotalCost == 0 )
DisableButton( guiSKI_TransactionButton );
*/
//If its a repair dealer, and there is no items in the Dealer Offer area,
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS &&
CountNumberOfItemsInTheArmsDealersOfferArea( ) == 0 &&
uiPlayersOfferAreaTotalMoney < uiArmsDealerTotalCost
)
DisableButton( guiSKI_TransactionButton );
}
//else if there is
else if( uiArmsDealerTotalCost != 0 )
{
EnableButton( guiSKI_TransactionButton );
}
else
{
DisableButton( guiSKI_TransactionButton );
}
if( uiArmsDealerTotalCost > uiPlayersOfferAreaTotalCost + LaptopSaveInfo.iCurrentBalance )
{
DisableButton( guiSKI_TransactionButton );
}
/* Allow transaction attempt when dealer can't afford to buy that much - he'll reject it with a special quote!
else if( ( gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash + uiArmsDealerTotalCost ) < ( uiPlayersOfferAreaTotalCost - uiPlayersOfferAreaTotalMoney ) )
{
DisableButton( guiSKI_TransactionButton );
}
*/
else if( ( uiPlayersOfferAreaTotalCost == uiPlayersOfferAreaTotalMoney ) && ( uiPlayersOfferAreaTotalMoney > 0 ) && ( uiArmsDealerTotalCost == 0 ) )
{
DisableButton( guiSKI_TransactionButton );
}
//if the player is currently moving an item, disable the transaction button
if( gMoveingItem.sItemIndex != 0 )
{
//Evaluate:
// DisableButton( guiSKI_EvaluateButton );
DisableButton( guiSKI_TransactionButton );
DisableButton( guiSKI_DoneButton );
}
else
{
EnableButton( guiSKI_DoneButton );
}
//ARM: Always permit trying bribes, even if they don't work on a given dealer!
// if the arms dealer is the kind of person who accepts gifts, and there is stuff to take
// if( ArmsDealerInfo[ gbSelectedArmsDealerID ].uiFlags & ARMS_DEALER_ACCEPTS_GIFTS )
{
//if the player is giving the dealer money, without buying anything
if( IsMoneyTheOnlyItemInThePlayersOfferArea( ) && CountNumberOfItemsInTheArmsDealersOfferArea( ) == 0 )
{
EnableButton( guiSKI_TransactionButton );
}
}
if( gfUserHasRequestedToLeave )
DisableButton( guiSKI_TransactionButton );
//if the player is in the item desc for the arms dealer items
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
{
ButtonList[ guiSKI_TransactionButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
ButtonList[ guiSKI_DoneButton ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
}
else
{
ButtonList[ guiSKI_TransactionButton ]->uiFlags &= ~BUTTON_FORCE_UNDIRTY;
ButtonList[ guiSKI_DoneButton ]->uiFlags &= ~BUTTON_FORCE_UNDIRTY;
}
}
void AddItemToPlayersOfferAreaAfterShopKeeperOpen( OBJECTTYPE *pItemObject, INT8 bPreviousInvPos )
{
gItemToAdd.fActive = TRUE;
memcpy( &gItemToAdd.ItemObject, pItemObject, sizeof( OBJECTTYPE ) );
gItemToAdd.bPreviousInvPos = bPreviousInvPos;
}
BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( )
{
UINT8 ubCnt;
BOOLEAN fFoundMoney = FALSE;
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if there is an item here
if( PlayersOfferArea[ ubCnt ].fActive )
{
if( Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass != IC_MONEY )
return( FALSE );
else
fFoundMoney = TRUE;
}
}
if ( fFoundMoney )
Assert( CalculateHowMuchMoneyIsInPlayersOfferArea() > 0 );
// only return TRUE if there IS money in the POA
return( fFoundMoney );
}
/*
void MoveRepairEvaluatedPlayerOfferedItemsToArmsDealersOfferArea()
{
UINT32 uiCnt;
//loop through all the slots in the players offer area
for( uiCnt=0; uiCnt<SKI_NUM_TRADING_INV_SLOTS; uiCnt++)
{
//if there is an item here
if( PlayersOfferArea[ uiCnt ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE )
{
AddItemToArmsDealerOfferArea( &PlayersOfferArea[ uiCnt ], -1 );
}
}
}
*/
UINT32 CalculateHowMuchMoneyIsInPlayersOfferArea( )
{
UINT8 ubCnt;
UINT32 uiTotalMoneyValue=0;
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if there is an item here
if( PlayersOfferArea[ ubCnt ].fActive )
{
if( Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass == IC_MONEY )
{
uiTotalMoneyValue += PlayersOfferArea[ ubCnt ].ItemObject.uiMoneyAmount;
}
}
}
return( uiTotalMoneyValue );
}
void MovePlayersItemsToBeRepairedToArmsDealersInventory()
{
//for all items in the dealers items offer area
UINT32 uiCnt;
//loop through all the slots in the shopkeeper's offer area
for( uiCnt=0; uiCnt<SKI_NUM_TRADING_INV_SLOTS; uiCnt++)
{
//if there is a item here
if( ArmsDealerOfferArea[ uiCnt ].fActive )
{
// NOTE: Any items that make it into a repairman's dealer offer area are guaranteed to be:
// a) Repairable
// b) Actually damaged
// c) Already stripped of all attachments
// d) If a gun, stripped of any non-ammo-class GunAmmoItems, and bullets
// add it to the arms dealer's inventory
GiveObjectToArmsDealerForRepair( gbSelectedArmsDealerID, &( ArmsDealerOfferArea[ uiCnt ].ItemObject ), ArmsDealerOfferArea[ uiCnt ].ubIdOfMercWhoOwnsTheItem );
ArmsDealerOfferArea[ uiCnt ].sSpecialItemElement = gubLastSpecialItemAddedAtElement;
//Remove the item from the owner merc's inventory
IfMercOwnedRemoveItemFromMercInv( &( ArmsDealerOfferArea[ uiCnt ]) );
//erase the item from the dealer's offer area
ClearArmsDealerOfferSlot( uiCnt );
}
}
gfResetShopKeepIdleQuote = TRUE;
}
BOOLEAN RemoveRepairItemFromDealersOfferArea( INT8 bSlot )
{
//if the item doesn't have a duplicate copy in its owner merc's inventory slot
if( ArmsDealerOfferArea[ bSlot ].bSlotIdInOtherLocation == -1 )
{
if ( !SKITryToReturnInvToOwnerOrCurrentMerc( &( ArmsDealerOfferArea[ bSlot ] ) ) )
{
//failed to add item, inventory probably filled up or item is unowned and current merc ineligible
return( FALSE );
}
}
// Clear the contents of the dealer's offer slot and its help text
ClearArmsDealerOfferSlot( bSlot );
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL1;
return( TRUE );
}
INT8 GetInvSlotOfUnfullMoneyInMercInventory( SOLDIERTYPE *pSoldier )
{
UINT8 ubCnt;
//loop through the soldier's inventory
for( ubCnt=0; ubCnt < NUM_INV_SLOTS; ubCnt++)
{
// Look for MONEY only, not Gold or Silver!!! And look for a slot not already full
if( ( pSoldier->inv[ ubCnt ].usItem == MONEY ) && ( pSoldier->inv[ ubCnt ].uiMoneyAmount < MoneySlotLimit( ubCnt ) ) )
{
return( ubCnt );
}
}
return( - 1 );
}
void ClearArmsDealerOfferSlot( INT32 ubSlotToClear )
{
// Clear the contents
memset( &ArmsDealerOfferArea[ ubSlotToClear ], 0, sizeof( INVENTORY_IN_SLOT ) );
//Remove the mouse help text from the region
SetRegionFastHelpText( &gDealersOfferSlotsMouseRegions[ ubSlotToClear ], L"" );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
SetRegionFastHelpText( &gDealersOfferSlotsSmallFaceMouseRegions[ ubSlotToClear ], L"" );
}
}
void ClearPlayersOfferSlot( INT32 ubSlotToClear )
{
// Clear the contents
memset( &PlayersOfferArea[ ubSlotToClear ], 0, sizeof( INVENTORY_IN_SLOT ) );
//Clear the text for the item
SetRegionFastHelpText( &gPlayersOfferSlotsMouseRegions[ ubSlotToClear ], L"" );
SetRegionFastHelpText( &gPlayersOfferSlotsSmallFaceMouseRegions[ ubSlotToClear ], L"" );
// if the player offer area is clear, reset flags for transaction
CheckAndHandleClearingOfPlayerOfferArea( );
}
void EvaluateItemAddedToPlayersOfferArea( INT8 bSlotID, BOOLEAN fFirstOne )
{
UINT32 uiEvalResult = EVAL_RESULT_NORMAL;
BOOLEAN fRocketRifleWasEvaluated = FALSE;
UINT8 ubNumberOfItemsAddedToRepairDuringThisEvaluation=0;
// there better be an item there
Assert ( PlayersOfferArea[ bSlotID ].fActive );
//if money is the item being evaluated, leave
if( Item[ PlayersOfferArea[ bSlotID ].sItemIndex ].usItemClass == IC_MONEY )
return;
// if already evaluated, don't do it again
if( PlayersOfferArea[ bSlotID ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_BEEN_EVALUATED )
{
return;
}
// say "Hmm... Let's see" once per trading session to start evaluation
// SPECIAL: Devin doesn't have this quote (he's the only one)
if( !gfDealerHasSaidTheEvaluateQuoteOnceThisSession && ( gbSelectedArmsDealerID != ARMS_DEALER_DEVIN ) )
{
gfDealerHasSaidTheEvaluateQuoteOnceThisSession = TRUE;
StartShopKeeperTalking( SK_QUOTES_PLAYER_REQUESTED_EVALUATION );
}
//Can this particular kind of item be sold/repaired here
if( WillShopKeeperRejectObjectsFromPlayer( gbSelectedArmsDealerID, bSlotID ) == FALSE )
{
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
UINT32 uiNumberOfItemsInForRepairs = CountTotalItemsRepairDealerHasInForRepairs( gbSelectedArmsDealerID );
UINT32 uiNumberOfItemsAlreadyEvaluated = CountNumberOfItemsInTheArmsDealersOfferArea();
//Get the number of items being evaluated
ubNumberOfItemsAddedToRepairDuringThisEvaluation = PlayersOfferArea[ bSlotID ].ItemObject.ubNumberOfObjects;
//if there is already enough items in for repairs, complain about it and DON'T accept the item for repairs
if( ( uiNumberOfItemsAlreadyEvaluated + ubNumberOfItemsAddedToRepairDuringThisEvaluation + uiNumberOfItemsInForRepairs ) > SKI_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME )
{
if ( !gfAlreadySaidTooMuchToRepair )
{
//Start the dealer talking
StartShopKeeperTalking( SK_QUOTES_CANT_AFFORD_TO_BUY_OR_TOO_MUCH_TO_REPAIR );
gfAlreadySaidTooMuchToRepair = TRUE;
}
return;
}
//if the item is a rocket rifle
if( ItemIsARocketRifle( PlayersOfferArea[ bSlotID ].sItemIndex ) )
{
fRocketRifleWasEvaluated = TRUE;
}
//if the item is damaged, or is a rocket rifle (which always "need repairing" even at 100%, to reset imprinting)
if( ( PlayersOfferArea[ bSlotID ].ItemObject.bStatus[ 0 ] < 100 ) || fRocketRifleWasEvaluated )
{
INT8 bSlotAddedTo;
// Move the item to the Dealer's Offer Area
bSlotAddedTo = AddItemToArmsDealerOfferArea( &PlayersOfferArea[ bSlotID ], PlayersOfferArea[ bSlotID ].bSlotIdInOtherLocation );
if( bSlotAddedTo != -1 )
{
// Clear the contents
ClearPlayersOfferSlot( bSlotID );
/* ARM: Leave it there, until transaction occurs it should be recallable
//Remove the item from the owner merc's inventory
IfMercOwnedRemoveItemFromMercInv( &(ArmsDealerOfferArea[ bSlotAddedTo ]) );
*/
//Mark the item as unselected, signifying that it can be moved
ArmsDealerOfferArea[ bSlotAddedTo ].uiFlags &= ~ARMS_INV_ITEM_SELECTED;
//increment the number of items being added
ubNumberOfItemsAddedToRepairDuringThisEvaluation++;
// check if the item is really badly damaged
if( Item[ ArmsDealerOfferArea[ bSlotAddedTo ].sItemIndex ].usItemClass != IC_AMMO )
{
if( ArmsDealerOfferArea[ bSlotAddedTo ].ItemObject.bStatus[ 0 ] < REALLY_BADLY_DAMAGED_THRESHOLD )
{
uiEvalResult = EVAL_RESULT_OK_BUT_REALLY_DAMAGED;
}
}
// check if it's the first time a rocket rifle is being submitted to Fredo
if( fRocketRifleWasEvaluated && ( gbSelectedArmsDealerID == ARMS_DEALER_FREDO ) )
{
//if he hasn't yet said his quote
if( !( gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags & ARMS_DEALER_FLAG__FREDO_HAS_SAID_ROCKET_RIFLE_QUOTE ) )
{
// use this special evaluation result instead (has a unique quote)
uiEvalResult = EVAL_RESULT_ROCKET_RIFLE;
}
}
}
else
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to add repair item to ArmsDealerOfferArea. AM-0");
#endif
return;
}
}
else
{
uiEvalResult = EVAL_RESULT_NOT_DAMAGED;
}
}
else // not a repairman
{
uiEvalResult = EvaluateInvSlot( & ( PlayersOfferArea[ bSlotID ] ) );
}
}
else // dealer doesn't handle this type of object
{
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
// only otherwise repairable items count as actual rejections
// if ( Item[ PlayersOfferArea[ bSlotID ].sItemIndex ].fFlags & ITEM_REPAIRABLE )
if ( Item[ PlayersOfferArea[ bSlotID ].sItemIndex ].repairable )
{
uiEvalResult = EVAL_RESULT_DONT_HANDLE;
}
else
{
uiEvalResult = EVAL_RESULT_NON_REPAIRABLE;
}
}
else
{
uiEvalResult = EVAL_RESULT_DONT_HANDLE;
}
}
// mark this item as having been evaluated
PlayersOfferArea[ bSlotID ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_BEEN_EVALUATED;
// when evaluating complex items that get split into multiple subobjects, dealer will talk only about the first one!
// don't bother with any of this if shopkeeper can't talk right now
if ( fFirstOne && CanShopkeeperOverrideDialogue( ) )
{
INT16 sQuoteNum = -1;
UINT8 ubChanceToSayNormalQuote;
switch ( uiEvalResult )
{
case EVAL_RESULT_DONT_HANDLE:
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_SELLS_ONLY )
{
// then he doesn't have quotes 17, 19, or 20, always use 4. Devin doesn't have 18 either,
// while the text of 18 seems wrong for Sam & Howard if offered something they should consider valuable.
sQuoteNum = SK_QUOTES_NOT_INTERESTED_IN_THIS_ITEM;
}
else
{
// he accepts items, but not this one
sQuoteNum = SK_QUOTES_DURING_EVALUATION_STUFF_REJECTED;
}
break;
case EVAL_RESULT_NON_REPAIRABLE:
// use quote 4 for this situation... It's a bit weird but better than "that looks fine / ain't broke"
sQuoteNum = SK_QUOTES_NOT_INTERESTED_IN_THIS_ITEM;
break;
case EVAL_RESULT_NOT_DAMAGED:
case EVAL_RESULT_WORTHLESS:
sQuoteNum = SK_QUOTES_EVALUATION_RESULT_VALUE_OF_ZERO;
break;
case EVAL_RESULT_OK_BUT_REALLY_DAMAGED:
sQuoteNum = SK_QUOTES_EVALUATION_RESULT_SOME_REALLY_DAMAGED_ITEMS;
break;
case EVAL_RESULT_ROCKET_RIFLE:
sQuoteNum = FREDO_QUOTE_CAN_RESET_IMPRINTING;
break;
case EVAL_RESULT_NORMAL:
//if it has been a long time since saying the last quote
if( guiLastTimeDealerSaidNormalEvaluationQuote == 0 )
ubChanceToSayNormalQuote = 100;
else if( ( GetJA2Clock() - guiLastTimeDealerSaidNormalEvaluationQuote ) > 25000 )
ubChanceToSayNormalQuote = 60;
else if( ( GetJA2Clock() - guiLastTimeDealerSaidNormalEvaluationQuote ) > 12000 )
ubChanceToSayNormalQuote = 25;
else if( ( GetJA2Clock() - guiLastTimeDealerSaidNormalEvaluationQuote ) > 7000 )
ubChanceToSayNormalQuote = 10;
else
ubChanceToSayNormalQuote = 0;
if( Chance( ubChanceToSayNormalQuote ) )
{
sQuoteNum = SK_QUOTES_EVALUATION_RESULT_NORMAL;
}
break;
default:
#ifdef JA2BETAVERSION
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Invalid evaluation result of %d. AM-0", uiEvalResult );
#endif
break;
}
// if a valid quote was selected
if ( sQuoteNum != -1 )
{
// if the appropriate quote hasn't already been used during this evaluation cycle
if ( !gfEvalResultQuoteSaid[ uiEvalResult ] )
{
// try to say it
if ( StartShopKeeperTalking( ( UINT16 ) sQuoteNum ) )
{
// set flag to keep from repeating it
gfEvalResultQuoteSaid[ uiEvalResult ] = TRUE;
// if it's the normal result
if ( uiEvalResult == EVAL_RESULT_NORMAL )
{
// set new time of last usage
guiLastTimeDealerSaidNormalEvaluationQuote = GetJA2Clock();
}
if ( sQuoteNum == FREDO_QUOTE_CAN_RESET_IMPRINTING )
{
//Set the fact that we have said this (to prevent that quote from coming up again)
gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags |= ARMS_DEALER_FLAG__FREDO_HAS_SAID_ROCKET_RIFLE_QUOTE;
}
}
}
}
}
}
BOOLEAN DoSkiMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback )
{
SGPRect pCenteringRect= {0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - INV_INTERFACE_HEIGHT };
// reset exit mode
gfExitSKIDueToMessageBox = TRUE;
// do message box and return
giSKIMessageBox = DoMessageBox( ubStyle, zString, uiExitScreen, ( UINT8 ) ( ubFlags| MSG_BOX_FLAG_USE_CENTERING_RECT ), ReturnCallback, &pCenteringRect );
// send back return state
return( ( giSKIMessageBox != -1 ) );
}
void ConfirmDontHaveEnoughForTheDealerMessageBoxCallBack( UINT8 bExitValue )
{
// simply redraw the panel
if( bExitValue == MSG_BOX_RETURN_OK )
{
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
// done, re-enable calls to PerformTransaction()
gfPerformTransactionInProgress = FALSE;
return;
}
void ConfirmToDeductMoneyFromPlayersAccountMessageBoxCallBack( UINT8 bExitValue )
{
// yes, deduct the money
if( bExitValue == MSG_BOX_RETURN_YES )
{
UINT32 uiPlayersOfferAreaValue = CalculateTotalPlayersValue();
UINT32 uiArmsDealersItemsCost = CalculateTotalArmsDealerCost();
INT32 iMoneyToDeduct = (INT32)( uiArmsDealersItemsCost - uiPlayersOfferAreaValue );
//Perform the transaction with the extra money from the players account
PerformTransaction( iMoneyToDeduct );
AddTransactionToPlayersBook( PURCHASED_ITEM_FROM_DEALER, ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID, GetWorldTotalMin(), -iMoneyToDeduct );
}
// done, re-enable calls to PerformTransaction()
gfPerformTransactionInProgress = FALSE;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
// run through what the player has on the table and see if the shop keep will aceept it or not
BOOLEAN WillShopKeeperRejectObjectsFromPlayer( INT8 bDealerId, INT8 bSlotId )
{
BOOLEAN fRejected = TRUE;
if( Item[ PlayersOfferArea[ bSlotId ].sItemIndex ].usItemClass == IC_MONEY )
{
fRejected = FALSE;
}
else if( CanDealerTransactItem( gbSelectedArmsDealerID, PlayersOfferArea[ bSlotId ].sItemIndex, TRUE ) )
{
fRejected = FALSE;
}
else
{
fRejected = TRUE;
}
return( fRejected );
}
void CheckAndHandleClearingOfPlayerOfferArea( void )
{
INT32 iCounter = 0;
BOOLEAN fActiveSlot = FALSE;
// find out if all the player trade slots/offer area is empty
for( iCounter=0; iCounter<SKI_NUM_TRADING_INV_SLOTS; iCounter++)
{
if( PlayersOfferArea[ iCounter ].fActive == TRUE )
{
// nope, there is an active slot
fActiveSlot = TRUE;
}
}
// if all player's offer area slots are empty
if( fActiveSlot == FALSE )
{
ResetAllQuoteSaidFlags();
gfRemindedPlayerToPickUpHisStuff = FALSE;
}
return;
}
BOOLEAN CanShopkeeperOverrideDialogue( void )
{
// if he's not currently saying anything
if( !gfIsTheShopKeeperTalking && ( giShopKeepDialogueEventinProgress == -1 ) )
{
return( TRUE );
}
// if the quote he is currently saying is unimportant (fluff),
// then shut him up & allow the override
if( giShopKeepDialogueEventinProgress < SK_QUOTES_PLAYER_REQUESTED_EVALUATION )
{
// shutup the shop keep and do this quote
ShutUpShopKeeper( );
return( TRUE );
}
// he's currently saying something important
return( FALSE );
}
void CrossOutUnwantedItems( void )
{
HVOBJECT hHandle;
INT8 bSlotId = 0;
INT16 sBoxStartX = 0, sBoxStartY = 0;
INT16 sBoxWidth = 0, sBoxHeight = 0;
// load the "cross out" graphic
GetVideoObject( &hHandle, guiItemCrossOut );
// get the box height and width
sBoxWidth = SKI_INV_SLOT_WIDTH;
sBoxHeight = SKI_INV_SLOT_HEIGHT;
for( bSlotId = 0; bSlotId < SKI_NUM_TRADING_INV_SLOTS; bSlotId++ )
{
// now run through what's on the players offer area
if( PlayersOfferArea[ bSlotId ].fActive )
{
// skip purchased items!
if ( !( PlayersOfferArea[ bSlotId ].uiFlags & ARMS_INV_JUST_PURCHASED ) )
{
//If item can't be sold here, or it's completely worthless (very cheap / very broken)
if( ( WillShopKeeperRejectObjectsFromPlayer( gbSelectedArmsDealerID, bSlotId ) == TRUE ) ||
!( PlayersOfferArea[ bSlotId ].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE ) )
{
// get x and y positions
sBoxStartX = SKI_PLAYERS_TRADING_INV_X + ( bSlotId % SKI_NUM_TRADING_INV_COLS ) * ( SKI_INV_OFFSET_X );
sBoxStartY = SKI_PLAYERS_TRADING_INV_Y + ( bSlotId / SKI_NUM_TRADING_INV_COLS ) * ( SKI_INV_OFFSET_Y );
BltVideoObject(FRAME_BUFFER, hHandle, 0,( sBoxStartX + 22 ), ( sBoxStartY ), VO_BLT_SRCTRANSPARENCY,NULL);
// invalidate the region
InvalidateRegion(sBoxStartX - 1, sBoxStartY - 1, sBoxStartX + sBoxWidth + 1, sBoxStartY + sBoxHeight + 1 );
}
}
}
}
return;
}
INT16 GetNumberOfItemsInPlayerOfferArea( void )
{
INT16 sCounter = 0;
INT32 iCounter = 0;
// find number of active slot in player offer area
for( iCounter = 0; iCounter < SKI_NUM_TRADING_INV_SLOTS; iCounter++ )
{
if( PlayersOfferArea[ iCounter ].fActive )
{
sCounter++;
}
}
return( sCounter );
}
void HandleCheckIfEnoughOnTheTable( void )
{
static INT32 iLastTime = 0;
INT32 iTime = 0, iDifference = 0, iRand = 0;
UINT32 uiPlayersOfferAreaValue = CalculateTotalPlayersValue();
UINT32 uiArmsDealersItemsCost = CalculateTotalArmsDealerCost();
if( ( iLastTime == 0 ) || gfResetShopKeepIdleQuote )
{
iLastTime = GetJA2Clock();
gfResetShopKeepIdleQuote = FALSE;
}
iDifference = GetJA2Clock() - iLastTime;
iRand = Random( 100 );
// delay for shopkeeper passed?
if( iDifference > DELAY_FOR_SHOPKEEPER_IDLE_QUOTE )
{
// random chance enough?
if( iRand > CHANCE_FOR_SHOPKEEPER_IDLE_QUOTE )
{
// is there enough on the table
if( ( uiArmsDealersItemsCost > uiPlayersOfferAreaValue ) && ( uiPlayersOfferAreaValue ) )
{
StartShopKeeperTalking( SK_QUOTES_EVAULATION_PLAYER_DOESNT_HAVE_ENOUGH_VALUE );
}
}
gfResetShopKeepIdleQuote = TRUE;
}
return;
}
void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT8 ubPocket, UINT8 ubFromLocation )
{
INT16 sPosX, sPosY;
switch( ubFromLocation )
{
case ARMS_DEALER_INVENTORY:
{
UINT8 ubSelectedInvSlot = ubPocket - gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
sPosX = SKI_ARMS_DEALERS_INV_START_X + ( SKI_INV_OFFSET_X * ( ubSelectedInvSlot % SKI_NUM_ARMS_DEALERS_INV_COLS ) - ( 358 / 2 ) ) + SKI_INV_SLOT_WIDTH / 2;
sPosY = SKI_ARMS_DEALERS_INV_START_Y + ( ( SKI_INV_OFFSET_Y * ubSelectedInvSlot / SKI_NUM_ARMS_DEALERS_INV_COLS ) + 1 ) - ( 128 / 2 ) + SKI_INV_SLOT_HEIGHT / 2;
// WANNE 2
//if the start position + the height of the box is off the screen, reposition
if( sPosY < (0 + SCREEN_Y_OFFSET) )
sPosY = 0 + SCREEN_Y_OFFSET;
//if the start position + the width of the box is off the screen, reposition
if( ( sPosX + 358 ) > SCREEN_WIDTH )
sPosX = sPosX - ( ( sPosX + 358 ) - SCREEN_WIDTH ) - 5;
//if it is starting to far to the left
else if( sPosX < (0 + SCREEN_X_OFFSET) )
sPosX = 0 + SCREEN_X_OFFSET;
//if the box will appear over the mercs face, move the box over so it doesn't obstruct the face
if( sPosY < SKI_FACE_Y + SKI_FACE_HEIGHT + 20 )
if( sPosX < (SCREEN_X_OFFSET + 160) )
sPosX = SCREEN_X_OFFSET + 160;
}
break;
case ARMS_DEALER_OFFER_AREA:
{
sPosX = SKI_ARMS_DEALERS_TRADING_INV_X + ( SKI_INV_OFFSET_X * ( ubPocket % ( SKI_NUM_TRADING_INV_SLOTS/2) ) - ( 358 / 2 ) ) + SKI_INV_SLOT_WIDTH / 2;
sPosY = SKI_ARMS_DEALERS_TRADING_INV_Y + ( ( SKI_INV_OFFSET_Y * ubPocket / ( SKI_NUM_TRADING_INV_SLOTS/2) ) + 1 ) - ( 128 / 2 ) + SKI_INV_SLOT_HEIGHT / 2;
//if the start position + the height of the box is off the screen, reposition
if( sPosY < (SCREEN_Y_OFFSET + 0) )
sPosY = 0 + SCREEN_Y_OFFSET;
//if the start position + the width of the box is off the screen, reposition
if( ( sPosX + 358 ) > SCREEN_WIDTH )
sPosX = sPosX - ( ( sPosX + 358 ) - SCREEN_WIDTH ) - 5;
//if it is starting to far to the left
else if( sPosX < (0 + SCREEN_X_OFFSET) )
sPosX = 10 + SCREEN_X_OFFSET;
//if the box will appear over the mercs face, move the box over so it doesn't obstruct the face
if( sPosY < SKI_FACE_Y + SKI_FACE_HEIGHT + 20 )
if( sPosX < (160 + SCREEN_X_OFFSET) )
sPosY = SCREEN_Y_OFFSET + INV_INTERFACE_HEIGHT;
}
break;
default:
Assert( 0 );
return;
}
pShopKeeperItemDescObject = pObject;
InitItemDescriptionBox( gpSMCurrentMerc, 255, sPosX, sPosY, 0 );
StartSKIDescriptionBox( );
}
void StartSKIDescriptionBox( void )
{
INT32 iCnt;
//shadow the entire screen
// ShadowVideoSurfaceRect( FRAME_BUFFER, 0, 0, 640, 480 );
//if the current merc is too far away, dont shade the SM panel because it is already shaded
// WANNE 2: Do not shade the background
if( gfSMDisableForItems )
DrawHatchOnInventory( FRAME_BUFFER, SCREEN_X_OFFSET, SCREEN_Y_OFFSET, SKI_INTERFACE_WIDTH, SKI_INTERFACE_HEIGHT );
else
{
DrawHatchOnInventory( FRAME_BUFFER, SCREEN_X_OFFSET, SCREEN_Y_OFFSET, SKI_INTERFACE_WIDTH, SKI_INTERFACE_HEIGHT );
}
InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
// disable almost everything!
gfSMDisableForItems = TRUE;
DisableInvRegions( gfSMDisableForItems );
DisableButton( guiSKI_InvPageUpButton );
DisableButton( guiSKI_InvPageDownButton );
// DisableButton( guiSKI_EvaluateButton );
DisableButton( guiSKI_TransactionButton );
DisableButton( guiSKI_DoneButton );
/*
for (iCnt = 0; iCnt < NUM_SKI_ATM_BUTTONS; iCnt++)
DisableButton( guiSKI_AtmButton[ iCnt ] );
*/
DisableAllDealersInventorySlots();
DisableAllDealersOfferSlots();
for (iCnt = 0; iCnt < SKI_NUM_TRADING_INV_SLOTS; iCnt++)
{
MSYS_DisableRegion( &gPlayersOfferSlotsMouseRegions[ iCnt ] );
MSYS_DisableRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
}
if( gShopKeeperSubTitleMouseRegion.uiFlags & MSYS_REGION_EXISTS )
{
MSYS_DisableRegion( &gShopKeeperSubTitleMouseRegion );
}
// MSYS_DisableRegion( &gShopKeeperCoverTacticalButtonMouseRegion );
// if( giItemDescAmmoButton >= 0 && ButtonList[ giItemDescAmmoButton ].
// DisableButton( giItemDescAmmoButton );
RenderItemDescriptionBox( );
}
void DeleteShopKeeperItemDescBox()
{
INT32 iCnt;
pShopKeeperItemDescObject = NULL;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
//Redraw the face
gFacesData[ giShopKeeperFaceIndex ].uiFlags |= FACE_REDRAW_WHOLE_FACE_NEXT_FRAME;
// enable almost everything!
CheckForDisabledForGiveItem( );
DisableInvRegions( gfSMDisableForItems ); //actually does an enable if current merc is in range
EnableButton( guiSKI_InvPageUpButton );
EnableButton( guiSKI_InvPageDownButton );
EnableButton( guiSKI_TransactionButton );
EnableButton( guiSKI_DoneButton );
EnableDisableDealersInventoryPageButtons();
EnableDisableEvaluateAndTransactionButtons();
// EnableButton( guiSKI_EvaluateButton );
/*
for (iCnt = 0; iCnt < NUM_SKI_ATM_BUTTONS; iCnt++)
EnableButton( guiSKI_AtmButton[ iCnt ] );
*/
EnableAllDealersInventorySlots();
EnableAllDealersOfferSlots();
for (iCnt = 0; iCnt < SKI_NUM_TRADING_INV_SLOTS; iCnt++)
{
MSYS_EnableRegion( &gPlayersOfferSlotsMouseRegions[ iCnt ] );
MSYS_EnableRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
}
if( gShopKeeperSubTitleMouseRegion.uiFlags & MSYS_REGION_EXISTS )
{
MSYS_EnableRegion( &gShopKeeperSubTitleMouseRegion );
}
// MSYS_EnableRegion( &gShopKeeperCoverTacticalButtonMouseRegion );
// if( giItemDescAmmoButton >= 0 && ButtonList[ giItemDescAmmoButton ].
// EnableButton( giItemDescAmmoButton );
}
BOOLEAN OfferObjectToDealer( OBJECTTYPE *pComplexObject, UINT8 ubOwnerProfileId, INT8 bOwnerSlotId )
{
UINT8 ubTotalSubObjects;
UINT8 ubRepairableSubObjects;
UINT8 ubNonRepairableSubObjects;
UINT8 ubDealerOfferAreaSlotsNeeded;
UINT8 ubPlayerOfferAreaSlotsNeeded;
UINT8 ubDiff;
UINT8 ubHowManyMoreItemsCanDealerTake;
UINT8 ubSubObject;
BOOLEAN fFirstOne = TRUE;
BOOLEAN fSuccess = FALSE;
if ( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS )
{
// if not actually doing repairs, there's no need to split objects up at all
if ( !AddObjectForEvaluation( pComplexObject, ubOwnerProfileId, bOwnerSlotId, TRUE ) )
{
gfDisplayNoRoomMsg = TRUE;
return(FALSE); // no room
}
}
else // dealing with a repairman
{
// split the object into its components
SplitComplexObjectIntoSubObjects( pComplexObject );
// determine how many subobjects of each category this complex object will have to be broken up into
CountSubObjectsInObject( pComplexObject, &ubTotalSubObjects, &ubRepairableSubObjects, &ubNonRepairableSubObjects );
// in the simplest situation, the # subobjects of each type gives us how many slots of each type are needed
ubDealerOfferAreaSlotsNeeded = ubRepairableSubObjects;
ubPlayerOfferAreaSlotsNeeded = ubNonRepairableSubObjects;
// consider that if dealer is at or will reach his max # of items repaired limit, not everything repairable will move
ubHowManyMoreItemsCanDealerTake = SKI_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME -
CountTotalItemsRepairDealerHasInForRepairs( gbSelectedArmsDealerID ) -
CountNumberOfItemsInTheArmsDealersOfferArea();
// if he can't repair everything repairable that we're about to submit, the space we'll need changes
if ( ubDealerOfferAreaSlotsNeeded > ubHowManyMoreItemsCanDealerTake )
{
ubDiff = ubDealerOfferAreaSlotsNeeded - ubHowManyMoreItemsCanDealerTake;
ubDealerOfferAreaSlotsNeeded -= ubDiff;
ubPlayerOfferAreaSlotsNeeded += ubDiff;
}
// if there is anything repairable that dealer will accept
if ( ubDealerOfferAreaSlotsNeeded > 0 )
{
// we need at least one EXTRA empty slot in player's area to pass repairable objects through for their evaluation
ubPlayerOfferAreaSlotsNeeded++;
}
Assert( SKI_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME < SKI_NUM_TRADING_INV_SLOTS );
/*
This code is commented out because a repair dealer will never be allowed to repair over more then
SKI_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME ( 4 ) items at a time, therefore, cant fill up the dealer offer area
// check if we have room for all of each type
if ( ( ubDealerOfferAreaSlotsNeeded + CountNumberOfItemsInTheArmsDealersOfferArea() ) > SKI_NUM_TRADING_INV_SLOTS )
{
// tell player there's not enough room in the dealer's offer area
DoSkiMessageBox( MSG_BOX_BASIC_STYLE, L"There is not enough room in the dealers repair area.", SHOPKEEPER_SCREEN, MSG_BOX_FLAG_OK, NULL );
return(FALSE); // no room
}
*/
if ( ( ubPlayerOfferAreaSlotsNeeded + CountNumberOfItemsInThePlayersOfferArea( ) ) > SKI_NUM_TRADING_INV_SLOTS )
{
gfDisplayNoRoomMsg = TRUE;
return(FALSE); // no room
}
// we have room, so move them all to the appropriate slots
for ( ubSubObject = 0; ubSubObject < MAX_SUBOBJECTS_PER_OBJECT; ubSubObject++ )
{
// if there is something stored there
if ( gSubObject[ ubSubObject ].usItem != NONE )
{
// if it's the main item itself (always in the very first subobject), and it has no other subobjects
if ( ( ubSubObject == 0 ) && ( ubTotalSubObjects == 1) )
{
// store its owner merc as the owner, and store the correct slot
fSuccess = AddObjectForEvaluation( &gSubObject[ ubSubObject ], ubOwnerProfileId, bOwnerSlotId, fFirstOne );
}
else // attachments, bullets/payload
{
// store it with a valid owner, but an invalid slot, so it still shows who owns it, but can't return to its slot
// ARM: New code will be needed here if we add parent/child item support & interface
fSuccess = AddObjectForEvaluation( &gSubObject[ ubSubObject ], ubOwnerProfileId, -1, fFirstOne );
}
// it has to succeed, or we have a bug in our earlier check for sufficient room
Assert( fSuccess );
fFirstOne = FALSE;
}
}
gfAlreadySaidTooMuchToRepair = FALSE;
}
//ARM: This comment isn't true unless parent/child support is added. Right now repairmen don't do this!
// NOTE that, either way, if owned, the item remains in the merc's inventory (hatched out) until the transaction is completed
// Dirty
fInterfacePanelDirty = DIRTYLEVEL2;
return(TRUE); // it worked
}
void SplitComplexObjectIntoSubObjects( OBJECTTYPE *pComplexObject )
{
OBJECTTYPE *pNextObj = &gSubObject[ 0 ];
UINT8 ubNextFreeSlot = 0;
UINT8 ubCnt;
Assert( pComplexObject );
Assert( pComplexObject->ubNumberOfObjects > 0 );
Assert( pComplexObject->ubNumberOfObjects <= MAX_OBJECTS_PER_SLOT );
// clear subobject array
memset (gSubObject, 0, sizeof( OBJECTTYPE ) * MAX_SUBOBJECTS_PER_OBJECT );
// if it isn't stacked
if ( pComplexObject->ubNumberOfObjects == 1 )
{
// make the main item into the very first subobject
CopyObj( pComplexObject, pNextObj );
// strip off any loaded ammo/payload
if ( Item [ pComplexObject->usItem ].usItemClass == IC_GUN )
{
// Exception: don't do this with rocket launchers, their "shots left" are fake and this screws 'em up!
if ( !Item[pComplexObject->usItem].singleshotrocketlauncher ) // Madd rpg - still do this
{
pNextObj->ubGunShotsLeft = 0;
pNextObj->usGunAmmoItem = NONE;
}
/* gunAmmoStatus is currently not being used that way, it's strictly used as a jammed/unjammed, and so should never be 0
// if jammed, must remember that, so leave it
if ( pNextObj->bGunAmmoStatus > 0 )
{
pNextObj->bGunAmmoStatus = 0;
}
*/
}
/* ARM: Can now repair with removeable attachments still attached...
// strip off any seperable attachments
for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
{
if ( pComplexObject->usAttachItem[ ubCnt ] != NONE )
{
// If the attachment is detachable
if (! (Item[ pComplexObject->usAttachItem[ ubCnt ] ].fFlags & ITEM_INSEPARABLE ) )
{
pNextObj->usAttachItem[ ubCnt ] = NONE;
pNextObj->bAttachStatus[ ubCnt ] = 0;
}
}
}
*/
// advance to next available subobject
pNextObj = &gSubObject[ ++ubNextFreeSlot ];
// if it's a gun
if ( Item [ pComplexObject->usItem ].usItemClass == IC_GUN )
{
// and it has ammo/payload
if ( pComplexObject->usGunAmmoItem != NONE )
{
// if it's bullets
if ( Item[ pComplexObject->usGunAmmoItem ].usItemClass == IC_AMMO )
{
// and there are some left
if ( pComplexObject->ubGunShotsLeft > 0 )
{
// make the bullets into another subobject
CreateItem( pComplexObject->usGunAmmoItem, 100, pNextObj );
// set how many are left
pNextObj->bStatus[ 0 ] = pComplexObject->ubGunShotsLeft;
pNextObj = &gSubObject[ ++ubNextFreeSlot ];
}
// ignore this if it's out of bullets
}
else // non-ammo payload
{
// make the payload into another subobject
CreateItem( pComplexObject->usGunAmmoItem, pComplexObject->bGunAmmoStatus, pNextObj );
// if the gun was jammed, fix up the payload's status
if ( pNextObj->bStatus[ 0 ] < 0 )
{
pNextObj->bStatus[ 0 ] *= -1;
}
pNextObj = &gSubObject[ ++ubNextFreeSlot ];
}
}
}
/* ARM: Can now repair with removeable attachments still attached...
// make each detachable attachment into a separate subobject
for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
{
if ( pComplexObject->usAttachItem[ ubCnt ] != NONE )
{
// If the attachment is detachable
if (! (Item[ pComplexObject->usAttachItem[ ubCnt ] ].fFlags & ITEM_INSEPARABLE ) )
{
CreateItem( pComplexObject->usAttachItem[ ubCnt ], pComplexObject->bAttachStatus[ ubCnt ], pNextObj );
pNextObj = &gSubObject[ ++ubNextFreeSlot ];
}
}
}
*/
}
else // stacked
{
// these can't be guns, can't have any attachments, can't be imprinted, etc.
Assert ( Item [ pComplexObject->usItem ].usItemClass != IC_GUN );
for( ubCnt = 0; ubCnt < MAX_ATTACHMENTS; ubCnt++ )
{
Assert( pComplexObject->usAttachItem[ ubCnt ] == NONE );
}
// make each item in the stack into a separate subobject
for( ubCnt = 0; ubCnt < pComplexObject->ubNumberOfObjects; ubCnt++ )
{
CreateItem( pComplexObject->usItem, pComplexObject->bStatus[ ubCnt ], pNextObj );
// advance to next available subobject
pNextObj = &gSubObject[ ++ubNextFreeSlot ];
}
}
// make sure we didn't screw up and honk something!
Assert( ubNextFreeSlot <= MAX_SUBOBJECTS_PER_OBJECT );
}
void CountSubObjectsInObject( OBJECTTYPE *pComplexObject, UINT8 *pubTotalSubObjects, UINT8 *pubRepairableSubObjects, UINT8 *pubNonRepairableSubObjects )
{
UINT8 ubSubObject;
*pubTotalSubObjects = 0;
*pubRepairableSubObjects = 0;
*pubNonRepairableSubObjects = 0;
// check every subobject and count it as either repairable or non-
for ( ubSubObject = 0; ubSubObject < MAX_SUBOBJECTS_PER_OBJECT; ubSubObject++ )
{
// if there is something stored there
if ( gSubObject[ ubSubObject ].usItem != NONE )
{
( *pubTotalSubObjects )++;
// is it in need of fixing, and also repairable by this dealer?
// A jammed gun with a 100% status is NOT repairable - shouldn't ever happen
if ( ( gSubObject[ ubSubObject ].bStatus[ 0 ] != 100 ) &&
CanDealerRepairItem( gbSelectedArmsDealerID, gSubObject[ ubSubObject ].usItem ) )
{
( *pubRepairableSubObjects )++;
}
else
{
( *pubNonRepairableSubObjects )++;
}
}
}
}
BOOLEAN AddObjectForEvaluation(OBJECTTYPE *pObject, UINT8 ubOwnerProfileId, INT8 bOwnerSlotId, BOOLEAN fFirstOne )
{
INVENTORY_IN_SLOT InvSlot;
INT8 bAddedToSlotID;
// Make a new inv slot out of the subobject
memset( &InvSlot, 0, sizeof( INVENTORY_IN_SLOT ) );
memcpy( &InvSlot.ItemObject, pObject, sizeof( OBJECTTYPE ) );
InvSlot.sItemIndex = pObject->usItem;
InvSlot.ubLocationOfObject = PLAYERS_INVENTORY;
InvSlot.ubIdOfMercWhoOwnsTheItem = ubOwnerProfileId;
//Add the item to the Players Offer Area
bAddedToSlotID = AddItemToPlayersOfferArea( ubOwnerProfileId, &InvSlot, bOwnerSlotId );
//Do the evaluation for the item if it was added correctly
if( bAddedToSlotID != -1 )
{
// This will move any repairable (sub)objects into the dealer's offer area immediately
EvaluateItemAddedToPlayersOfferArea( bAddedToSlotID, fFirstOne );
return( TRUE );
}
else
{
return( FALSE );
}
}
// The Shopkeeper interface *MUST* use this intermediary function instead of calling AutoPlaceObject() directly!
// This is because the OBJECTTYPEs used within Shopkeeper may contain an illegal ubNumberOfObjects
BOOLEAN ShopkeeperAutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObject, BOOLEAN fNewItem )
{
OBJECTTYPE CopyOfObject;
UINT8 ubObjectsLeftToPlace;
// the entire pObj will get memset to 0 by RemoveObjs() if all the items are successfully placed,
// so we have to keep a copy to retrieve with every iteration of the loop
memcpy( &CopyOfObject, pObject, sizeof( OBJECTTYPE ) );
ubObjectsLeftToPlace = pObject->ubNumberOfObjects;
while ( ubObjectsLeftToPlace > 0 )
{
// figure out how many to place during this loop iteration. Can't do more than MAX_OBJECTS_PER_SLOT at a time
pObject->ubNumberOfObjects = min( MAX_OBJECTS_PER_SLOT, ubObjectsLeftToPlace);
ubObjectsLeftToPlace -= pObject->ubNumberOfObjects;
if (!AutoPlaceObject( pSoldier, pObject, fNewItem ))
{
// no more room, didn't all fit - add back in any that we didn't even get to yet
pObject->ubNumberOfObjects += ubObjectsLeftToPlace;
return( FALSE );
}
// restore object properties from our backup copy
memcpy( pObject, &CopyOfObject, sizeof( OBJECTTYPE ) );
}
return( TRUE );
}
// The Shopkeeper interface *MUST* use this intermediary function instead of calling AddItemToPool() directly!
// This is because the OBJECTTYPEs used within Shopkeeper may contain an illegal ubNumberOfObjects
void ShopkeeperAddItemToPool( INT16 sGridNo, OBJECTTYPE *pObject, INT8 bVisible, UINT8 ubLevel, UINT16 usFlags, INT8 bRenderZHeightAboveLevel )
{
OBJECTTYPE CopyOfObject;
UINT8 ubObjectsLeftToPlace;
// the entire pObj will get memset to 0 by RemoveObjs() if all the items are successfully placed,
// so we have to keep a copy to retrieve with every iteration of the loop
memcpy( &CopyOfObject, pObject, sizeof( OBJECTTYPE ) );
ubObjectsLeftToPlace = pObject->ubNumberOfObjects;
while ( ubObjectsLeftToPlace > 0 )
{
// figure out how many to place during this loop iteration. Can't do more than MAX_OBJECTS_PER_SLOT at a time
pObject->ubNumberOfObjects = min( MAX_OBJECTS_PER_SLOT, ubObjectsLeftToPlace);
ubObjectsLeftToPlace -= pObject->ubNumberOfObjects;
AddItemToPool( sGridNo, pObject, bVisible, ubLevel, usFlags, bRenderZHeightAboveLevel );
// restore object properties from our backup copy
memcpy( pObject, &CopyOfObject, sizeof( OBJECTTYPE ) );
}
}
void IfMercOwnedCopyItemToMercInv( INVENTORY_IN_SLOT *pInv )
{
INT16 sSoldierID;
//if the item picked up was in a previous location, and that location is on a merc's inventory
if ( ( pInv->bSlotIdInOtherLocation != -1 ) && ( pInv->ubIdOfMercWhoOwnsTheItem != NO_PROFILE ) )
{
// then it better be a valid slot #
Assert( pInv->bSlotIdInOtherLocation < NUM_INV_SLOTS );
// and it better have a valid merc who owned it
Assert( pInv->ubIdOfMercWhoOwnsTheItem != NO_PROFILE );
// get soldier
sSoldierID = GetSoldierIDFromMercID( pInv->ubIdOfMercWhoOwnsTheItem );
Assert( sSoldierID != -1 );
Assert( CanMercInteractWithSelectedShopkeeper( MercPtrs[ sSoldierID ] ) );
//Copy the object back into that merc's original inventory slot
CopyObj( &( pInv->ItemObject ), &( Menptr[ sSoldierID ].inv[ pInv->bSlotIdInOtherLocation ] ) );
}
}
void IfMercOwnedRemoveItemFromMercInv( INVENTORY_IN_SLOT *pInv )
{
IfMercOwnedRemoveItemFromMercInv2( pInv->ubIdOfMercWhoOwnsTheItem, pInv->bSlotIdInOtherLocation );
}
void IfMercOwnedRemoveItemFromMercInv2( UINT8 ubOwnerProfileId, INT8 bOwnerSlotId )
{
INT16 sSoldierID;
BOOLEAN fSuccess;
OBJECTTYPE ObjectToRemove;
//if this item was in a previous location, and that location is on a merc's inventory
if ( ( bOwnerSlotId != -1 ) && ( ubOwnerProfileId != NO_PROFILE ) )
{
// then it better be a valid slot #
Assert( bOwnerSlotId < NUM_INV_SLOTS );
// and it better have a valid merc who owned it
Assert( ubOwnerProfileId != NO_PROFILE );
sSoldierID = GetSoldierIDFromMercID( ubOwnerProfileId );
Assert( sSoldierID != -1 );
Assert( CanMercInteractWithSelectedShopkeeper( MercPtrs[ sSoldierID ] ) );
//remove the object from that merc's original inventory slot
fSuccess = RemoveObjectFromSlot( &Menptr[ sSoldierID ], bOwnerSlotId, &ObjectToRemove );
Assert(fSuccess);
}
}
BOOLEAN SKITryToReturnInvToOwnerOrCurrentMerc( INVENTORY_IN_SLOT *pInv )
{
// don't use this if the item has a copy in merc's inventory!! It would create a duplicate!!
Assert( pInv->bSlotIdInOtherLocation == -1 );
// if it does have an owner
if( pInv->ubIdOfMercWhoOwnsTheItem != NO_PROFILE )
{
INT16 sSoldierID;
sSoldierID = GetSoldierIDFromMercID( pInv->ubIdOfMercWhoOwnsTheItem );
// if that soldier is not in player's hire any longer
if ( sSoldierID == -1 )
{
return(FALSE);
}
// For owners of repaired items, this checks that owner is still hired, in sector,
// on current squad, close enough to the shopkeeper, etc.
if ( !CanMercInteractWithSelectedShopkeeper( MercPtrs[ sSoldierID ] ) )
{
return(FALSE);
}
// Try to find a place to put in its owner's inventory (regardless of which merc is currently displayed!)
if ( SKITryToAddInvToMercsInventory( pInv, MercPtrs[ sSoldierID ] ) )
{
return( TRUE );
}
// owner's inventory is full, so we'll try to give it to the current merc instead
}
//if the current merc is not disabled
if( !gfSMDisableForItems )
{
// Try to find a place to put in current merc's inventory
if ( SKITryToAddInvToMercsInventory( pInv, gpSMCurrentMerc ) )
{
return( TRUE );
}
}
//failed to add item, either inventory was filled up, or nobody was even eligible to receive it
return( FALSE );
}
BOOLEAN SKITryToAddInvToMercsInventory( INVENTORY_IN_SLOT *pInv, SOLDIERTYPE *pSoldier )
{
INT8 bMoneyInvPos;
BOOLEAN fNewItem = FALSE;
//if the item is money
if( Item[ pInv->sItemIndex ].usItemClass == IC_MONEY )
{
// search through the merc's inventory for a pocket of money which isn't full already
bMoneyInvPos = GetInvSlotOfUnfullMoneyInMercInventory( pSoldier );
// if he has a money pocket going
if ( bMoneyInvPos != -1 )
{
// try to add to it. If successful, it will delete the object... It returns TRUE even if not all would fit!
PlaceObject( pSoldier, bMoneyInvPos, &( pInv->ItemObject ) );
// if the money is all gone
if ( pInv->ItemObject.uiMoneyAmount == 0 )
{
// we've been succesful!
return(TRUE);
}
// otherwise we'll try to place the rest seperately
}
}
// If it's just been purchased or repaired, mark it as a "new item"
fNewItem = ( BOOLEAN ) ( pInv->uiFlags & ( ARMS_INV_JUST_PURCHASED | ARMS_INV_ITEM_REPAIRED ) );
//try autoplacing the item in this soldier's inventory.
if( !ShopkeeperAutoPlaceObject( pSoldier, &pInv->ItemObject, fNewItem ) )
{
//failed to add item, inventory probably filled up
return( FALSE );
}
return(TRUE);
}
BOOLEAN CanMercInteractWithSelectedShopkeeper( SOLDIERTYPE *pSoldier )
{
SOLDIERTYPE *pShopkeeper;
INT16 sDestGridNo;
INT8 bDestLevel;
INT16 sDistVisible;
UINT32 uiRange;
Assert( pSoldier!= NULL );
Assert( gbSelectedArmsDealerID != -1 );
pShopkeeper = FindSoldierByProfileID( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID, FALSE );
Assert( pShopkeeper != NULL );
Assert( pShopkeeper->bActive );
Assert( pShopkeeper->bInSector );
if ( pShopkeeper->bLife < OKLIFE )
{
return( FALSE );
}
if ( pSoldier->bActive && pSoldier->bInSector && IsMercOnCurrentSquad( pSoldier ) && ( pSoldier->bLife >= OKLIFE ) &&
!( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) && !AM_A_ROBOT( pSoldier ) )
{
sDestGridNo = pShopkeeper->sGridNo;
bDestLevel = pShopkeeper->bLevel;
// is he close enough to see that gridno if he turns his head?
sDistVisible = DistanceVisible( pSoldier, DIRECTION_IRRELEVANT, DIRECTION_IRRELEVANT, sDestGridNo, bDestLevel, pSoldier );
// If he has LOS...
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, sDestGridNo, bDestLevel, 3, (UINT8) sDistVisible, TRUE ) )
{
// Get range to shopkeeper
uiRange = GetRangeFromGridNoDiff( pSoldier->sGridNo, sDestGridNo );
// and is close enough to talk to the shopkeeper (use this define INSTEAD of PASSING_ITEM_DISTANCE_OKLIFE!)
if ( uiRange <= NPC_TALK_RADIUS )
{
return( TRUE );
}
}
}
return( FALSE );
}
#ifdef JA2TESTVERSION
void AddShopkeeperToGridNo( UINT8 ubProfile, INT16 sGridNo )
{
SOLDIERCREATE_STRUCT MercCreateStruct;
INT16 sSectorX, sSectorY;
UINT8 ubID;
GetCurrentWorldSector( &sSectorX, &sSectorY );
memset( &MercCreateStruct, 0, sizeof( MercCreateStruct ) );
MercCreateStruct.bTeam = CIV_TEAM;
MercCreateStruct.ubProfile = ubProfile;
MercCreateStruct.sSectorX = sSectorX;
MercCreateStruct.sSectorY = sSectorY;
MercCreateStruct.bSectorZ = gbWorldSectorZ;
MercCreateStruct.sInsertionGridNo = sGridNo;
if ( TacticalCreateSoldier( &MercCreateStruct, &ubID ) )
{
AddSoldierToSector( ubID );
// So we can see them!
AllTeamsLookForAll(NO_INTERRUPTS);
}
}
#endif
void ExitSKIRequested()
{
BOOLEAN fPlayerOwnedStuffOnTable = FALSE;
ShutUpShopKeeper();
if( !gfRemindedPlayerToPickUpHisStuff )
{
if( AreThereItemsInThePlayersOfferArea( ) )
{
fPlayerOwnedStuffOnTable = TRUE;
}
if( ( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS ) &&
AreThereItemsInTheArmsDealersOfferArea( ) )
{
fPlayerOwnedStuffOnTable = TRUE;
}
//if there are any items belonging to player still on the table
if( fPlayerOwnedStuffOnTable )
{
// remind player to pick them up
ShutUpShopKeeper( );
StartShopKeeperTalking( SK_QUOTES_PRESSED_DONE_STILL_HAS_STUFF_IN_OFFER_AREA );
gfRemindedPlayerToPickUpHisStuff = TRUE;
return;
}
else
{
//if the player has already requested to leave
if( gfUserHasRequestedToLeave )
{
// has already asked to leave, shut the dealer up and allow the player to leave
ShutUpShopKeeper();
return;
}
}
}
// if the player hasn't already requested to leave
if( !gfUserHasRequestedToLeave )
{
UINT16 usQuoteNum;
if( gfDoneBusinessThisSession )
usQuoteNum = SK_QUOTES_PRESSES_DONE_HAS_AT_LEAST_1_TRANSACTION;
else
usQuoteNum = SK_QUOTES_PRESSED_DONE_HASNT_MADE_TRANSACTION;
StartShopKeeperTalking( usQuoteNum );
//Set the fact that the player wants to leave
gfUserHasRequestedToLeave = TRUE;
}
}
void ResetAllQuoteSaidFlags()
{
UINT8 uiCnt;
// reset flags for quotes said
for ( uiCnt = 0; uiCnt < NUM_EVAL_RESULTS; uiCnt++ )
{
gfEvalResultQuoteSaid[ uiCnt ] = FALSE;
}
guiLastTimeDealerSaidNormalEvaluationQuote = 0;
}
void DealWithItemsStillOnTheTable()
{
BOOLEAN fAddedCorrectly = FALSE;
UINT8 ubCnt;
SOLDIERTYPE *pDropSoldier;
// in case we have have to drop stuff off at someone's feet, figure out where it's all gonna go
// use the current merc, unless he's ineligible, then use the selected merc instead.
if( !gfSMDisableForItems )
{
pDropSoldier = gpSMCurrentMerc;
}
else
{
pDropSoldier = MercPtrs[ gusSelectedSoldier ];
}
// this guy HAS to be valid!
Assert( CanMercInteractWithSelectedShopkeeper( pDropSoldier ) );
//loop through the players offer area and add return any items there to the player
for( ubCnt=0; ubCnt<SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if there is an item here, give it back somehow
if( PlayersOfferArea[ ubCnt ].fActive )
{
ReturnItemToPlayerSomehow( &( PlayersOfferArea[ ubCnt ] ), pDropSoldier );
ClearPlayersOfferSlot( ubCnt );
}
}
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
//loop through the arms dealers' offer area and return any items there to the player
for( ubCnt = 0; ubCnt < SKI_NUM_TRADING_INV_SLOTS; ubCnt++)
{
//if there is an item here, give it back somehow
if( ArmsDealerOfferArea[ ubCnt ].fActive )
{
ReturnItemToPlayerSomehow( &( ArmsDealerOfferArea[ ubCnt ] ), pDropSoldier );
ClearArmsDealerOfferSlot( ubCnt );
}
}
}
}
void ReturnItemToPlayerSomehow( INVENTORY_IN_SLOT *pInvSlot, SOLDIERTYPE *pDropSoldier )
{
//if the item doesn't have a duplicate copy in its owner merc's inventory slot
if( pInvSlot->bSlotIdInOtherLocation == -1 )
{
// first try to give it to its owner, or if he's unavailable, the current merc
if ( !SKITryToReturnInvToOwnerOrCurrentMerc( pInvSlot ) )
{
// failed to add item, inventory probably filled up or item is unowned and current merc ineligible.
// drop it at the specified guy's feet instead
ShopkeeperAddItemToPool( pDropSoldier->sGridNo, &pInvSlot->ItemObject, VISIBLE, pDropSoldier->bLevel, 0, 0 );
}
}
}
void GivePlayerSomeChange( UINT32 uiAmount )
{
INVENTORY_IN_SLOT MoneyInvSlot;
memset( &MoneyInvSlot, 0, sizeof ( MoneyInvSlot ) );
CreateMoney( uiAmount, &MoneyInvSlot.ItemObject );
MoneyInvSlot.sItemIndex = MoneyInvSlot.ItemObject.usItem;
MoneyInvSlot.ubLocationOfObject = PLAYERS_INVENTORY;
MoneyInvSlot.ubIdOfMercWhoOwnsTheItem = NO_PROFILE;
AddItemToPlayersOfferArea( NO_PROFILE, &MoneyInvSlot, -1 );
if ( ( gbSelectedArmsDealerID == ARMS_DEALER_JAKE ) &&
( gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash < uiAmount ) )
{
// HACK HACK HACK: We forgot to write/record quote 27 for Jake, so he ALWAYS must have enough money!
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash += ( uiAmount - gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash );
}
// he must have enough cash left to give change
Assert( gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash >= uiAmount );
// subtract change from dealer's cash
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiArmsDealersCash -= uiAmount;
}
void DealerGetsBribed( UINT8 ubProfileId, UINT32 uiMoneyAmount )
{
BOOLEAN fBribable = FALSE;
UINT32 uiMinBribe = 0;
UINT16 usFact = 0;
// this is only for dealers
if (!IsMercADealer( ubProfileId ) )
{
return;
}
switch ( ubProfileId )
{
case FRANK:
fBribable = TRUE;
uiMinBribe = 10; // This should match the handling of a bribe submitted outside the SKI, using the GIVE system
usFact = FACT_FRANK_HAS_BEEN_BRIBED;
break;
}
// if this guy can be bribed, and we gave enough to bribe him
if ( fBribable && ( uiMoneyAmount >= uiMinBribe ) )
{
// set the appropriate fact
SetFactTrue( usFact );
}
}
void HandlePossibleRepairDelays()
{
UINT32 uiHoursSinceAnyItemsShouldHaveBeenRepaired = 0;
// assume there won't be a delay
gfStartWithRepairsDelayedQuote = FALSE;
// if it's Fredo or Perko
if ( ( gbSelectedArmsDealerID == ARMS_DEALER_FREDO ) || ( gbSelectedArmsDealerID == ARMS_DEALER_PERKO ) )
{
// because the quotes are so specific, we'll only use them once per game per repairman
if( !gArmsDealerStatus[ gbSelectedArmsDealerID ].fRepairDelayBeenUsed )
{
// and it's been a while since the player last dealt with this repairman (within SKI that is)
// this serves 2 purposes:
// a) reduces delays being much more likely if player checks time remaining very frequently, AND
// b) gives time for the events described in the text of the dealers' excuses to happen (e.g. scouting trip)
if ( ( GetWorldTotalMin() - gArmsDealerStatus[ gbSelectedArmsDealerID ].uiTimePlayerLastInSKI ) >= ( 3 * 60 ) )
{
// if he should have been finished, but it's only been a few hours since then (not days!)
if ( RepairmanFixingAnyItemsThatShouldBeDoneNow( &uiHoursSinceAnyItemsShouldHaveBeenRepaired ) &&
( uiHoursSinceAnyItemsShouldHaveBeenRepaired < REPAIR_DELAY_IN_HOURS ) )
{
// then there's a fair chance he'll be delayed. Use pre-chance to hopefully preserve across reloads
if ( PreChance( 50 ) )
{
DelayRepairsInProgressBy( ( REPAIR_DELAY_IN_HOURS + Random( REPAIR_DELAY_IN_HOURS ) ) * 60 );
// this triggers a different opening quote
gfStartWithRepairsDelayedQuote = TRUE;
// set flag so it doesn't happen again
gArmsDealerStatus[ gbSelectedArmsDealerID ].fRepairDelayBeenUsed = TRUE;
}
}
}
}
}
}
BOOLEAN RepairmanFixingAnyItemsThatShouldBeDoneNow( UINT32 *puiHoursSinceOldestItemRepaired )
{
UINT16 usItemIndex;
UINT8 ubElement;
DEALER_ITEM_HEADER *pDealerItem;
DEALER_SPECIAL_ITEM *pSpecialItem;
BOOLEAN fFoundOne = FALSE;
UINT32 uiMinutesSinceItWasDone;
UINT32 uiMinutesShopClosedSinceItWasDone;
UINT32 uiWorkingHoursSinceThisItemRepaired;
//if the dealer is not a repair dealer, return
if( !DoesDealerDoRepairs( gbSelectedArmsDealerID ) )
return( FALSE );
*puiHoursSinceOldestItemRepaired = 0;
//loop through the dealers inventory and check if there are only unrepaired items
for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
{
if ( Item[usItemIndex].usItemClass == 0 )
break;
pDealerItem = &( gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ] );
//if there is some items in stock
if( pDealerItem->ubTotalItems )
{
//loop through the array of items
for( ubElement=0; ubElement< pDealerItem->ubElementsAlloced; ubElement++ )
{
pSpecialItem = &( pDealerItem->SpecialItem[ ubElement ] );
if ( pSpecialItem->fActive )
{
//if the items status is below 0, the item is being repaired
if( pSpecialItem->Info.bItemCondition < 0 )
{
//if the repairs are done
if( pSpecialItem->uiRepairDoneTime <= GetWorldTotalMin() )
{
// at least one item is supposed to be done by now
fFoundOne = TRUE;
uiMinutesSinceItWasDone = GetWorldTotalMin() - pSpecialItem->uiRepairDoneTime;
uiMinutesShopClosedSinceItWasDone = CalculateMinutesClosedBetween( gbSelectedArmsDealerID, pSpecialItem->uiRepairDoneTime, GetWorldTotalMin() );
// calculate how many WORKING hours since this item's been repaired
uiWorkingHoursSinceThisItemRepaired = ( uiMinutesSinceItWasDone - uiMinutesShopClosedSinceItWasDone ) / 60;
// we need to determine how long it's been since the item that's been repaired for the longest time was done
if ( uiWorkingHoursSinceThisItemRepaired > *puiHoursSinceOldestItemRepaired )
{
*puiHoursSinceOldestItemRepaired = uiWorkingHoursSinceThisItemRepaired;
}
}
}
}
}
}
}
// if FALSE returned here, he's either not repairing anything, or none of it's done yet
return( fFoundOne );
}
void DelayRepairsInProgressBy( UINT32 uiMinutesDelayed )
{
UINT16 usItemIndex;
UINT8 ubElement;
DEALER_ITEM_HEADER *pDealerItem;
DEALER_SPECIAL_ITEM *pSpecialItem;
UINT32 uiMinutesShopClosedBeforeItsDone;
//if the dealer is not a repair dealer, return
if( !DoesDealerDoRepairs( gbSelectedArmsDealerID ) )
return;
//loop through the dealers inventory and check if there are only unrepaired items
for( usItemIndex = 1; usItemIndex < MAXITEMS; usItemIndex++ )
{
if ( Item[usItemIndex].usItemClass == 0 )
return;
pDealerItem = &( gArmsDealersInventory[ gbSelectedArmsDealerID ][ usItemIndex ] );
//if there is some items in stock
if( pDealerItem->ubTotalItems )
{
//loop through the array of items
for( ubElement=0; ubElement< pDealerItem->ubElementsAlloced; ubElement++ )
{
pSpecialItem = &( pDealerItem->SpecialItem[ ubElement ] );
if ( pSpecialItem->fActive )
{
//if the items status is below 0, the item is being repaired
if( pSpecialItem->Info.bItemCondition < 0 )
{
uiMinutesShopClosedBeforeItsDone = CalculateOvernightRepairDelay( gbSelectedArmsDealerID, pSpecialItem->uiRepairDoneTime, uiMinutesDelayed );
// add this many minutes to the repair time estimate
pSpecialItem->uiRepairDoneTime += ( uiMinutesShopClosedBeforeItsDone + uiMinutesDelayed );
}
}
}
}
}
}
//Mouse Call back for the Arms delaers face
void SelectArmsDealersDropItemToGroundRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
// WANNE 2: not needed to drop the item to the ground -> on the right side of the shopkeeper screen!
/*
if (iReason & MSYS_CALLBACK_REASON_INIT)
{
}
else if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
{
SOLDIERTYPE *pDropSoldier;
// use the current merc, unless he's ineligible, then use the selected merc instead.
if( !gfSMDisableForItems )
{
pDropSoldier = gpSMCurrentMerc;
}
else
{
pDropSoldier = MercPtrs[ gusSelectedSoldier ];
}
//if we don't have an item, pick one up
if( gMoveingItem.sItemIndex != 0 )
{
//add the item to the ground
ShopkeeperAddItemToPool( pDropSoldier->sGridNo, &gMoveingItem.ItemObject, VISIBLE, pDropSoldier->bLevel, 0, 0 );
//Reset the cursor
SetSkiCursor( CURSOR_NORMAL );
//refresh the screen
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
}
*/
}
void SelectArmsDealersDropItemToGroundMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
{
if( iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
{
gfSkiDisplayDropItemToGroundText = FALSE;
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
}
else if( iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
{
if( CanTheDropItemToGroundStringBeDisplayed() )
{
gfSkiDisplayDropItemToGroundText = TRUE;
}
else
{
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
gfSkiDisplayDropItemToGroundText = FALSE;
}
}
else if( iReason & MSYS_CALLBACK_REASON_MOVE )
{
}
}
BOOLEAN CanTheDropItemToGroundStringBeDisplayed()
{
//if we don't have an item, pick one up
if( gMoveingItem.sItemIndex != 0 )
return( TRUE );
else
return( FALSE );
}
void DisplayTheSkiDropItemToGroundString()
{
UINT16 usHeight;
//get the height of the displayed text
usHeight = DisplayWrappedString( SKI_DROP_ITEM_TO_GROUND_START_X, SKI_DROP_ITEM_TO_GROUND_TEXT_START_Y, (UINT16)(SCREEN_WIDTH-SKI_DROP_ITEM_TO_GROUND_START_X), 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[ SKI_TEXT_DROP_ITEM_TO_GROUND ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | DONT_DISPLAY_TEXT );
// WANNE 2 - not needed to show the string
//display the 'drop item to ground' text
//DisplayWrappedString( SKI_DROP_ITEM_TO_GROUND_START_X, (UINT16)(SKI_DROP_ITEM_TO_GROUND_TEXT_START_Y-usHeight), (UINT16)(SCREEN_WIDTH-SKI_DROP_ITEM_TO_GROUND_START_X), 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[ SKI_TEXT_DROP_ITEM_TO_GROUND ], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED | INVALIDATE_TEXT );
}
UINT32 EvaluateInvSlot( INVENTORY_IN_SLOT *pInvSlot )
{
UINT32 uiEvalResult = EVAL_RESULT_NORMAL;
FLOAT dPriceModifier;
UINT32 uiBuyingPrice;
//if the dealer is Micky
if( gbSelectedArmsDealerID == ARMS_DEALER_MICKY )
{
INT16 sSoldierID;
sSoldierID = GetSoldierIDFromMercID( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubShopKeeperID );
if( ( sSoldierID != -1 ) && ( GetDrunkLevel( &Menptr[ sSoldierID ] ) == DRUNK ) )
{
//Micky is DRUNK, pays more!
dPriceModifier = ArmsDealerInfo[ gbSelectedArmsDealerID ].dSellModifier;
}
else
{
// Micky isn't drunk, charge regular price
dPriceModifier = ArmsDealerInfo[ gbSelectedArmsDealerID ].dBuyModifier;
}
}
else
{
dPriceModifier = ArmsDealerInfo[ gbSelectedArmsDealerID ].dBuyModifier;
}
// Calculate dealer's buying price for the item
uiBuyingPrice = CalcShopKeeperItemPrice( DEALER_BUYING, FALSE, pInvSlot->sItemIndex, dPriceModifier, &( pInvSlot->ItemObject ) );
pInvSlot->uiItemPrice = uiBuyingPrice;
if ( uiBuyingPrice > 0 )
{
// check if the item is really badly damaged
if( Item[ pInvSlot->sItemIndex ].usItemClass != IC_AMMO )
{
if( pInvSlot->ItemObject.bStatus[ 0 ] < REALLY_BADLY_DAMAGED_THRESHOLD )
{
uiEvalResult = EVAL_RESULT_OK_BUT_REALLY_DAMAGED;
}
}
//the item can be sold here, so mark it as such
pInvSlot->uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
}
else
{
// he normally buys this, but it's in such bad shape that he won't, it's worthless (different quote)
uiEvalResult = EVAL_RESULT_WORTHLESS;
pInvSlot->uiFlags &= ~ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
}
return( uiEvalResult );
}
// round off reapir times shown to the near quarter-hour
#define REPAIR_MINUTES_INTERVAL 15
void BuildRepairTimeString( CHAR16 sString[], UINT32 uiTimeInMinutesToFixItem )
{
UINT16 usNumberOfHoursToFixItem = 0;
// if it's 0, it shouldn't be up here any more!
Assert ( uiTimeInMinutesToFixItem > 0 );
// round off to next higher 15 minutes
if ( ( uiTimeInMinutesToFixItem % REPAIR_MINUTES_INTERVAL ) > 0 )
{
uiTimeInMinutesToFixItem += REPAIR_MINUTES_INTERVAL - ( uiTimeInMinutesToFixItem % REPAIR_MINUTES_INTERVAL );
}
if ( uiTimeInMinutesToFixItem < REPAIR_MINUTES_INTERVAL )
{
uiTimeInMinutesToFixItem = REPAIR_MINUTES_INTERVAL;
}
// show up to 1.5 hrs in minutes
if ( uiTimeInMinutesToFixItem <= 90 )
{
// show minutes
swprintf( sString, SKI_Text[ SKI_TEXT_MINUTES ], uiTimeInMinutesToFixItem );
}
else
{
// show hours
// round fractions of 15+ minutes up to next full hour
usNumberOfHoursToFixItem = (UINT16) ( ( uiTimeInMinutesToFixItem + 45 ) / 60 );
if ( usNumberOfHoursToFixItem > 1 )
{
swprintf( sString, SKI_Text[ SKI_TEXT_PLURAL_HOURS ], usNumberOfHoursToFixItem );
}
else
{
wcscpy( sString, SKI_Text[ SKI_TEXT_ONE_HOUR ] );
}
}
}
void BuildDoneWhenTimeString( CHAR16 sString[], UINT8 ubArmsDealer, UINT16 usItemIndex, UINT8 ubElement )
{
UINT32 uiDoneTime;
UINT32 uiDay, uiHour, uiMin;
//dealer must be a repair dealer
Assert( DoesDealerDoRepairs( ubArmsDealer ) );
// element index must be valid
Assert( ubElement < gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].ubElementsAlloced );
// that item must be active
Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].fActive );
// that item must be in repair
Assert( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].Info.bItemCondition < 0 );
//if the item has already been repaired
if( gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime <= GetWorldTotalMin() )
{
wcscpy( sString, L"" );
return;
}
uiDoneTime = gArmsDealersInventory[ ubArmsDealer ][ usItemIndex ].SpecialItem[ ubElement ].uiRepairDoneTime;
// round off to next higher 15 minutes
if ( ( uiDoneTime % REPAIR_MINUTES_INTERVAL ) > 0 )
{
uiDoneTime += REPAIR_MINUTES_INTERVAL - ( uiDoneTime % REPAIR_MINUTES_INTERVAL );
}
// uiDoneTime is in minutes...
uiDay = ( uiDoneTime / NUM_MIN_IN_DAY );
uiHour = ( uiDoneTime - ( uiDay * NUM_MIN_IN_DAY ) ) / NUM_MIN_IN_HOUR;
uiMin = uiDoneTime - ( ( uiDay * NUM_MIN_IN_DAY ) + ( uiHour * NUM_MIN_IN_HOUR ) );
// only show day if it's gonna take overnight
if ( GetWorldDay() != uiDay )
{
swprintf( sString, L"%s %d %02d:%02d", pDayStrings[ 0 ], uiDay, uiHour, uiMin );
}
else
{
swprintf( sString, L"%02d:%02d", uiHour, uiMin );
}
}
void BuildItemHelpTextString( CHAR16 sString[], INVENTORY_IN_SLOT *pInv, UINT8 ubScreenArea )
{
CHAR16 zHelpText[ 512 ];
CHAR16 zRepairTime[ 64 ];
if( pInv != NULL )
{
GetHelpTextForItem( zHelpText, &( pInv->ItemObject ), NULL );
// add repair time for items in a repairman's offer area
if ( ( ubScreenArea == ARMS_DEALER_OFFER_AREA ) &&
( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS ) )
{
BuildRepairTimeString( zRepairTime, CalculateObjectItemRepairTime( gbSelectedArmsDealerID, &( pInv->ItemObject ) ) );
swprintf( sString, L"%s\n(%s: %s)", zHelpText, gzLateLocalizedString[ 44 ], zRepairTime );
}
else
{
wcscpy( sString, zHelpText );
}
}
else
{
sString[ 0 ] = '\0';
}
}
void DisableAllDealersInventorySlots( void )
{
INT32 iCnt;
for (iCnt = 0; iCnt < SKI_NUM_ARMS_DEALERS_INV_SLOTS; iCnt++)
{
MSYS_DisableRegion( &gDealersInventoryMouseRegions[ iCnt ] );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_DisableRegion( &gRepairmanInventorySmallFaceMouseRegions[ iCnt ] );
}
}
}
void EnableAllDealersInventorySlots( void )
{
INT32 iCnt;
for (iCnt = 0; iCnt < SKI_NUM_ARMS_DEALERS_INV_SLOTS; iCnt++)
{
MSYS_EnableRegion( &gDealersInventoryMouseRegions[ iCnt ] );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_EnableRegion( &gRepairmanInventorySmallFaceMouseRegions[ iCnt ] );
}
}
}
void DisableAllDealersOfferSlots( void )
{
INT32 iCnt;
for (iCnt = 0; iCnt < SKI_NUM_TRADING_INV_SLOTS; iCnt++)
{
MSYS_DisableRegion( &gDealersOfferSlotsMouseRegions[ iCnt ] );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_DisableRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
}
}
}
void EnableAllDealersOfferSlots( void )
{
INT32 iCnt;
for (iCnt = 0; iCnt < SKI_NUM_TRADING_INV_SLOTS; iCnt++)
{
MSYS_EnableRegion( &gDealersOfferSlotsMouseRegions[ iCnt ] );
//if the dealer repairs
if( ArmsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
{
MSYS_EnableRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
}
}
}
void HatchOutInvSlot( UINT16 usPosX, UINT16 usPosY )
{
UINT16 usSlotX, usSlotY;
UINT16 usSlotWidth, usSlotHeight;
//if we are in the item desc panel
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
{
// do nothing, don't wanna shade things twice!
return;
}
usSlotX = ( UINT16 ) ( usPosX - 1 );
usSlotY = ( UINT16 ) ( usPosY - 1 );
usSlotWidth = SKI_INV_SLOT_WIDTH;
usSlotHeight = SKI_INV_SLOT_HEIGHT;
//Hatch it out
DrawHatchOnInventory( guiRENDERBUFFER, usSlotX, usSlotY, usSlotWidth, usSlotHeight );
InvalidateRegion( usSlotX, usSlotY, usSlotX + usSlotWidth, usSlotY + usSlotHeight );
}