mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23643&goto=352475&#msg_352475 Requires GameDir >= r2401. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8522 3b4a5df2-a311-0410-b5c6-a8a6f20db521
7399 lines
250 KiB
C++
7399 lines
250 KiB
C++
#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 "Font Control.h"
|
|
#include "WordWrap.h"
|
|
#include "Text Input.h"
|
|
#include "Interface.h"
|
|
#include "Interface Control.h"
|
|
#include "Overhead.h"
|
|
#include "Cursors.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"
|
|
#include "PATHAI.h"
|
|
#include "Points.h"
|
|
#include "InterfaceItemImages.h"
|
|
#include "Encyclopedia_new.h"
|
|
#include "Animation Control.h" // added by Flugente
|
|
#include "Town Militia.h" // added by Flugente
|
|
#endif
|
|
|
|
#ifdef JA2UB
|
|
#include "Explosion Control.h"
|
|
#include "Ja25_Tactical.h"
|
|
#include "Ja25 Strategic Ai.h"
|
|
#include "MapScreen Quotes.h"
|
|
#include "email.h"
|
|
#include "interface Dialogue.h"
|
|
#include "Ja25_Tactical.h"
|
|
#include "ub_config.h"
|
|
#endif
|
|
|
|
#include "BuildDefines.h"
|
|
#include <algorithm>
|
|
|
|
////////////////////////////////////////////
|
|
//
|
|
// global defines
|
|
//
|
|
///////////////////////////////////////////
|
|
|
|
#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_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
|
|
|
|
//Number of Inventory slots
|
|
#define SKI_NUM_ARMS_DEALERS_INV_SLOTS 500 // Flugente: simply a resonably huge number
|
|
#define SKI_NUM_TRADING_INV_SLOTS 500 // Flugente: simply a resonably huge number
|
|
|
|
//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_OFFSET_X 74
|
|
#define SKI_INV_OFFSET_Y 36
|
|
|
|
#define SKI_INV_PRICE_OFFSET_X 1
|
|
#define SKI_INV_PRICE_OFFSET_Y 24
|
|
|
|
// the delay for glow cycling in glow areas, in millisecs
|
|
#define SKI_GLOW_DELAY 70
|
|
|
|
#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_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_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME 4
|
|
|
|
// round off reapir times shown to the near quarter-hour
|
|
#define REPAIR_MINUTES_INTERVAL 15
|
|
|
|
#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 REALLY_BADLY_DAMAGED_THRESHOLD 30
|
|
|
|
#define REPAIR_DELAY_IN_HOURS 6
|
|
|
|
#define FLO_DISCOUNT_PERCENTAGE 10
|
|
|
|
#ifdef JA2UB
|
|
#define SKI_BETTY_MINIMUM_AMOUNT_TO_SET_FACT 10
|
|
#define SKI_RAUL_MINIMUM_AMOUNT_TO_SET_FACT 100
|
|
#endif
|
|
|
|
// Flugente: new defines for shopkeeper interface with a resolution-dependent size
|
|
|
|
// the main tradescreen is a rectangle, which contains trader inventory, trader offer area and player offer area as sub-rectangles
|
|
#define SKI_TOTAL_END_X (SCREEN_X_OFFSET + SKI_INTERFACE_WIDTH)
|
|
#define SKI_TOTAL_END_Y (SCREEN_HEIGHT - INV_INTERFACE_HEIGHT)
|
|
#define SKI_TOTAL_BEGIN_Y 0
|
|
|
|
// we determine how many item boxes we could display in a row, and then depend where the shopkeeper display should start
|
|
// as a result, the margins will always look the same
|
|
#define SKI_TOTAL_BEGIN_X (SKI_TOTAL_END_X - 166 - ((SKI_TOTAL_END_X - 166) / SKI_INV_OFFSET_X) * SKI_INV_OFFSET_X)
|
|
|
|
// first: trader inventory
|
|
#define SKI_TRADER_INVENTORY_BEGIN_X SKI_TOTAL_BEGIN_X
|
|
#define SKI_TRADER_INVENTORY_BEGIN_Y SKI_TOTAL_BEGIN_Y
|
|
#define SKI_TRADER_INVENTORY_END_X SKI_TOTAL_END_X
|
|
#define SKI_TRADER_INVENTORY_END_Y (143 + (SKI_TOTAL_END_Y - SKI_INTERFACE_HEIGHT) / 2)
|
|
|
|
#define SKI_MAIN_TITLE_X (SKI_TRADER_INVENTORY_BEGIN_X + 112)
|
|
#define SKI_MAIN_TITLE_Y (SKI_TRADER_INVENTORY_BEGIN_Y + 12)
|
|
#define SKI_MAIN_TITLE_WIDTH 420
|
|
|
|
// merchant face
|
|
#define SKI_FACE_X (SKI_TRADER_INVENTORY_BEGIN_X + 13)
|
|
#define SKI_FACE_Y (SKI_TRADER_INVENTORY_BEGIN_Y + 13)
|
|
#define SKI_FACE_WIDTH 90
|
|
#define SKI_FACE_HEIGHT 100
|
|
|
|
// trader inventory page buttons
|
|
#define SKI_PAGE_UP_ARROWS_X (SKI_TRADER_INVENTORY_BEGIN_X + 121)
|
|
#define SKI_PAGE_UP_ARROWS_Y (SKI_TRADER_INVENTORY_BEGIN_Y + 35)
|
|
|
|
#define SKI_PAGE_DOWN_ARROWS_X SKI_PAGE_UP_ARROWS_X
|
|
#define SKI_PAGE_DOWN_ARROWS_Y (SKI_TRADER_INVENTORY_BEGIN_Y + 102)
|
|
|
|
#define SKI_PAGE_X (SKI_TRADER_INVENTORY_BEGIN_X + 112)
|
|
#define SKI_PAGE_Y (SKI_TRADER_INVENTORY_BEGIN_Y + 70)
|
|
#define SKI_PAGE_WIDTH 45
|
|
#define SKI_PAGE_HEIGHT 27
|
|
|
|
#define SKI_BUDGET_X (SKI_TRADER_INVENTORY_BEGIN_X + 9)
|
|
#define SKI_BUDGET_Y (SKI_FACE_Y + SKI_FACE_HEIGHT + 5)
|
|
#define SKI_BUDGET_WIDTH 73
|
|
#define SKI_BUDGET_OFFSET_TO_VALUE (SKI_BUDGET_Y + 10)
|
|
|
|
// trader inventory item boxes
|
|
#define SKI_TRADER_INVENTORY_BOXES_BEGIN_X (SKI_TRADER_INVENTORY_BEGIN_X + 166)
|
|
#define SKI_TRADER_INVENTORY_BOXES_BEGIN_Y (SKI_TRADER_INVENTORY_BEGIN_Y + 30)
|
|
#define SKI_TRADER_INVENTORY_BOXES_PER_ROW ((SKI_TRADER_INVENTORY_END_X - SKI_TRADER_INVENTORY_BOXES_BEGIN_X) / SKI_INV_OFFSET_X)
|
|
#define SKI_TRADER_INVENTORY_BOXES_PER_COL ((SKI_TRADER_INVENTORY_END_Y - SKI_TRADER_INVENTORY_BOXES_BEGIN_Y) / SKI_INV_OFFSET_Y)
|
|
|
|
// second: trader offer area
|
|
#define SKI_TRADER_OFFER_BEGIN_X SKI_TOTAL_BEGIN_X
|
|
#define SKI_TRADER_OFFER_BEGIN_Y SKI_TRADER_INVENTORY_END_Y
|
|
#define SKI_TRADER_OFFER_END_X SKI_TOTAL_END_X
|
|
#define SKI_TRADER_OFFER_END_Y (82 + SKI_TRADER_INVENTORY_END_Y)
|
|
|
|
// trader offer area item boxes
|
|
#define SKI_TRADER_OFFER_BOXES_BEGIN_X (SKI_TRADER_OFFER_BEGIN_X + 91)
|
|
#define SKI_TRADER_OFFER_BOXES_BEGIN_Y (SKI_TRADER_OFFER_BEGIN_Y + 8)
|
|
#define SKI_TRADER_OFFER_BOXES_PER_ROW ((SKI_TRADER_OFFER_END_X - SKI_TRADER_OFFER_BOXES_BEGIN_X) / SKI_INV_OFFSET_X)
|
|
#define SKI_TRADER_OFFER_BOXES_PER_COL ((SKI_TRADER_OFFER_END_Y - SKI_TRADER_OFFER_BOXES_BEGIN_Y) / SKI_INV_OFFSET_Y)
|
|
|
|
#define SKI_TOTAL_COST_X (SKI_TRADER_OFFER_BEGIN_X + 9)
|
|
#define SKI_TOTAL_COST_Y (SKI_TRADER_OFFER_BEGIN_Y + 35)//159
|
|
#define SKI_TOTAL_COST_WIDTH 73
|
|
|
|
#define SKI_ARMS_DEALER_TOTAL_COST_X (SKI_TRADER_OFFER_BEGIN_X + 16)
|
|
#define SKI_ARMS_DEALER_TOTAL_COST_Y (SKI_TRADER_OFFER_BEGIN_Y + 51)//191
|
|
#define SKI_ARMS_DEALER_TOTAL_COST_WIDTH 59
|
|
#define SKI_ARMS_DEALER_TOTAL_COST_HEIGHT 20
|
|
|
|
// third: player offer area
|
|
#define SKI_PLAYER_OFFER_BEGIN_X SKI_TOTAL_BEGIN_X
|
|
#define SKI_PLAYER_OFFER_BEGIN_Y SKI_TRADER_OFFER_END_Y
|
|
#define SKI_PLAYER_OFFER_END_X SKI_TOTAL_END_X
|
|
#define SKI_PLAYER_OFFER_END_Y SKI_TOTAL_END_Y
|
|
|
|
// player offer area item boxes
|
|
#define SKI_PLAYER_OFFER_BOXES_BEGIN_X (SKI_PLAYER_OFFER_BEGIN_X + 91)
|
|
#define SKI_PLAYER_OFFER_BOXES_BEGIN_Y (SKI_PLAYER_OFFER_BEGIN_Y + 41)
|
|
#define SKI_PLAYER_OFFER_BOXES_PER_ROW ((SKI_PLAYER_OFFER_END_X - SKI_PLAYER_OFFER_BOXES_BEGIN_X) / SKI_INV_OFFSET_X)
|
|
#define SKI_PLAYER_OFFER_BOXES_PER_COL ((SKI_PLAYER_OFFER_END_Y - SKI_PLAYER_OFFER_BOXES_BEGIN_Y) / SKI_INV_OFFSET_Y)
|
|
|
|
#define SKI_PLAYERS_CURRENT_BALANCE_X (SKI_PLAYER_OFFER_BEGIN_X + 9)
|
|
#define SKI_PLAYERS_CURRENT_BALANCE_Y (SKI_PLAYER_OFFER_BEGIN_Y + 35)
|
|
#define SKI_PLAYERS_CURRENT_BALANCE_WIDTH SKI_TOTAL_COST_WIDTH
|
|
#define SKI_PLAYERS_CURRENT_BALANCE_OFFSET_TO_VALUE (SKI_PLAYERS_CURRENT_BALANCE_Y + 20)
|
|
|
|
#define SKI_TOTAL_VALUE_X (SKI_PLAYER_OFFER_BEGIN_X + 9)
|
|
#define SKI_TOTAL_VALUE_Y (SKI_PLAYERS_CURRENT_BALANCE_Y + 50)
|
|
#define SKI_TOTAL_VALUE_WIDTH SKI_TOTAL_COST_WIDTH
|
|
#define SKI_TOTAL_VALUE_OFFSET_TO_VALUE (SKI_TOTAL_VALUE_Y + 20)
|
|
|
|
#define SKI_TRANSACTION_BUTTON_X (SKI_PLAYER_OFFER_BEGIN_X + 147)//214
|
|
#define SKI_TRANSACTION_BUTTON_Y (SKI_PLAYER_OFFER_BEGIN_Y + 8)
|
|
|
|
#define SKI_DONE_BUTTON_X (SKI_PLAYER_OFFER_BEGIN_X + 292)//414
|
|
#define SKI_DONE_BUTTON_Y SKI_TRANSACTION_BUTTON_Y
|
|
|
|
// when colouring the tradescreen, we use this margin
|
|
#define SKI_MARGIN 4
|
|
////////////////////////////////////////////
|
|
//
|
|
// Global Variables
|
|
//
|
|
///////////////////////////////////////////
|
|
#ifdef JA2UB
|
|
//ja25 UB
|
|
enum
|
|
{
|
|
TRNSMTR_MSG_BOX__NONE,
|
|
TRNSMTR_MSG_BOX__1_FRAME_WAIT,
|
|
TRNSMTR_MSG_BOX__DISPLAY_BOX,
|
|
};
|
|
|
|
void AskUserToAttachTransmitterToLaptop();
|
|
void AttachLaptopTransmitterToLaptop( UINT8 ubExitValue );
|
|
#endif
|
|
|
|
UINT32 guiCornerWhereTacticalIsStillSeenImage; //This image is for where the corner of tactical is still seen through the shop keeper interface
|
|
|
|
BOOLEAN gfSKIScreenEntry = TRUE;
|
|
BOOLEAN gfSKIScreenExit = FALSE;
|
|
BOOLEAN gfUserHasRequestedToLeave = FALSE;
|
|
|
|
BOOLEAN gfRenderScreenOnNextLoop = FALSE;
|
|
|
|
UINT8 gubSkiDirtyLevel = SKI_DIRTY_LEVEL0;
|
|
INT32 giSKIMessageBox=-1;
|
|
|
|
INT8 gbSelectedArmsDealerID = -1; //Contains the enum value for the currently selected arms dealer
|
|
|
|
// Flugente: while we're trading, store the ID of non-NPC dealers
|
|
UINT8 gusIDOfCivTrader = NOBODY;
|
|
|
|
//the quote that is in progress, in certain circumstances, we don't want queuing of related but different quotes
|
|
INT32 giShopKeepDialogueEventinProgress = - 1;
|
|
|
|
INVENTORY_IN_SLOT gMoveingItem;
|
|
|
|
OBJECTTYPE *gpHighLightedItemObject=NULL;
|
|
|
|
BOOLEAN gfResetShopKeepIdleQuote = FALSE;
|
|
BOOLEAN gfDoEvaluationAfterOpening = FALSE;
|
|
|
|
typedef struct
|
|
{
|
|
UINT8 ubCurrentPage;
|
|
UINT8 ubNumberOfPages;
|
|
|
|
UINT16 ubFirstItemIndexOnPage;
|
|
|
|
} SELECTED_ARMS_DEALERS_STATS;
|
|
|
|
SELECTED_ARMS_DEALERS_STATS gSelectArmsDealerInfo;
|
|
|
|
//This pointer is used to store the inventory the arms dealer has for sale
|
|
std::vector<INVENTORY_IN_SLOT> gpTempDealersInventory;
|
|
|
|
INVENTORY_IN_SLOT ArmsDealerOfferArea[ SKI_NUM_TRADING_INV_SLOTS ];
|
|
INVENTORY_IN_SLOT PlayersOfferArea[ SKI_NUM_TRADING_INV_SLOTS ];
|
|
|
|
std::vector<OBJECTTYPE> subObjects;
|
|
|
|
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;
|
|
|
|
#ifdef JA2UB
|
|
UINT8 gubDisplayMsgBoxAskingUserToAttachTransmitter=0; // Ja25 UB
|
|
#endif
|
|
|
|
// 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[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ];
|
|
UINT32 guiSmallSoldiersFace[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ];
|
|
UINT8 gubNumberMercsInArray;
|
|
|
|
//The subutitled text for what the merc is saying
|
|
CHAR16 gsShopKeeperTalkingText[ SKI_SUBTITLE_TEXT_SIZE ];
|
|
|
|
UINT16 gusPositionOfSubTitlesX=0;
|
|
|
|
BOOLEAN gfExitSKIDueToMessageBox=FALSE;
|
|
|
|
OBJECTTYPE *pShopKeeperItemDescObject=NULL;
|
|
|
|
#ifdef JA2UB
|
|
BOOLEAN gfCanSayMakeTransactionQuote; //ja25 UB
|
|
#endif
|
|
|
|
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 OBJECTTYPE *gpItemDescPrevObject;
|
|
extern OBJECTTYPE *gpItemDescPrevObject;
|
|
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 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;
|
|
|
|
class ITEM_TO_ADD_AFTER_SKI_OPEN
|
|
{
|
|
public:
|
|
ITEM_TO_ADD_AFTER_SKI_OPEN() {initialize();};
|
|
void initialize() {fActive = FALSE; ItemObject.initialize();};
|
|
BOOLEAN fActive;
|
|
OBJECTTYPE ItemObject;
|
|
};
|
|
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;
|
|
|
|
//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;
|
|
|
|
UINT32 guiItemCrossOut;
|
|
UINT32 guiMainTradeScreenImage = -1;
|
|
|
|
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 ];
|
|
int gDealersInventoryActiveRegions = 0;
|
|
void SelectDealersInventoryRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
void SelectDealersInventoryMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
|
|
MOUSE_REGION gDealersOfferSlotsMouseRegions[ SKI_NUM_TRADING_INV_SLOTS ];
|
|
MOUSE_REGION gDealersOfferSlotsSmallFaceMouseRegions[SKI_NUM_TRADING_INV_SLOTS];
|
|
int gDealersOfferActiveRegions = 0;
|
|
void SelectDealersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
void SelectDealersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
|
|
MOUSE_REGION gPlayersOfferSlotsMouseRegions[ SKI_NUM_TRADING_INV_SLOTS ];
|
|
MOUSE_REGION gPlayersOfferSlotsSmallFaceMouseRegions[SKI_NUM_TRADING_INV_SLOTS];
|
|
int gPlayersOfferActiveRegions = 0;
|
|
void SelectPlayersOfferSlotsRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
void SelectPlayersOfferSlotsMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
|
|
MOUSE_REGION gSkiInventoryMovementAreaMouseRegions;
|
|
|
|
//Mouse region for the subtitles region when the merc is talking
|
|
MOUSE_REGION gShopKeeperSubTitleMouseRegion;
|
|
void ShopKeeperSubTitleRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason );
|
|
|
|
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( DEALER_SPECIAL_ITEM* pSpecial, std::vector<INVENTORY_IN_SLOT>& pInventory, UINT8 ubOwner );
|
|
BOOLEAN RepairIsDone(DEALER_SPECIAL_ITEM* pSpecial);
|
|
|
|
UINT32 DisplayInvSlot( UINT16 ubSlotNum, UINT16 usItemIndex, UINT16 usPosX, UINT16 usPosY, OBJECTTYPE *ItemObject, BOOLEAN fHatchedOut, UINT8 ubItemArea );
|
|
void DisplayArmsDealerOfferArea();
|
|
INT16 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation );
|
|
BOOLEAN RemoveItemFromArmsDealerOfferArea( INT16 bSlotId, BOOLEAN fKeepItem );
|
|
void SetSkiRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION* pRegion, UINT8 ubScreenArea );
|
|
void SetSkiFaceRegionHelpText( INVENTORY_IN_SLOT *pInv, MOUSE_REGION* pRegion, UINT8 ubScreenArea );
|
|
void RestoreTacticalBackGround();
|
|
void DisplayPlayersOfferArea();
|
|
UINT32 CalcShopKeeperItemPrice( BOOLEAN fDealerSelling, BOOLEAN fUnitPriceOnly, UINT16 usItemID, FLOAT dModifier, OBJECTTYPE *pItemObject );
|
|
FLOAT ItemConditionModifier(UINT16 usItemIndex, INT16 bStatus);
|
|
BOOLEAN RemoveItemFromPlayersOfferArea( INT16 bSlotIdInOtherLocation );
|
|
|
|
UINT32 CalculateTotalArmsDealerCost();
|
|
UINT32 CalculateTotalPlayersValue();
|
|
void MoveAllArmsDealersItemsInOfferAreaToPlayersOfferArea( );
|
|
void PerformTransaction( UINT32 uiMoneyFromPlayersAccount );
|
|
void MovePlayerOfferedItemsOfValueToArmsDealersInventory( );
|
|
INT16 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT16 ubSpotLocation, UINT8 ubWhere );
|
|
BOOLEAN RemoveItemFromDealersInventory( INVENTORY_IN_SLOT* pInvSlot, UINT16 ubSlot );
|
|
BOOLEAN InitShopKeepersFace( UINT8 usProfileID );
|
|
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 HandleCurrentModeText( UINT8 ubMode );
|
|
void EnableDisableDealersInventoryPageButtons();
|
|
void EnableDisableEvaluateAndTransactionButtons();
|
|
BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( );
|
|
|
|
UINT32 CalculateHowMuchMoneyIsInPlayersOfferArea( );
|
|
void MovePlayersItemsToBeRepairedToArmsDealersInventory();
|
|
BOOLEAN RemoveRepairItemFromDealersOfferArea( INT16 bSlot );
|
|
|
|
INT8 GetInvSlotOfUnfullMoneyInMercInventory( SOLDIERTYPE *pSoldier );
|
|
void ClearPlayersOfferSlot( INT32 ubSlotToClear );
|
|
void ClearArmsDealerOfferSlot( INT32 ubSlotToClear );
|
|
|
|
BOOLEAN DoSkiMessageBox( UINT8 ubStyle, STR16 zString, UINT32 uiExitScreen, UINT8 ubFlags, MSGBOX_CALLBACK ReturnCallback );
|
|
|
|
BOOLEAN WillShopKeeperRejectObjectsFromPlayer( INT8 bDealerId, INT8 bSlotId );
|
|
void CheckAndHandleClearingOfPlayerOfferArea( void );
|
|
BOOLEAN CanShopkeeperOverrideDialogue( void );
|
|
INT16 GetNumberOfItemsInPlayerOfferArea( void );
|
|
void HandleCheckIfEnoughOnTheTable( void );
|
|
void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT16 ubPocket, UINT8 ubFromLocation );
|
|
void StartSKIDescriptionBox( void );
|
|
|
|
BOOLEAN ShopkeeperAutoPlaceObject( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN fNewItem );
|
|
void ShopkeeperAddItemToPool( INT32 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, INT16 bOwnerSlotId );
|
|
|
|
void SplitComplexObjectIntoSubObjects( OBJECTTYPE *pComplexObject );
|
|
void CountSubObjectsInObject( OBJECTTYPE *pComplexObject, UINT8 *pubRepairableSubObjects, UINT8 *pubNonRepairableSubObjects );
|
|
BOOLEAN AddObjectForEvaluation(OBJECTTYPE *pObject, UINT8 ubOwnerProfileId, INT16 bOwnerSlotId, BOOLEAN fFirstOne );
|
|
BOOLEAN OfferObjectToDealer( OBJECTTYPE *pComplexObject, UINT8 ubOwnerProfileId, INT16 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, INT16 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, INVENTORY_IN_SLOT* pObject );
|
|
|
|
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;
|
|
|
|
void INVENTORY_IN_SLOT::initialize()
|
|
{
|
|
ItemObject.initialize();
|
|
fActive = 0;
|
|
sItemIndex = 0;
|
|
uiFlags = 0;
|
|
ubLocationOfObject = 0;
|
|
bSlotIdInOtherLocation = 0;
|
|
ubIdOfMercWhoOwnsTheItem = 0;
|
|
uiItemPrice = 0;
|
|
uiRepairDoneTime = 0;
|
|
}
|
|
|
|
INVENTORY_IN_SLOT& INVENTORY_IN_SLOT::operator=(OLD_INVENTORY_IN_SLOT_101& src)
|
|
{
|
|
this->ItemObject = src.oldItemObject;
|
|
this->fActive = src.fActive;
|
|
this->sItemIndex = src.sItemIndex;
|
|
this->uiFlags = src.uiFlags;
|
|
this->ubLocationOfObject = src.ubLocationOfObject;
|
|
this->bSlotIdInOtherLocation = src.bSlotIdInOtherLocation;
|
|
this->ubIdOfMercWhoOwnsTheItem = src.ubIdOfMercWhoOwnsTheItem;
|
|
this->uiItemPrice = src.uiItemPrice;
|
|
this->uiRepairDoneTime = 0;
|
|
return *this;
|
|
}
|
|
|
|
//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( );
|
|
//ADB if we fail, unpause the game
|
|
UnPauseGame();
|
|
|
|
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->flags.fCheckForNewlyAddedItems )
|
|
{
|
|
// Startup any newly added items....
|
|
CheckForAnyNewlyAddedItems( gpSMCurrentMerc );
|
|
gpSMCurrentMerc->flags.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
|
|
DisableSMPpanelButtonsWhenInShopKeeperInterface( FALSE );
|
|
|
|
RenderButtons( );
|
|
|
|
//CHRISL: If we put this function call here, we overwrite the bullet graphic. I don't know why. I just know it happens.
|
|
//RenderItemDescriptionBox( );
|
|
|
|
// 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;
|
|
|
|
//ADB if we are here, we must be able to talk with an extended ear (CheckIfRadioIsEquipped())
|
|
//but if we are physically too far away, we don't have extended arms!
|
|
|
|
SOLDIERTYPE* pSoldier = MercPtrs[ gusSelectedSoldier ];
|
|
SOLDIERTYPE* pShopkeeper = NULL;
|
|
|
|
if ( gusIDOfCivTrader != NOBODY )
|
|
pShopkeeper = MercPtrs[gusIDOfCivTrader];
|
|
else
|
|
pShopkeeper = FindSoldierByProfileID( armsDealerInfo[gbSelectedArmsDealerID].ubShopKeeperID, FALSE );
|
|
|
|
if ( GetRangeFromGridNoDiff( pSoldier->sGridNo, pShopkeeper->sGridNo ) > NPC_TALK_RADIUS )
|
|
{
|
|
//so now we know we are too far away to trade, so instead of just quitting,
|
|
//either post a message or run to the guy like HandleTalkInit does
|
|
if( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, L"Unable to interact with shopkeeper during combat" );
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
// First calculate APs and validate...
|
|
// Check AP cost...
|
|
if ( !EnoughPoints( pSoldier, APBPConstants[AP_TALK], 0, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// First get an adjacent gridno....
|
|
UINT8 ubDirection;
|
|
INT32 sActionGridNo = FindAdjacentGridEx( pSoldier, pShopkeeper->sGridNo, &ubDirection, NULL, FALSE, TRUE );
|
|
|
|
if ( sActionGridNo == -1 )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ NO_PATH ] );
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( UIPlotPath( pSoldier, sActionGridNo, NO_COPYROUTE, FALSE, TEMPORARY, pSoldier->usUIMovementMode, NOT_STEALTH, FORWARD, pSoldier->bActionPoints ) == 0 )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ NO_PATH ] );
|
|
return( FALSE );
|
|
}
|
|
|
|
// Walk up and talk to buddy....
|
|
gfNPCCircularDistLimit = TRUE;
|
|
INT32 sGoodGridNo = FindGridNoFromSweetSpotWithStructData( pSoldier, pSoldier->usUIMovementMode, pShopkeeper->sGridNo, (NPC_TALK_RADIUS-1), &ubDirection, TRUE );
|
|
gfNPCCircularDistLimit = FALSE;
|
|
|
|
// Now walkup to talk....
|
|
pSoldier->aiData.ubPendingAction = MERC_TALK;
|
|
pSoldier->aiData.uiPendingActionData1 = pShopkeeper->ubID;
|
|
pSoldier->aiData.ubPendingActionAnimCount = 0;
|
|
|
|
// WALK UP TO DEST FIRST
|
|
pSoldier->EVENT_InternalGetNewSoldierPath(sGoodGridNo, pSoldier->usUIMovementMode , TRUE , pSoldier->flags.fNoAPToFinishMove );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
//Heinz: 22.02.09 BUGFIX: best way - to update whole tactical screen around SKI
|
|
//vs_desc.usWidth = SKI_TACTICAL_BACKGROUND_START_WIDTH;
|
|
//vs_desc.usHeight = SKI_TACTICAL_BACKGROUND_START_HEIGHT;
|
|
vs_desc.usWidth = SCREEN_WIDTH;
|
|
vs_desc.usHeight = SCREEN_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 );
|
|
}
|
|
|
|
//Heinz: 22.02.09 shadowing of tactical screen for further using as a background
|
|
ShadowVideoSurfaceRect( guiCornerWhereTacticalIsStillSeenImage, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
//Clear out all the save background rects
|
|
EmptyBackgroundRects( );
|
|
|
|
ShadowVideoSurfaceRect( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - INV_INTERFACE_HEIGHT );
|
|
|
|
if( gfExitSKIDueToMessageBox )
|
|
{
|
|
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
|
gfExitSKIDueToMessageBox = FALSE;
|
|
}
|
|
|
|
// silversurfer: added this to prevent random crashes when the temp vector wasn't initialized properly.
|
|
// This is called in InitializeShopKeeper() a few lines below anyway so it shouldn't hurt here.
|
|
gpTempDealersInventory.clear();
|
|
|
|
//Check to make sure the inventory is null ( should always be null if we are just coming in to the SKI )
|
|
Assert( gpTempDealersInventory.empty() == true );
|
|
|
|
//Reinitialize the team panel to be the SM panel
|
|
SetCurrentInterfacePanel( SM_PANEL );
|
|
SetCurrentTacticalPanelCurrentMerc( (UINT8)gusSelectedSoldier );
|
|
SetSMPanelCurrentMerc( (UINT8)gusSelectedSoldier );
|
|
|
|
// 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 );
|
|
}
|
|
|
|
//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->flags.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
|
|
if ( gProfilesIMP[ pSoldier->ubProfile ].ProfilId == pSoldier->ubProfile )
|
|
{
|
|
sprintf( zTemp, "IMPFACES\\33FACE\\%02d.sti", gMercProfiles[ pSoldier->ubProfile ].ubFaceIndex );
|
|
}
|
|
else
|
|
{
|
|
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 );
|
|
|
|
EnableDisableShopkeeperButtons(SHOPKEEPER_SCREEN, ACTIVATE_BUTTON);
|
|
|
|
//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 );
|
|
|
|
//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 );
|
|
|
|
for (int x = 0; x < SKI_NUM_TRADING_INV_SLOTS; ++x)
|
|
{
|
|
ArmsDealerOfferArea[x].initialize();
|
|
PlayersOfferArea[x].initialize();
|
|
}
|
|
|
|
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;
|
|
|
|
gMoveingItem.initialize();
|
|
|
|
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;
|
|
gfDisplayNoRoomMsg = FALSE;
|
|
|
|
//Disable the map radar region
|
|
MSYS_DisableRegion(&gRadarRegion);
|
|
|
|
gfDoEvaluationAfterOpening = FALSE;
|
|
|
|
if( gItemToAdd.fActive )
|
|
{
|
|
bool fAddedOK = false;
|
|
//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_TRADER_INVENTORY_BOXES_PER_ROW * SKI_TRADER_INVENTORY_BOXES_PER_COL)) )
|
|
{
|
|
if ( OfferObjectToDealer( &(gItemToAdd.ItemObject), gpSMCurrentMerc->ubProfile, NO_SLOT ) )
|
|
{
|
|
fAddedOK = true;
|
|
}
|
|
}
|
|
|
|
if ( fAddedOK == true )
|
|
{
|
|
// evaluate it
|
|
gfDoEvaluationAfterOpening = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//add the item back to the current PC into the slot it came from
|
|
//ADB screw slot, slot is (used to be, before it was deleted) only ever, so autoplace it
|
|
AutoPlaceObject(&Menptr[ gpSMCurrentMerc->ubID ], &gItemToAdd.ItemObject, FALSE);
|
|
}
|
|
|
|
//Clear the contents of the structure
|
|
gItemToAdd.initialize();
|
|
}
|
|
|
|
// 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;
|
|
#ifdef JA2UB
|
|
//JA25 UB
|
|
//if the dealer is RAUL
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_RAUL )
|
|
{
|
|
//set the fact the raul refreshed his inventory
|
|
SetFactFalse( FACT_RAULS_INVENTORY_CHANGED_SINCE_LAST_VISIT );
|
|
}
|
|
#endif
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN InitShopKeepersFace( UINT8 usProfileID )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
// if this is a non-NPC, don't set this up
|
|
if ( gusIDOfCivTrader == NOBODY )
|
|
pSoldier = FindSoldierByProfileID( armsDealerInfo[gbSelectedArmsDealerID].ubShopKeeperID, FALSE );
|
|
|
|
if( pSoldier == NULL )
|
|
{
|
|
//Create the facial index
|
|
giShopKeeperFaceIndex = InitFace( usProfileID, NOBODY, FACE_BIGFACE );
|
|
}
|
|
else
|
|
{
|
|
//Create the facial index
|
|
giShopKeeperFaceIndex = InitFace( usProfileID, 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
|
|
if ( giShopKeeperFaceIndex > -1 )
|
|
gFacesData[ giShopKeeperFaceIndex ].uiFlags |= FACE_INACTIVE_HANDLED_ELSEWHERE;
|
|
|
|
RenderAutoFace( giShopKeeperFaceIndex );
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN ExitShopKeeperInterface()
|
|
{
|
|
if( gfExitSKIDueToMessageBox )
|
|
{
|
|
gfSKIScreenExit = FALSE;
|
|
|
|
// gfExitSKIDueToMessageBox = FALSE;
|
|
}
|
|
|
|
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
|
|
{
|
|
DeleteItemDescriptionBox( );
|
|
}
|
|
|
|
FreeMouseCursor( TRUE );
|
|
|
|
//Delete the main shopkeep background
|
|
DeleteVideoObjectFromIndex( guiItemCrossOut );
|
|
DeleteVideoSurfaceFromIndex( guiCornerWhereTacticalIsStillSeenImage );
|
|
|
|
if ( guiMainTradeScreenImage != -1 )
|
|
{
|
|
DeleteVideoSurfaceFromIndex( guiMainTradeScreenImage );
|
|
guiMainTradeScreenImage = -1;
|
|
}
|
|
|
|
ShutUpShopKeeper();
|
|
|
|
UnloadButtonImage( guiSKI_InvPageUpButtonImage );
|
|
UnloadButtonImage( guiSKI_InvPageDownButtonImage );
|
|
|
|
//loop through the area and delete small faces
|
|
for (UINT8 ubCnt=0; ubCnt<gubNumberMercsInArray; ++ubCnt)
|
|
{
|
|
DeleteVideoObjectFromIndex( guiSmallSoldiersFace[ ubCnt ] );
|
|
}
|
|
|
|
RemoveButton( guiSKI_InvPageUpButton );
|
|
RemoveButton( guiSKI_InvPageDownButton );
|
|
|
|
EnableDisableShopkeeperButtons(SHOPKEEPER_SCREEN, DEACTIVATE_BUTTON);
|
|
|
|
MSYS_RemoveRegion( &gSKI_EntireScreenMouseRegions);
|
|
|
|
MSYS_RemoveRegion( &gSkiInventoryMovementAreaMouseRegions );
|
|
|
|
//Remove the region for the face
|
|
MSYS_RemoveRegion( &gArmsDealersFaceMouseRegions );
|
|
|
|
//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
|
|
gpTempDealersInventory.clear();
|
|
|
|
//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;
|
|
#ifdef JA2UB
|
|
//JA25 UB
|
|
//Check to see if a merc should say something
|
|
//CheckForValidQuotesWhenLeavingDealer( gTalkPanel.ubCharNum );
|
|
|
|
//if the laptop was just fixed
|
|
if( gubQuest[ QUEST_FIX_LAPTOP ] == QUESTDONE && !( gJa25SaveStruct.uiJa25GeneralFlags & JA_GF__PLAYER_SAID_LAPTOP_FIXED_QUOTE ) )
|
|
{
|
|
INT8 bSoldierID=-1;
|
|
|
|
//Have a new merc say a quote
|
|
bSoldierID = RandomSoldierIdFromNewMercsOnPlayerTeam();
|
|
if( bSoldierID != -1 )
|
|
{
|
|
TacticalCharacterDialogue( &Menptr[ bSoldierID ], QUOTE_JA2UB_LAPTOP_FIXED );
|
|
}
|
|
|
|
gJa25SaveStruct.uiJa25GeneralFlags |= JA_GF__PLAYER_SAID_LAPTOP_FIXED_QUOTE;
|
|
}
|
|
#endif
|
|
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 );
|
|
EnableDisableShopkeeperButtons(SHOPKEEPER_SCREEN, DISABLE_BUTTON);
|
|
//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;
|
|
//Heinz: 22.02.09 BUGFIX: buttons should render for items in inventory with EDB
|
|
//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( ) )
|
|
{
|
|
RenderItemStackPopup( ( BOOLEAN )( fInterfacePanelDirty == DIRTYLEVEL2 ) );
|
|
}
|
|
|
|
// handle check if enough on the table
|
|
HandleCheckIfEnoughOnTheTable( );
|
|
|
|
// Render view window
|
|
fInterfacePanelDirty = DIRTYLEVEL2;
|
|
RenderRadarScreen( );
|
|
|
|
if( fInterfacePanelDirty == DIRTYLEVEL2 )
|
|
{
|
|
fInterfacePanelDirty = DIRTYLEVEL0;
|
|
}
|
|
|
|
DisplayTalkingArmsDealer();
|
|
|
|
MarkButtonsDirty( );
|
|
|
|
if( gfDoEvaluationAfterOpening )
|
|
{
|
|
BOOLEAN fFirstOne = TRUE;
|
|
|
|
gfDoEvaluationAfterOpening = FALSE;
|
|
|
|
for ( iCounter = 0; iCounter < gPlayersOfferActiveRegions; ++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 )
|
|
//Heinz: 23.02.09 BUGFIX: if shopkeeper is talking we should render popup in all cases
|
|
//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();
|
|
}
|
|
#ifdef JA2UB
|
|
//ja25 UB
|
|
else if( gubDisplayMsgBoxAskingUserToAttachTransmitter != TRNSMTR_MSG_BOX__NONE )
|
|
{
|
|
if( gubDisplayMsgBoxAskingUserToAttachTransmitter == TRNSMTR_MSG_BOX__1_FRAME_WAIT )
|
|
{
|
|
gubDisplayMsgBoxAskingUserToAttachTransmitter = TRNSMTR_MSG_BOX__DISPLAY_BOX;
|
|
}
|
|
else if( gubDisplayMsgBoxAskingUserToAttachTransmitter == TRNSMTR_MSG_BOX__DISPLAY_BOX )
|
|
{
|
|
//Tell user that they are attaching the transmitter
|
|
AskUserToAttachTransmitterToLaptop();
|
|
|
|
//clear the flag
|
|
gubDisplayMsgBoxAskingUserToAttachTransmitter = TRNSMTR_MSG_BOX__NONE;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BOOLEAN RenderShopKeeperInterface()
|
|
{
|
|
CHAR16 zMoney[128];
|
|
HVSURFACE hDestVSurface, hSrcVSurface;
|
|
SGPRect SrcRect;
|
|
|
|
if( InItemDescriptionBox( ) && pShopKeeperItemDescObject != NULL )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// wipe everything once and then redraw
|
|
if ( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
|
|
{
|
|
//Restore the area before blitting the new data on
|
|
RestoreExternBackgroundRect( SKI_TOTAL_BEGIN_X, SKI_TOTAL_BEGIN_Y,
|
|
SKI_TOTAL_END_X - SKI_TOTAL_BEGIN_X,
|
|
SKI_TOTAL_END_Y - SKI_TOTAL_BEGIN_Y );
|
|
}
|
|
|
|
UINT16 col_tradescreenmargin = Get16BPPColor( FROMRGB( 64, 64, 64 ) );
|
|
UINT16 col_tradescreen = Get16BPPColor( FROMRGB( 255, 0, 255 ) );
|
|
UINT16 col_itembox = Get16BPPColor( FROMRGB( 74, 65, 49 ) );
|
|
UINT16 col_itemdescription = Get16BPPColor( FROMRGB( 181, 150, 74 ) );
|
|
UINT16 col_itemstatusbar = Get16BPPColor( FROMRGB( 57, 56, 41 ) );
|
|
|
|
// we need to do the colouring twice to colour the margin differently
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, SKI_TOTAL_BEGIN_X, SKI_TOTAL_BEGIN_Y,
|
|
SKI_TOTAL_END_X, SKI_TOTAL_END_Y,
|
|
col_tradescreenmargin );
|
|
|
|
// Flugente: because people find simple plane backgrounds to be offputting, we try for something more fancy
|
|
// we use a very huge background picture and then display parts of it.
|
|
// Given that the default picture has a size of 3088x2056, you would need a gigantic resolution for this to not work out.
|
|
// Flugente: guiMainTradeScreenImage is unsigned as the functions require UINT32. As it is unlikely we will ever use 2^32 pictures, this works well enough
|
|
if ( guiMainTradeScreenImage == -1 )
|
|
{
|
|
VSURFACE_DESC vs_desc;
|
|
vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE;
|
|
strcpy( vs_desc.ImageFile, "LAPTOP\\shopkeeperbackground.pcx" );
|
|
if ( FileExists( vs_desc.ImageFile ) )
|
|
{
|
|
AddVideoSurface( &vs_desc, &guiMainTradeScreenImage );
|
|
}
|
|
}
|
|
|
|
if ( guiMainTradeScreenImage != -1 )
|
|
{
|
|
HVSURFACE hSrcVSurface;
|
|
UINT32 uiDestPitchBYTES;
|
|
UINT32 uiSrcPitchBYTES;
|
|
UINT16 *pDestBuf;
|
|
UINT8 *pSrcBuf;
|
|
SGPRect clip;
|
|
|
|
// get surfaces
|
|
pDestBuf = (UINT16*)LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
|
|
GetVideoSurface( &hSrcVSurface, guiMainTradeScreenImage );
|
|
pSrcBuf = LockVideoSurface( guiMainTradeScreenImage, &uiSrcPitchBYTES );
|
|
|
|
// for our 3 regions we display only parts of the picture
|
|
clip.iLeft = SKI_TRADER_INVENTORY_BEGIN_X + SKI_MARGIN;
|
|
clip.iRight = SKI_TRADER_INVENTORY_END_X - SKI_MARGIN;
|
|
clip.iTop = SKI_TRADER_INVENTORY_BEGIN_Y + SKI_MARGIN;
|
|
clip.iBottom = SKI_TRADER_INVENTORY_END_Y - SKI_MARGIN;
|
|
|
|
Blt8BPPDataSubTo16BPPBuffer( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf, uiSrcPitchBYTES, SKI_TRADER_INVENTORY_BEGIN_X + SKI_MARGIN, SKI_TRADER_INVENTORY_BEGIN_Y + SKI_MARGIN, &clip );
|
|
|
|
clip.iLeft = SKI_TRADER_OFFER_BEGIN_X + SKI_MARGIN;
|
|
clip.iRight = SKI_TRADER_OFFER_END_X - SKI_MARGIN;
|
|
clip.iTop = SKI_TRADER_OFFER_BEGIN_Y + SKI_MARGIN;
|
|
clip.iBottom = SKI_TRADER_OFFER_END_Y - SKI_MARGIN;
|
|
|
|
Blt8BPPDataSubTo16BPPBuffer( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf, uiSrcPitchBYTES, SKI_TRADER_OFFER_BEGIN_X + SKI_MARGIN, SKI_TRADER_OFFER_BEGIN_Y + SKI_MARGIN, &clip );
|
|
|
|
clip.iLeft = SKI_PLAYER_OFFER_BEGIN_X + SKI_MARGIN;
|
|
clip.iRight = SKI_PLAYER_OFFER_END_X - SKI_MARGIN;
|
|
clip.iTop = SKI_PLAYER_OFFER_BEGIN_Y + SKI_MARGIN;
|
|
clip.iBottom = SKI_PLAYER_OFFER_END_Y - SKI_MARGIN;
|
|
|
|
Blt8BPPDataSubTo16BPPBuffer( pDestBuf, uiDestPitchBYTES, hSrcVSurface, pSrcBuf, uiSrcPitchBYTES, SKI_PLAYER_OFFER_BEGIN_X + SKI_MARGIN, SKI_PLAYER_OFFER_BEGIN_Y + SKI_MARGIN, &clip );
|
|
|
|
// release surfaces
|
|
UnLockVideoSurface( guiMainTradeScreenImage );
|
|
UnLockVideoSurface( FRAME_BUFFER );
|
|
}
|
|
// if we cannot find the picture, use a fallback solution
|
|
else
|
|
{
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, SKI_TRADER_INVENTORY_BEGIN_X + SKI_MARGIN, SKI_TRADER_INVENTORY_BEGIN_Y + SKI_MARGIN,
|
|
SKI_TRADER_INVENTORY_END_X - SKI_MARGIN, SKI_TRADER_INVENTORY_END_Y - SKI_MARGIN,
|
|
col_tradescreen );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, SKI_TRADER_OFFER_BEGIN_X + SKI_MARGIN, SKI_TRADER_OFFER_BEGIN_Y + SKI_MARGIN,
|
|
SKI_TRADER_OFFER_END_X - SKI_MARGIN, SKI_TRADER_OFFER_END_Y - SKI_MARGIN,
|
|
col_tradescreen );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, SKI_PLAYER_OFFER_BEGIN_X + SKI_MARGIN, SKI_PLAYER_OFFER_BEGIN_Y + SKI_MARGIN,
|
|
SKI_PLAYER_OFFER_END_X - SKI_MARGIN, SKI_PLAYER_OFFER_END_Y - SKI_MARGIN,
|
|
col_tradescreen );
|
|
}
|
|
|
|
{
|
|
int usPosY = SKI_TRADER_INVENTORY_BOXES_BEGIN_Y;
|
|
for ( int y = 0; y<SKI_TRADER_INVENTORY_BOXES_PER_COL; ++y )
|
|
{
|
|
int usPosX = SKI_TRADER_INVENTORY_BOXES_BEGIN_X;
|
|
|
|
for ( int x = 0; x<SKI_TRADER_INVENTORY_BOXES_PER_ROW; ++x )
|
|
{
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, usPosX, usPosY,
|
|
(INT16)(usPosX + 4), (INT16)(usPosY + 24),
|
|
col_itemstatusbar );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, (INT16)(usPosX + 4), usPosY,
|
|
(INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + 24),
|
|
col_itembox );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, usPosX, (INT16)(usPosY + 24),
|
|
(INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + SKI_INV_SLOT_HEIGHT),
|
|
col_itemdescription );
|
|
|
|
usPosX += SKI_INV_OFFSET_X;
|
|
}
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
|
|
{
|
|
int usPosY = SKI_TRADER_OFFER_BOXES_BEGIN_Y;
|
|
for ( int y = 0; y<SKI_TRADER_OFFER_BOXES_PER_COL; ++y )
|
|
{
|
|
int usPosX = SKI_TRADER_OFFER_BOXES_BEGIN_X;
|
|
|
|
for ( int x = 0; x<SKI_TRADER_OFFER_BOXES_PER_ROW; ++x )
|
|
{
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, usPosX, usPosY,
|
|
(INT16)(usPosX + 4), (INT16)(usPosY + 24),
|
|
col_itemstatusbar );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, (INT16)(usPosX + 4), usPosY,
|
|
(INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + 24),
|
|
col_itembox );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, usPosX, (INT16)(usPosY + 24),
|
|
(INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + SKI_INV_SLOT_HEIGHT),
|
|
col_itemdescription );
|
|
|
|
usPosX += SKI_INV_OFFSET_X;
|
|
}
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
|
|
{
|
|
int usPosY = SKI_PLAYER_OFFER_BOXES_BEGIN_Y;
|
|
for ( int y = 0; y<SKI_PLAYER_OFFER_BOXES_PER_COL; ++y )
|
|
{
|
|
int usPosX = SKI_PLAYER_OFFER_BOXES_BEGIN_X;
|
|
|
|
for ( int x = 0; x<SKI_PLAYER_OFFER_BOXES_PER_ROW; ++x )
|
|
{
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, usPosX, usPosY,
|
|
(INT16)(usPosX + 4), (INT16)(usPosY + 24),
|
|
col_itemstatusbar );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, (INT16)(usPosX + 4), usPosY,
|
|
(INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + 24),
|
|
col_itembox );
|
|
|
|
ColorFillVideoSurfaceArea( FRAME_BUFFER, usPosX, (INT16)(usPosY + 24),
|
|
(INT16)(usPosX + SKI_INV_SLOT_WIDTH), (INT16)(usPosY + SKI_INV_SLOT_HEIGHT),
|
|
col_itemdescription );
|
|
|
|
usPosX += SKI_INV_OFFSET_X;
|
|
}
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
|
|
if ( giShopKeeperFaceIndex > -1 )
|
|
RenderAutoFace( giShopKeeperFaceIndex );
|
|
// Flugente: if this is a non-NPC dealer, we instead show their body in their current animation
|
|
else if ( gusIDOfCivTrader != NOBODY )
|
|
{
|
|
SOLDIERTYPE* pSoldier = MercPtrs[gusIDOfCivTrader];
|
|
|
|
if ( pSoldier )
|
|
{
|
|
UINT32 uiPitch;
|
|
|
|
// Lock video surface
|
|
UINT16* pBuffer = (UINT16*)LockVideoSurface( FRAME_BUFFER, &uiPitch );
|
|
|
|
if ( pBuffer != NULL )
|
|
{
|
|
UINT16 usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
|
|
HVOBJECT hVObject = gAnimSurfaceDatabase[usAnimSurface].hVideoObject;
|
|
|
|
ETRLEObject* pTrav = &(hVObject->pETRLEObject[pSoldier->usAniFrame]);
|
|
|
|
INT32 sCenX = SKI_FACE_X + (INT16)(abs( (long)(SKI_FACE_WIDTH - pTrav->usWidth) ) / 2) - pTrav->sOffsetX;
|
|
INT32 sCenY = SKI_FACE_Y + (INT16)(abs( (long)(SKI_FACE_HEIGHT - pTrav->usHeight) ) / 2) - pTrav->sOffsetY;
|
|
|
|
SGPRect rect;
|
|
rect.iLeft = SKI_FACE_X;
|
|
rect.iTop = SKI_FACE_Y;
|
|
rect.iRight = SKI_FACE_X + SKI_FACE_WIDTH;
|
|
rect.iBottom = SKI_FACE_Y + SKI_FACE_HEIGHT;
|
|
|
|
Blt8BPPDataTo16BPPBufferTransShadowClip( pBuffer, uiPitch,
|
|
hVObject,
|
|
sCenX, sCenY,
|
|
pSoldier->usAniFrame,
|
|
&rect,
|
|
pSoldier->pShades[pSoldier->ubFadeLevel] );
|
|
|
|
UnLockVideoSurface( FRAME_BUFFER );
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHRISL: If in NIV mode, don't display the clock
|
|
if ( UsingNewInventorySystem( ) == false )
|
|
RenderClock( INTERFACE_CLOCK_X, INTERFACE_CLOCK_Y );
|
|
|
|
// CHRISL: Added X,Y parameters to allow control of TownID string placement.
|
|
RenderTownIDString( LOCATION_NAME_X, LOCATION_NAME_Y );
|
|
|
|
//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 );
|
|
|
|
// display shopkeeper budget
|
|
DisplayWrappedString( SKI_BUDGET_X, SKI_BUDGET_Y, SKI_BUDGET_WIDTH, 2, SKI_LABEL_FONT, SKI_TITLE_COLOR, SKI_Text[SKI_TEXT_BUDGET], FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
|
|
|
swprintf( zMoney, L"%d", gArmsDealerStatus[gbSelectedArmsDealerID].uiArmsDealersCash );
|
|
|
|
InsertCommasForDollarFigure( zMoney );
|
|
|
|
CHAR16 zTemp2[64];
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
swprintf( zTemp2, L"%s Intel", zMoney );
|
|
else
|
|
swprintf( zTemp2, L"$%s", zMoney );
|
|
|
|
DrawTextToScreen( zTemp2, SKI_BUDGET_X, SKI_BUDGET_OFFSET_TO_VALUE, SKI_BUDGET_WIDTH, FONT10ARIAL, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, TRUE, 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 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
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
{
|
|
swprintf( zMoney, L"%d", (int)(GetIntel()) );
|
|
InsertCommasForDollarFigure( zMoney );
|
|
swprintf( zTemp2, L"%s Intel", zMoney );
|
|
}
|
|
else
|
|
{
|
|
swprintf( zMoney, L"%d", LaptopSaveInfo.iCurrentBalance );
|
|
InsertCommasForDollarFigure( zMoney );
|
|
swprintf( zTemp2, L"$%s", zMoney );
|
|
}
|
|
|
|
DrawTextToScreen( zTemp2, 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 );
|
|
|
|
//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 );
|
|
|
|
//Heinz: 22.02.09 BUGFIX: best way - to update whole tactical screen around SKI
|
|
//BlitBufferToBuffer( guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SKI_TACTICAL_BACKGROUND_START_X, SKI_TACTICAL_BACKGROUND_START_HEIGHT );
|
|
BlitBufferToBuffer( guiRENDERBUFFER, guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_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 );
|
|
|
|
//Heinz: 22.02.09 BUGFIX: best way - to update whole tactical screen around SKI
|
|
//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 );
|
|
SrcRect.iLeft = 0;
|
|
SrcRect.iTop = 0;
|
|
SrcRect.iRight = SCREEN_WIDTH;
|
|
SrcRect.iBottom = SCREEN_HEIGHT;
|
|
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, 0, 0, (RECT*)&SrcRect );
|
|
|
|
gfRenderScreenOnNextLoop = FALSE;
|
|
}
|
|
|
|
DisplayArmsDealerCurrentInventoryPage( );
|
|
|
|
DisplayArmsDealerOfferArea( );
|
|
|
|
DisplayPlayersOfferArea( );
|
|
|
|
EnableDisableEvaluateAndTransactionButtons( );
|
|
|
|
//if the merc is talking and the screen has been dirtied
|
|
if( gfIsTheShopKeeperTalking )
|
|
RenderMercPopUpBoxFromIndex( giPopUpBoxId, gusPositionOfSubTitlesX, SKI_POSITION_SUBTITLES_Y, FRAME_BUFFER);
|
|
|
|
//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 );
|
|
|
|
// Top
|
|
SrcRect.iLeft = 0;
|
|
SrcRect.iTop = 0;
|
|
SrcRect.iRight = SCREEN_WIDTH;
|
|
SrcRect.iBottom = SKI_TOTAL_BEGIN_Y;
|
|
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, SrcRect.iLeft, SrcRect.iTop, (RECT*)&SrcRect );
|
|
|
|
// Bottom
|
|
SrcRect.iLeft = 0;
|
|
SrcRect.iTop = SKI_TOTAL_END_Y;
|
|
SrcRect.iRight = SCREEN_WIDTH;
|
|
SrcRect.iBottom = SCREEN_HEIGHT - INV_INTERFACE_HEIGHT;
|
|
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, SrcRect.iLeft, SrcRect.iTop, (RECT*)&SrcRect );
|
|
|
|
// Left
|
|
SrcRect.iLeft = 0;
|
|
SrcRect.iTop = SKI_TOTAL_BEGIN_Y;
|
|
SrcRect.iRight = SKI_TOTAL_BEGIN_X;
|
|
SrcRect.iBottom = SKI_TOTAL_END_Y;
|
|
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, SrcRect.iLeft, SrcRect.iTop, (RECT*)&SrcRect );
|
|
|
|
// Right
|
|
SrcRect.iLeft = SKI_TOTAL_END_X;
|
|
SrcRect.iTop = SKI_TOTAL_BEGIN_Y;
|
|
SrcRect.iRight = SCREEN_WIDTH;
|
|
SrcRect.iBottom = SKI_TOTAL_END_Y;
|
|
BltVSurfaceUsingDD( hDestVSurface, hSrcVSurface, VO_BLT_SRCTRANSPARENCY, SrcRect.iLeft, SrcRect.iTop, (RECT*)&SrcRect );
|
|
}
|
|
|
|
void GetShopKeeperInterfaceUserInput()
|
|
{
|
|
InputAtom Event;
|
|
POINT MousePos;
|
|
|
|
GetCursorPos(&MousePos);
|
|
ScreenToClient(ghWindow, &MousePos); // In window coords!
|
|
|
|
while (DequeueSpecificEvent(&Event, KEY_DOWN|KEY_UP|KEY_REPEAT))
|
|
{
|
|
if( !HandleTextInput( &Event ) && Event.usEvent == KEY_DOWN )
|
|
{
|
|
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()
|
|
{
|
|
UINT16 usPosY=0;
|
|
CHAR16 zTemp[512];
|
|
CHAR16 zTemp2[64];
|
|
UINT8 ubForeColor;
|
|
|
|
//loop through all the shopkeeper's and display their money
|
|
for ( INT8 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 );
|
|
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
swprintf( zTemp2, L"%s Intel", zTemp );
|
|
else
|
|
swprintf( zTemp2, L"$%s", zTemp );
|
|
|
|
ubForeColor = ( UINT8 ) ( ( bArmsDealer == gbSelectedArmsDealerID ) ? SKI_BUTTON_COLOR : SKI_TITLE_COLOR );
|
|
DrawTextToScreen( zTemp2, 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);
|
|
}
|
|
}
|
|
|
|
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( )
|
|
{
|
|
int ubCnt, x,y;
|
|
UINT16 usPosX, usPosY;
|
|
|
|
// Create the mouse regions for the shopkeeper's inventory
|
|
usPosY = SKI_TRADER_INVENTORY_BOXES_BEGIN_Y;
|
|
ubCnt=0;
|
|
for ( y = 0; y<SKI_TRADER_INVENTORY_BOXES_PER_COL; ++y )
|
|
{
|
|
usPosX = SKI_TRADER_INVENTORY_BOXES_BEGIN_X;
|
|
|
|
for ( x = 0; x<SKI_TRADER_INVENTORY_BOXES_PER_ROW; ++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;
|
|
++gDealersInventoryActiveRegions;
|
|
}
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
|
|
// Create the mouse regions for the shopkeeper's trading slots
|
|
usPosY = SKI_TRADER_OFFER_BOXES_BEGIN_Y;
|
|
ubCnt=0;
|
|
for ( y = 0; y<SKI_TRADER_OFFER_BOXES_PER_COL; ++y )
|
|
{
|
|
usPosX = SKI_TRADER_OFFER_BOXES_BEGIN_X;
|
|
|
|
for ( x = 0; x<SKI_TRADER_OFFER_BOXES_PER_ROW; ++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;
|
|
++gDealersOfferActiveRegions;
|
|
}
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
|
|
// Create the mouse regions for the Players trading slots
|
|
usPosY = SKI_PLAYER_OFFER_BOXES_BEGIN_Y;
|
|
ubCnt=0;
|
|
for ( y = 0; y<SKI_PLAYER_OFFER_BOXES_PER_COL; ++y )
|
|
{
|
|
usPosX = SKI_PLAYER_OFFER_BOXES_BEGIN_X;
|
|
|
|
for ( x = 0; x<SKI_PLAYER_OFFER_BOXES_PER_ROW; ++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);
|
|
|
|
//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;
|
|
++gPlayersOfferActiveRegions;
|
|
}
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
|
|
void DestroySkiInventorySlotMouseRegions( )
|
|
{
|
|
for ( int i = 0; i<gDealersInventoryActiveRegions; ++i )
|
|
{
|
|
MSYS_RemoveRegion( &gDealersInventoryMouseRegions[ i ] );
|
|
|
|
//if the dealer repairs
|
|
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
MSYS_RemoveRegion( &gRepairmanInventorySmallFaceMouseRegions[ i ] );
|
|
}
|
|
}
|
|
|
|
gDealersInventoryActiveRegions = 0;
|
|
|
|
for ( int i = 0; i<gDealersOfferActiveRegions; ++i )
|
|
{
|
|
MSYS_RemoveRegion( &gDealersOfferSlotsMouseRegions[ i ] );
|
|
|
|
//if the dealer repairs
|
|
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
MSYS_RemoveRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ i ] );
|
|
}
|
|
}
|
|
|
|
gDealersOfferActiveRegions = 0;
|
|
|
|
for ( int i = 0; i<gPlayersOfferActiveRegions; ++i )
|
|
{
|
|
MSYS_RemoveRegion( &gPlayersOfferSlotsMouseRegions[i] );
|
|
|
|
MSYS_RemoveRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[i] );
|
|
}
|
|
|
|
gPlayersOfferActiveRegions = 0;
|
|
}
|
|
|
|
//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)
|
|
{
|
|
UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 );
|
|
INT16 ubLocation;
|
|
|
|
if( gpTempDealersInventory.empty() == true )
|
|
return;
|
|
|
|
ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
|
|
|
|
//if the selected slot is above any inventory we have, return
|
|
if( ubSelectedInvSlot >= gpTempDealersInventory.size() )
|
|
return;
|
|
|
|
//if there are any items still there
|
|
if( gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.exists() == true )
|
|
{
|
|
//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 ] )
|
|
{
|
|
DeleteObj(&gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject);
|
|
}
|
|
else
|
|
{
|
|
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.RemoveObjectsFromStack(1);
|
|
}
|
|
|
|
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 and Increase the number in dealer's offer area
|
|
ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ForceAddObjectsToStack(
|
|
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject, ubNumToMove);
|
|
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
|
}
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
|
|
{
|
|
UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if( gpTempDealersInventory.empty() == true )
|
|
return;
|
|
|
|
ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
|
|
|
|
//if the selected slot is above any inventory we have, return
|
|
if( ubSelectedInvSlot >= gpTempDealersInventory.size() )
|
|
return;
|
|
|
|
if(gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.exists() == false)
|
|
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.exists() == true )
|
|
{
|
|
//Decrease the number in the dealer offer area
|
|
ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.MoveThisObjectTo(gTempObject, 1);
|
|
|
|
//Increase the number in the dealer inventory
|
|
gpTempDealersInventory[ ubSelectedInvSlot ].ItemObject.AddObjectsToStack(gTempObject);
|
|
|
|
//if there is nothing left in the arms dealer offer area
|
|
if( ArmsDealerOfferArea[ gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.exists() == false )
|
|
{
|
|
RemoveItemFromArmsDealerOfferArea( gpTempDealersInventory[ ubSelectedInvSlot ].bSlotIdInOtherLocation, FALSE );
|
|
}
|
|
|
|
//redraw the screen
|
|
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SelectDealersInventoryMovementRegionCallBack(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 );
|
|
ubSelectedInvSlot += gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
|
|
|
|
if( gpTempDealersInventory.empty() == true )
|
|
return;
|
|
|
|
if( ubSelectedInvSlot >= gpTempDealersInventory.size() )
|
|
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 )
|
|
{
|
|
UINT16 ubSelectedInvSlot = 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 )
|
|
{
|
|
UINT16 ubSelectedInvSlot = 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 )
|
|
{
|
|
UINT16 ubSelectedInvSlot = 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 );
|
|
|
|
TempSlot = ArmsDealerOfferArea[ ubSelectedInvSlot ];
|
|
ArmsDealerOfferArea[ ubSelectedInvSlot ] = gMoveingItem;
|
|
gMoveingItem = TempSlot;
|
|
|
|
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
|
|
gpTempDealersInventory[ ArmsDealerOfferArea[ ubSelectedInvSlot ].bSlotIdInOtherLocation ].ItemObject.ForceAddObjectsToStack(ArmsDealerOfferArea[ ubSelectedInvSlot ].ItemObject, 1);
|
|
}
|
|
|
|
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 )
|
|
{
|
|
UINT16 ubSelectedInvSlot = MSYS_GetRegionUserData( pRegion, 0 );
|
|
INT16 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 );
|
|
|
|
TempSlot = PlayersOfferArea[ ubSelectedInvSlot ];
|
|
PlayersOfferArea[ ubSelectedInvSlot ] = gMoveingItem;
|
|
gMoveingItem = TempSlot;
|
|
|
|
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 && !( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
|
{
|
|
//Since money is always evaluated
|
|
PlayersOfferArea[ ubSelectedInvSlot ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
|
|
PlayersOfferArea[ ubSelectedInvSlot ].uiItemPrice = PlayersOfferArea[ ubSelectedInvSlot ].ItemObject[0]->data.money.uiMoneyAmount;
|
|
}
|
|
}
|
|
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 )
|
|
{
|
|
gusIDOfCivTrader = NOBODY;
|
|
|
|
//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 );
|
|
}
|
|
|
|
// Flugente: set up shopkeeper with a non-NPC
|
|
void EnterShopKeeperInterfaceScreen_NonNPC( INT8 ubArmsDealerID, UINT8 aMercID )
|
|
{
|
|
gusIDOfCivTrader = aMercID;
|
|
|
|
//Get Dealer ID from from merc Id
|
|
gbSelectedArmsDealerID = ubArmsDealerID;
|
|
|
|
if ( gbSelectedArmsDealerID <= -1 )
|
|
{
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( FONT_MCOLOR_WHITE, MSG_BETAVERSION, L"Failed to find Arms Dealer ID From Merc ID #%d", ubArmsDealerID );
|
|
#endif
|
|
gfSKIScreenExit = TRUE;
|
|
}
|
|
|
|
// Flugente: additional dialogue
|
|
if ( gusSelectedSoldier != NOBODY )
|
|
AdditionalTacticalCharacterDialogue_CallsLua( MercPtrs[gusSelectedSoldier], ADE_MERCHANT_CHAT );
|
|
|
|
LeaveTacticalScreen( SHOPKEEPER_SCREEN );
|
|
}
|
|
|
|
void InitializeShopKeeper( BOOLEAN fResetPage )
|
|
{
|
|
// update time player last dealt with him
|
|
gArmsDealerStatus[ gbSelectedArmsDealerID ].uiTimePlayerLastInSKI = GetWorldTotalMin();
|
|
|
|
gpTempDealersInventory.clear();
|
|
|
|
HandlePossibleArmsDealerIntelRefresh(FALSE);
|
|
|
|
//Get the number of distinct items in the inventory
|
|
//Create the shopkeeper's temp inventory
|
|
DetermineArmsDealersSellingInventory( );
|
|
|
|
gSelectArmsDealerInfo.ubNumberOfPages = (UINT8)(gpTempDealersInventory.size( ) / (SKI_TRADER_INVENTORY_BOXES_PER_ROW * SKI_TRADER_INVENTORY_BOXES_PER_COL));
|
|
if( gpTempDealersInventory.size() % 15 != 0 )
|
|
gSelectArmsDealerInfo.ubNumberOfPages += 1;
|
|
|
|
//Should we reset the current inventory page being displayed
|
|
if( gpTempDealersInventory.empty() == true )
|
|
gSelectArmsDealerInfo.ubCurrentPage = 0;
|
|
else
|
|
{
|
|
if( fResetPage )
|
|
{
|
|
if( gpTempDealersInventory.empty() == true )
|
|
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( gpTempDealersInventory.empty() == false )
|
|
gSelectArmsDealerInfo.ubCurrentPage = 1;
|
|
}
|
|
|
|
//if there is no inventory
|
|
if( gpTempDealersInventory.empty() == true )
|
|
{
|
|
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_TRADER_INVENTORY_BOXES_PER_ROW * SKI_TRADER_INVENTORY_BOXES_PER_COL);
|
|
}
|
|
|
|
void DisplayArmsDealerCurrentInventoryPage( )
|
|
{
|
|
CHAR16 zTemp[32];
|
|
UINT16 uiFontHeight;
|
|
UINT16 usCnt=0;
|
|
UINT16 usPosX, usPosY;
|
|
int sItemCount=0;
|
|
BOOLEAN fDisplayHatchOnItem=FALSE;
|
|
|
|
usPosX = SKI_TRADER_INVENTORY_BOXES_BEGIN_X;
|
|
usPosY = SKI_TRADER_INVENTORY_BOXES_BEGIN_Y;
|
|
|
|
//if there is any inventory
|
|
if( gpTempDealersInventory.empty() == false )
|
|
{
|
|
if( gubSkiDirtyLevel != SKI_DIRTY_LEVEL0 )
|
|
{
|
|
//Calculate the item that is at the top of the list
|
|
CalculateFirstItemIndexOnPage( );
|
|
|
|
//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<gpTempDealersInventory.size( )) && (sItemCount < gDealersInventoryActiveRegions)); ++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.exists() == false )
|
|
{
|
|
fDisplayHatchOnItem = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fDisplayHatchOnItem = FALSE;
|
|
}
|
|
}
|
|
|
|
// Display the inventory slot
|
|
DisplayInvSlot( 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_TRADER_INVENTORY_BOXES_PER_ROW) )
|
|
{
|
|
usPosX = SKI_TRADER_INVENTORY_BOXES_BEGIN_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 < gDealersInventoryActiveRegions )
|
|
{
|
|
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_TRADER_INVENTORY_BOXES_PER_ROW) )
|
|
{
|
|
usPosX = SKI_TRADER_INVENTORY_BOXES_BEGIN_X;
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT32 DisplayInvSlot( UINT16 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;
|
|
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 );
|
|
|
|
//Display the item graphic, and price
|
|
pItem = &Item[ usItemIndex ];
|
|
GetVideoObject( &hVObject, GetInterfaceGraphicForItem( pItem ) );
|
|
UINT16 usGraphicNum = g_bUsePngItemImages ? 0 : pItem->ubGraphicNum;
|
|
pTrav = &(hVObject->pETRLEObject[ usGraphicNum ] );
|
|
|
|
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;
|
|
|
|
//blt the shadow of the item
|
|
if(gGameSettings.fOptions[ TOPTION_SHOW_ITEM_SHADOW ]) BltVideoObjectOutlineShadowFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), g_bUsePngItemImages ? 0 : pItem->ubGraphicNum, sCenX-2, sCenY+2);
|
|
|
|
//blt the item
|
|
BltVideoObjectOutlineFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), g_bUsePngItemImages ? 0 : pItem->ubGraphicNum, sCenX, sCenY, Get16BPPColor( FROMRGB( 255, 255, 255 ) ), fHighlighted );
|
|
|
|
#ifdef ENCYCLOPEDIA_WORKS
|
|
//Moa: encyclopedia item visibility
|
|
EncyclopediaSetItemAsVisible( usItemIndex, ENC_ITEM_DISCOVERED_INSPECTABLE );
|
|
#endif
|
|
|
|
//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->exists() == false )
|
|
{
|
|
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
|
|
{
|
|
//display the length of time needed to repair the item
|
|
uiItemCost = 0;
|
|
|
|
//Get the length of time needed to fix the item
|
|
BuildDoneWhenTimeString( zTemp, gbSelectedArmsDealerID, &(gpTempDealersInventory[ ubSlotNum ]) );
|
|
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 );
|
|
|
|
CHAR16 zTemp2[64];
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
swprintf( zTemp2, L"%s Intel", zTemp );
|
|
else
|
|
swprintf( zTemp2, L"$%s", zTemp );
|
|
|
|
DrawTextToScreen( zTemp2, (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 ) ||
|
|
( ( pItemObject->ubNumberOfObjects == 1 ) &&
|
|
( 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 );
|
|
}
|
|
|
|
// CHRISL: if item is LBENODE
|
|
else if( (UsingNewInventorySystem() == true) && pItemObject->HasAnyActiveLBEs() == true)
|
|
{
|
|
//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_BLUE, FONT_MCOLOR_BLACK, FALSE, LEFT_JUSTIFIED );
|
|
}
|
|
|
|
// Display 'JAMMED' if it's jammed
|
|
if ( (*pItemObject)[0]->data.gun.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( )
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("DEF: DetermineArmsDealersSellingInventory") );
|
|
|
|
//allocate memory to hold the inventory in memory
|
|
gpTempDealersInventory.clear();
|
|
guiNextFreeInvSlot = 0;
|
|
|
|
//loop through the dealer's permanent inventory items, adding them all to the temp inventory list
|
|
for (DealerItemList::iterator iter = gArmsDealersInventory[ gbSelectedArmsDealerID ].begin();
|
|
iter != gArmsDealersInventory[ gbSelectedArmsDealerID ].end();) {
|
|
|
|
if ( iter->ItemIsInInventory() == false) {
|
|
++iter;
|
|
continue;
|
|
}
|
|
|
|
bool increment = true;
|
|
if (ItemIsSpecial(*iter) == false) {
|
|
StoreObjectsInNextFreeDealerInvSlot( &(*iter), gpTempDealersInventory, gbSelectedArmsDealerID );
|
|
}
|
|
else
|
|
{
|
|
//if the object has attachments, or is damaged, or otherwise special, then it is not stacked
|
|
bool fAddSpecialItem = true;
|
|
bool underRepair = false;
|
|
bool repaired = false;
|
|
|
|
if( iter->IsUnderRepair() == true )
|
|
{
|
|
underRepair = true;
|
|
//if the repairs are done
|
|
if( iter->uiRepairDoneTime <= GetWorldTotalMin() )
|
|
{
|
|
if (RepairIsDone( &(*iter) ))
|
|
{
|
|
//ADB moved from RepairIsDone so iterator remains ok
|
|
// Remove the repaired item from the dealer's permanent inventory list
|
|
iter = gArmsDealersInventory[ gbSelectedArmsDealerID ].erase(iter);
|
|
if (iter == gArmsDealersInventory[ gbSelectedArmsDealerID ].end()) {
|
|
break;
|
|
}
|
|
increment = false;
|
|
|
|
// don't add it here, it was put in the player's area
|
|
fAddSpecialItem = false;
|
|
}
|
|
else
|
|
{
|
|
repaired = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fAddSpecialItem == true )
|
|
{
|
|
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 = iter->ubOwnerProfileId;
|
|
}
|
|
|
|
StoreObjectsInNextFreeDealerInvSlot( &(*iter), gpTempDealersInventory, ubOwner );
|
|
if (underRepair == true) {
|
|
if (repaired == true) {
|
|
gpTempDealersInventory.back().uiFlags |= ARMS_INV_ITEM_REPAIRED;
|
|
}
|
|
else {
|
|
gpTempDealersInventory.back().uiFlags |= ARMS_INV_ITEM_NOT_REPAIRED_YET;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (increment == true) {
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
// repairmen sort differently from merchants
|
|
// sort this list by object category, and by ascending price within each category
|
|
if ( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
std::sort(gpTempDealersInventory.begin(), gpTempDealersInventory.end(), RepairmanItemQsortCompare);//RepairmanItemQsortCompare
|
|
}
|
|
else
|
|
{
|
|
std::sort(gpTempDealersInventory.begin(), gpTempDealersInventory.end(), ArmsDealerItemQsortCompare);//ArmsDealerItemQsortCompare
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
bool ArmsDealerItemQsortCompare(INVENTORY_IN_SLOT& pInvSlot1, INVENTORY_IN_SLOT& pInvSlot2)
|
|
{
|
|
int retVal = ( CompareItemsForSorting( pInvSlot1.sItemIndex, pInvSlot2.sItemIndex,
|
|
pInvSlot1.ItemObject[0]->data.objectStatus, pInvSlot2.ItemObject[0]->data.objectStatus ) );
|
|
if (retVal == -1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool RepairmanItemQsortCompare(INVENTORY_IN_SLOT& pInvSlot1, INVENTORY_IN_SLOT& pInvSlot2)
|
|
{
|
|
// lower repair time first
|
|
if ( pInvSlot1.uiRepairDoneTime < pInvSlot2.uiRepairDoneTime )
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void StoreObjectsInNextFreeDealerInvSlot( DEALER_SPECIAL_ITEM *pSpclItemInfo, std::vector<INVENTORY_IN_SLOT>& pInventory, UINT8 ubOwner )
|
|
{
|
|
pInventory.push_back(INVENTORY_IN_SLOT());
|
|
INVENTORY_IN_SLOT* pDealerInvSlot = &(pInventory.back());
|
|
pDealerInvSlot->fActive = TRUE;
|
|
pDealerInvSlot->sItemIndex = pSpclItemInfo->object.usItem;
|
|
pDealerInvSlot->uiRepairDoneTime = pSpclItemInfo->uiRepairDoneTime;
|
|
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( pSpclItemInfo, &(pDealerInvSlot->ItemObject) );
|
|
|
|
//ADB no longer necessary
|
|
/*
|
|
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(DEALER_SPECIAL_ITEM* pSpecial)
|
|
{
|
|
|
|
// make a new shopkeeper invslot item out of it
|
|
INVENTORY_IN_SLOT RepairItem;
|
|
|
|
RepairItem.fActive = TRUE;
|
|
RepairItem.sItemIndex = pSpecial->object.usItem;
|
|
|
|
// set the owner of the item. Slot is always -1 of course.
|
|
RepairItem.ubIdOfMercWhoOwnsTheItem = pSpecial->ubOwnerProfileId;
|
|
RepairItem.bSlotIdInOtherLocation = -1;
|
|
|
|
// Create the item object
|
|
MakeObjectOutOfDealerItems( pSpecial, &RepairItem.ItemObject );
|
|
|
|
if ( CanDealerRepairItem( gbSelectedArmsDealerID, RepairItem.ItemObject.usItem ) )
|
|
{
|
|
// make its condition 100%
|
|
RepairItem.ItemObject[0]->data.objectStatus = 100;
|
|
|
|
// Flugente: shopkeepers will also restore an item's repair threshold
|
|
RepairItem.ItemObject[0]->data.sRepairThreshold = 100;
|
|
}
|
|
|
|
// max condition of all permanent attachments on it
|
|
for (attachmentList::iterator iter = RepairItem.ItemObject[0]->attachments.begin(); iter != RepairItem.ItemObject[0]->attachments.end(); ++iter) {
|
|
if ( CanDealerRepairItem( gbSelectedArmsDealerID, iter->usItem ) && iter->exists())
|
|
{
|
|
// fix it up
|
|
(*iter)[0]->data.objectStatus = 100;
|
|
|
|
// Flugente: shopkeepers will also restore an item's repair threshold and clean it
|
|
(*iter)[0]->data.sRepairThreshold = 100;
|
|
}
|
|
}
|
|
|
|
#ifdef JA2UB
|
|
//no UB
|
|
#else
|
|
// if the item is imprinted (by anyone, even player's mercs), and it's Fredo repairing it
|
|
if ( ( gbSelectedArmsDealerID == ARMS_DEALER_FREDO ) )
|
|
{
|
|
// then reset the imprinting!
|
|
RepairItem.ItemObject[0]->data.ubImprintID = NO_PROFILE;
|
|
}
|
|
#endif
|
|
//try to add the item to the players offer area
|
|
INT8 bSlotNum;
|
|
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;
|
|
// there was room to add it to player's area
|
|
return(TRUE);
|
|
}
|
|
|
|
void DrawHatchOnInventory( UINT32 uiSurface, UINT16 usPosX, UINT16 usPosY, UINT16 usWidth, UINT16 usHeight, UINT16 usColor )
|
|
{
|
|
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
|
|
};
|
|
// CHRISL:
|
|
ClipRect.iLeft = usPosX-1;
|
|
ClipRect.iRight = usPosX + usWidth-1;
|
|
ClipRect.iTop = usPosY;
|
|
ClipRect.iBottom = usPosY + usHeight;
|
|
|
|
pDestBuf = LockVideoSurface( uiSurface, &uiDestPitchBYTES );
|
|
if(usColor == 0){
|
|
Blt16BPPBufferPixelateRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, Pattern );
|
|
}
|
|
else{
|
|
Blt16BPPBufferPixelateRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, Pattern, usColor );
|
|
}
|
|
UnLockVideoSurface( uiSurface );
|
|
}
|
|
|
|
void DrawHatchOnInventory_MilitiaAccess( UINT32 uiSurface, UINT16 usPosX, UINT16 usPosY, UINT16 usWidth, UINT16 usHeight, UINT16 usColor )
|
|
{
|
|
UINT8 *pDestBuf;
|
|
UINT32 uiDestPitchBYTES;
|
|
SGPRect ClipRect;
|
|
static UINT8 Pattern[8][8] =
|
|
{
|
|
1,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,1,0,0,
|
|
0,0,1,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,1,
|
|
0,0,0,0,1,0,0,0,
|
|
0,1,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,1,0,
|
|
0,0,0,1,0,0,0,0
|
|
};
|
|
// CHRISL:
|
|
ClipRect.iLeft = usPosX-1;
|
|
ClipRect.iRight = usPosX + usWidth-1;
|
|
ClipRect.iTop = usPosY;
|
|
ClipRect.iBottom = usPosY + usHeight;
|
|
|
|
pDestBuf = LockVideoSurface( uiSurface, &uiDestPitchBYTES );
|
|
if(usColor == 0){
|
|
Blt16BPPBufferPixelateRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, Pattern );
|
|
}
|
|
else{
|
|
Blt16BPPBufferPixelateRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, Pattern, usColor );
|
|
}
|
|
UnLockVideoSurface( uiSurface );
|
|
}
|
|
|
|
UINT32 CalcShopKeeperItemPrice( BOOLEAN fDealerSelling, BOOLEAN fUnitPriceOnly, UINT16 usItemID, FLOAT dModifier, OBJECTTYPE *pItemObject )
|
|
{
|
|
UINT8 ubCnt;
|
|
UINT32 uiUnitPrice = 0;
|
|
UINT32 uiTotalPrice = 0;
|
|
// UINT32 uiDifFrom10 = 0;
|
|
#ifdef JA2UB
|
|
UINT8 ubItemsNotCounted = 0; //ja25 UB
|
|
#endif
|
|
std::vector<UINT32> uiItemPrice;
|
|
|
|
uiItemPrice.resize(pItemObject->ubNumberOfObjects);
|
|
|
|
for (ubCnt = 0; ubCnt < pItemObject->ubNumberOfObjects; ++ubCnt )
|
|
{
|
|
uiItemPrice[ubCnt] = 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
|
|
uiItemPrice[ubCnt] += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, usItemID, fDealerSelling ) *
|
|
ItemConditionModifier(usItemID, (*pItemObject)[ubCnt]->data.gun.bGunStatus) *
|
|
dModifier );
|
|
|
|
// if any ammo is loaded
|
|
if( (*pItemObject)[ubCnt]->data.gun.usGunAmmoItem != NONE)
|
|
{
|
|
// if it's regular ammo
|
|
if( Item[ (*pItemObject)[ubCnt]->data.gun.usGunAmmoItem ].usItemClass == IC_AMMO )
|
|
{
|
|
// add value of its remaining ammo
|
|
uiItemPrice[ubCnt] += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, (*pItemObject)[ubCnt]->data.gun.usGunAmmoItem, fDealerSelling ) *
|
|
ItemConditionModifier((*pItemObject)[ubCnt]->data.gun.usGunAmmoItem, (*pItemObject)[ubCnt]->data.gun.ubGunShotsLeft) *
|
|
dModifier );
|
|
}
|
|
else // assume it's attached ammo (mortar shells, grenades)
|
|
{
|
|
// add its value (uses normal status 0-100)
|
|
uiItemPrice[ubCnt] += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, (*pItemObject)[ubCnt]->data.gun.usGunAmmoItem, fDealerSelling ) *
|
|
ItemConditionModifier((*pItemObject)[ubCnt]->data.gun.usGunAmmoItem, (*pItemObject)[ubCnt]->data.gun.bGunAmmoStatus) *
|
|
dModifier );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IC_AMMO:
|
|
// add the value of each magazine (multiple mags may have vastly different #bullets left)
|
|
// for bullets, ItemConditionModifier will convert the #ShotsLeft into a percentage
|
|
uiItemPrice[ubCnt] += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, usItemID, fDealerSelling ) *
|
|
ItemConditionModifier(usItemID, (*pItemObject)[ubCnt]->data.ubShotsLeft) *
|
|
dModifier );
|
|
|
|
break;
|
|
default:
|
|
// add the value of each magazine (multiple mags may have vastly different #bullets left)
|
|
// for bullets, ItemConditionModifier will convert the #ShotsLeft into a percentage
|
|
uiItemPrice[ubCnt] += (UINT32)( CalcValueOfItemToDealer( gbSelectedArmsDealerID, usItemID, fDealerSelling ) *
|
|
ItemConditionModifier(usItemID, (*pItemObject)[ ubCnt ]->data.objectStatus) *
|
|
dModifier );
|
|
|
|
break;
|
|
}
|
|
// loop through any attachments and add in their price
|
|
for (attachmentList::iterator iter = (*pItemObject)[ubCnt]->attachments.begin(); iter != (*pItemObject)[ubCnt]->attachments.end(); ++iter) {
|
|
// add value of this particular attachment
|
|
if(iter->exists())
|
|
uiItemPrice[ubCnt] += CalcShopKeeperItemPrice( fDealerSelling, fUnitPriceOnly, iter->usItem, dModifier, &(*iter)) ;
|
|
}
|
|
|
|
// Flugente: used in backgrounds now, old code in comments for historical reasons
|
|
/*// 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 = ( uiItemPrice[ubCnt] * FLO_DISCOUNT_PERCENTAGE ) / 100;
|
|
|
|
// she gets a discount! Read her M.E.R.C. profile to understand why
|
|
if ( fDealerSelling )
|
|
{
|
|
// she buys for less...
|
|
uiItemPrice[ubCnt] -= uiDiscountValue;
|
|
}
|
|
else
|
|
{
|
|
// and sells for more!
|
|
uiItemPrice[ubCnt] += uiDiscountValue;
|
|
}
|
|
break;
|
|
}
|
|
}*/
|
|
|
|
// Flugente: backgrounds can alter prices
|
|
INT16 pricepercentage = 100;
|
|
|
|
// if it's a GUN or AMMO (but not Launchers, and all attachments and payload is included)
|
|
if ( Item [ usItemID ].usItemClass & (IC_GUN|IC_AMMO) )
|
|
{
|
|
pricepercentage = max( 0, 100 + (fDealerSelling ? -1 : 1) * gpSMCurrentMerc->GetBackgroundValue( BG_PERC_PRICES_GUNS ) );
|
|
|
|
// Even without backgrounds, Flo gets a discount. Read her M.E.R.C. profile to understand why
|
|
if ( !gGameOptions.fBackGround && gpSMCurrentMerc->ubProfile == FLO )
|
|
pricepercentage = max( 0, 100 + (fDealerSelling ? -1 : 1) * FLO_DISCOUNT_PERCENTAGE );
|
|
}
|
|
else if ( Item [ usItemID ].usItemClass & (IC_MAPFILTER_MELEE|IC_MAPFILTER_KIT|IC_MAPFILTER_LBE|IC_MAPFILTER_ARMOR|IC_MAPFILTER_MISC) )
|
|
{
|
|
pricepercentage = max( 0, 100 + (fDealerSelling ? -1 : 1) * gpSMCurrentMerc->GetBackgroundValue( BG_PERC_PRICES ) );
|
|
}
|
|
|
|
uiItemPrice[ubCnt] = (uiItemPrice[ubCnt] * pricepercentage) / 100;
|
|
|
|
// 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 && ( uiItemPrice[ubCnt] == 0 ) )
|
|
{
|
|
uiItemPrice[ubCnt] = 1;
|
|
}
|
|
|
|
/*
|
|
//if the price is not diviseble by 10, make it so
|
|
uiDifFrom10 = 10 - uiItemPrice[ubCnt] % 10;
|
|
if( uiDifFrom10 != 0 && uiDifFrom10 != 10 )
|
|
{
|
|
uiItemPrice[ubCnt] += uiDifFrom10;
|
|
}
|
|
*/
|
|
}
|
|
|
|
// if we want the unit price, find the highest price in the stack
|
|
for (ubCnt = 0; ubCnt < pItemObject->ubNumberOfObjects; ++ubCnt )
|
|
{
|
|
if(fUnitPriceOnly == TRUE)
|
|
{
|
|
uiUnitPrice = __max(uiUnitPrice, uiItemPrice[ubCnt]);
|
|
}
|
|
else
|
|
{
|
|
uiUnitPrice += uiItemPrice[ubCnt];
|
|
}
|
|
}
|
|
|
|
// we're always count the first one
|
|
uiTotalPrice = uiUnitPrice;
|
|
|
|
#ifdef JA2UB
|
|
//---------------------------JA25 UB---------------
|
|
// if NOT pricing just one
|
|
if ( !fUnitPriceOnly )
|
|
{
|
|
// add value of all that weren't already counted
|
|
uiTotalPrice += ( ubItemsNotCounted * uiUnitPrice );
|
|
}
|
|
|
|
//if the dealer is Raul
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_RAUL )
|
|
{
|
|
//if the item is the antique musket
|
|
if( usItemID == HAND_CANNON ) //4498
|
|
{
|
|
//if the "Find anitque musket" quest is active
|
|
if( gubQuest[ QUEST_FIND_ANTIQUE_MUSKET_FOR_RAUL ] == QUESTINPROGRESS )
|
|
{
|
|
//the price should be.... nothin ( reward for the quest )
|
|
uiTotalPrice = 1;
|
|
|
|
//if the player hasnt said the quote before
|
|
if( !( gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags & ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_48 ) )
|
|
{
|
|
StartShopKeeperTalking( SK_QUOTES_NPC_SPECIFIC_48 );
|
|
gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags |= ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_48;
|
|
gfCanSayMakeTransactionQuote = FALSE;
|
|
}
|
|
|
|
//else if
|
|
if( gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags & ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_49 )
|
|
{
|
|
//if the player hasnt said it before
|
|
if( !( gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags & ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_50 ) )
|
|
{
|
|
StartShopKeeperTalking( SK_QUOTES_NPC_SPECIFIC_50 );
|
|
gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags |= ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_50;
|
|
}
|
|
|
|
//the price should be
|
|
uiTotalPrice = 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
//if the item is the barrat
|
|
if( usItemID == BARRETT_UB )
|
|
{
|
|
//and if the player found the antique musket for Raul
|
|
if( IsJa25GeneralFlagSet( JA_GF__BARRETT_IS_HALF_PRICE ) )
|
|
{
|
|
//the barrett is half off
|
|
uiTotalPrice /= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
//JA25UB
|
|
//if the dealer is Raul
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_BETTY )
|
|
{
|
|
//if the item is the antique musket
|
|
if( usItemID == TEX_MOVIE_ATTACK_CLYDESDALES || usItemID == TEX_MOVIE_WILD_EAST || usItemID == TEX_MOVIE_HAVE_HONDA )
|
|
// if( usItemID == 1356 || usItemID == 1357 || usItemID == 1358 )
|
|
{
|
|
//Make the item price top be what is listed in the item table ( 20 )
|
|
uiTotalPrice = Item[ usItemID ].usPrice;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
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_TRADER_OFFER_BOXES_BEGIN_X;
|
|
usPosY = SKI_TRADER_OFFER_BOXES_BEGIN_Y;
|
|
|
|
sCount = 0;
|
|
|
|
//Display all the items that are in the Arms traders offered area
|
|
uiTotalCost = 0;
|
|
for ( sCnt = 0; sCnt<gDealersOfferActiveRegions; ++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( (UINT16)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_TRADER_OFFER_BOXES_PER_ROW) )
|
|
{
|
|
usPosX = SKI_TRADER_OFFER_BOXES_BEGIN_X;
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
|
|
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
|
|
{
|
|
//Display the total cost text
|
|
swprintf( zTemp, L"%d", uiTotalCost );
|
|
InsertCommasForDollarFigure( zTemp );
|
|
|
|
CHAR16 zTemp2[64];
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
swprintf( zTemp2, L"%s Intel", zTemp );
|
|
else
|
|
swprintf( zTemp2, L"$%s", zTemp );
|
|
|
|
DrawTextToScreen( zTemp2, 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 );
|
|
}
|
|
}
|
|
|
|
INT16 AddItemToArmsDealerOfferArea( INVENTORY_IN_SLOT* pInvSlot, INT16 bSlotIdInOtherLocation )
|
|
{
|
|
for ( INT16 bCnt = 0; bCnt<gDealersOfferActiveRegions; ++bCnt )
|
|
{
|
|
//if there are no items here, copy the data in
|
|
if( ArmsDealerOfferArea[bCnt].fActive == FALSE )
|
|
{
|
|
//Copy the inventory items
|
|
ArmsDealerOfferArea[bCnt] = *pInvSlot;
|
|
|
|
//if the shift key is being pressed, add them all
|
|
if( gfKeyState[ SHIFT ] ) {
|
|
//nothing needed
|
|
}
|
|
//If there was more then 1 item, reduce it to only 1 item moved
|
|
else if( pInvSlot->ItemObject.ubNumberOfObjects > 1 ) {
|
|
ArmsDealerOfferArea[bCnt].ItemObject.RemoveObjectsFromStack(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( INT16 bSlotId, BOOLEAN fKeepItem )
|
|
{
|
|
//if this is the requested slot
|
|
if( ArmsDealerOfferArea[bSlotId].fActive )
|
|
{
|
|
if( fKeepItem )
|
|
{
|
|
gpTempDealersInventory[ ArmsDealerOfferArea[bSlotId].bSlotIdInOtherLocation ].ItemObject.ForceAddObjectsToStack(ArmsDealerOfferArea[ bSlotId ].ItemObject);
|
|
}
|
|
|
|
//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, INT16 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<gPlayersOfferActiveRegions; ++bCnt )
|
|
{
|
|
//if there are no items here, copy the data in
|
|
if( PlayersOfferArea[bCnt].fActive == FALSE )
|
|
{
|
|
PlayersOfferArea[bCnt] = *pInvSlot;
|
|
|
|
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 && !( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
|
{
|
|
//Since money is always evaluated
|
|
PlayersOfferArea[ bCnt ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
|
|
PlayersOfferArea[ bCnt ].uiItemPrice = PlayersOfferArea[ bCnt ].ItemObject[0]->data.money.uiMoneyAmount;
|
|
}
|
|
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
|
|
|
return( bCnt );
|
|
}
|
|
}
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
BOOLEAN RemoveItemFromPlayersOfferArea( INT16 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 sCount = 0;
|
|
CHAR16 zTemp[32];
|
|
UINT32 uiTotalCost;
|
|
UINT16 usPosX, usPosY;
|
|
BOOLEAN fDisplayHatchOnItem=FALSE;
|
|
HVOBJECT hHandle;
|
|
|
|
// load the "cross out" graphic
|
|
GetVideoObject( &hHandle, guiItemCrossOut );
|
|
|
|
usPosX = SKI_PLAYER_OFFER_BOXES_BEGIN_X;
|
|
usPosY = SKI_PLAYER_OFFER_BOXES_BEGIN_Y;
|
|
|
|
//Display all the items that are in the Players offered area
|
|
uiTotalCost = 0;
|
|
for ( int sCnt = 0; sCnt < gPlayersOfferActiveRegions; ++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[0]->data.money.uiMoneyAmount = Menptr[ sSoldierID ].inv[ PlayersOfferArea[ sCnt ].bSlotIdInOtherLocation ][0]->data.money.uiMoneyAmount;
|
|
PlayersOfferArea[ sCnt ].uiItemPrice = PlayersOfferArea[ sCnt ].ItemObject[0]->data.money.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 ] ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Display the inventory slot
|
|
DisplayInvSlot( (UINT16)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;
|
|
|
|
// cross out unwanted items
|
|
if ( !(PlayersOfferArea[sCnt].uiFlags & ARMS_INV_JUST_PURCHASED) )
|
|
{
|
|
//If item can't be sold here, or it's completely worthless (very cheap / very broken)
|
|
if ( (WillShopKeeperRejectObjectsFromPlayer( gbSelectedArmsDealerID, sCnt ) == TRUE) || !(PlayersOfferArea[sCnt].uiFlags & ARMS_INV_PLAYERS_ITEM_HAS_VALUE) )
|
|
{
|
|
BltVideoObject( FRAME_BUFFER, hHandle, 0, (usPosX + 22), (usPosY), VO_BLT_SRCTRANSPARENCY, NULL );
|
|
|
|
// invalidate the region
|
|
InvalidateRegion( usPosX - 1, usPosY - 1, usPosX + SKI_INV_SLOT_WIDTH + 1, usPosY + SKI_INV_SLOT_HEIGHT + 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
usPosX += SKI_INV_OFFSET_X;
|
|
|
|
++sCount;
|
|
|
|
//if we are on to the next row
|
|
if ( !(sCount % SKI_TRADER_OFFER_BOXES_PER_ROW) )
|
|
{
|
|
usPosX = SKI_PLAYER_OFFER_BOXES_BEGIN_X;
|
|
usPosY += SKI_INV_OFFSET_Y;
|
|
}
|
|
}
|
|
|
|
if( gubSkiDirtyLevel == SKI_DIRTY_LEVEL2 )
|
|
{
|
|
//Display the total cost text
|
|
swprintf( zTemp, L"%d", uiTotalCost );
|
|
InsertCommasForDollarFigure( zTemp );
|
|
|
|
CHAR16 zTemp2[64];
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
swprintf( zTemp2, L"%s Intel", zTemp );
|
|
else
|
|
swprintf( zTemp2, L"$%s", zTemp );
|
|
|
|
DrawTextToScreen( zTemp2, SKI_TOTAL_VALUE_X, SKI_TOTAL_VALUE_OFFSET_TO_VALUE, SKI_INV_SLOT_WIDTH, SKI_LABEL_FONT, SKI_ITEM_PRICE_COLOR, FONT_MCOLOR_BLACK, FALSE, CENTER_JUSTIFIED );
|
|
}
|
|
}
|
|
|
|
INVENTORY_IN_SLOT *GetPtrToOfferSlotWhereThisItemIs( UINT8 ubProfileID, INT16 bInvPocket )
|
|
{
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
if( ( PlayersOfferArea[ ubCnt ].bSlotIdInOtherLocation == bInvPocket ) &&
|
|
( PlayersOfferArea[ ubCnt ].ubIdOfMercWhoOwnsTheItem == ubProfileID ) &&
|
|
( PlayersOfferArea[ ubCnt ].ItemObject.exists() == true ) )
|
|
{
|
|
return( &( PlayersOfferArea[ ubCnt ] ) );
|
|
}
|
|
}
|
|
|
|
for ( int ubCnt = 0; ubCnt < gDealersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
if ( (ArmsDealerOfferArea[ubCnt].bSlotIdInOtherLocation == bInvPocket) &&
|
|
(ArmsDealerOfferArea[ubCnt].ubIdOfMercWhoOwnsTheItem == ubProfileID) &&
|
|
(ArmsDealerOfferArea[ubCnt].ItemObject.exists( ) == true) )
|
|
{
|
|
return(&(ArmsDealerOfferArea[ubCnt]));
|
|
}
|
|
}
|
|
|
|
// not found (perfectly valid result)
|
|
return( NULL );
|
|
}
|
|
|
|
BOOLEAN ShouldSoldierDisplayHatchOnItem( UINT8 ubProfileID, INT16 sSlotNum )
|
|
{
|
|
INVENTORY_IN_SLOT *pInvSlot = GetPtrToOfferSlotWhereThisItemIs( ubProfileID, sSlotNum );
|
|
|
|
if( pInvSlot == NULL )
|
|
// not found in either offer area
|
|
return( FALSE );
|
|
|
|
// found it, display it hatched out
|
|
return( TRUE );
|
|
}
|
|
|
|
UINT32 CalculateTotalArmsDealerCost()
|
|
{
|
|
UINT32 uiTotal=0;
|
|
|
|
for ( int uiCnt = 0; uiCnt< gDealersOfferActiveRegions; ++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()
|
|
{
|
|
// we can't substitute money for intel
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
return 0;
|
|
|
|
UINT32 uiTotal = 0;
|
|
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++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[0]->data.money.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 = (gPlayersOfferActiveRegions - 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 )
|
|
{
|
|
INT32 balance = LaptopSaveInfo.iCurrentBalance;
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
balance = GetIntel();
|
|
|
|
//if the player doesn't have enough money in his account to pay the rest
|
|
if( uiArmsDealersItemsCost > uiPlayersTotalMoneyValue + balance )
|
|
{
|
|
// 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 - ( balance + 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 ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
{
|
|
if ( uiPlayersTotalMoneyValue )
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 8, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
|
else
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_SHOPKEEPER, 9, ( uiArmsDealersItemsCost - uiPlayersTotalMoneyValue ), 0, giShopKeeperFaceIndex, DIALOGUE_SHOPKEEPER_UI );
|
|
}
|
|
else
|
|
{
|
|
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( );
|
|
#ifdef JA2UB
|
|
//JA25 UB
|
|
//if the arms dealer is Raul
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_RAUL )
|
|
{
|
|
//if this is the first time that the player purchased somehting form raul
|
|
if( gArmsDealerStatus[ gbSelectedArmsDealerID ].fHasSoldSomethingToPlayer == FALSE )
|
|
{
|
|
//if RAUL doesnt have the BARRETT anymore ie the player already bought it
|
|
//if( gArmsDealersInventory[ ARMS_DEALER_PERKO ][ BARRETT ].ubTotalItems != 0 )
|
|
//{
|
|
if( gubQuest[ QUEST_FIND_ANTIQUE_MUSKET_FOR_RAUL ] == QUESTNOTSTARTED )
|
|
{
|
|
//Raul Start the quest and have Raul say somehitng
|
|
StartShopKeeperTalking( SK_QUOTES_NPC_SPECIFIC_46 );
|
|
StartShopKeeperTalking( SK_QUOTES_NPC_SPECIFIC_47 );
|
|
|
|
StartQuest( QUEST_FIND_ANTIQUE_MUSKET_FOR_RAUL, -1, -1 );
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//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 );
|
|
}
|
|
#ifdef JA2UB
|
|
//Bought from dealer specific stuff
|
|
|
|
//if the arms dealer is Betty, set fact 403
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_BETTY )
|
|
{
|
|
//if the player spent more the X
|
|
if( uiMoneyFromPlayersAccount >= SKI_BETTY_MINIMUM_AMOUNT_TO_SET_FACT )
|
|
{
|
|
//set the fact
|
|
SetFactTrue( FACT_PLAYER_PAID_BETTY_MORE_THEN_X_FOR_ITEM );
|
|
}
|
|
}
|
|
|
|
//if the arms dealer is Raul, set fact 407
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_RAUL )
|
|
{
|
|
//if the player spent more the X
|
|
if( uiMoneyFromPlayersAccount >= SKI_RAUL_MINIMUM_AMOUNT_TO_SET_FACT )
|
|
{
|
|
//set the fact
|
|
SetFactTrue( FACT_PLAYER_BOUGHT_SOMETHING_FROM_RAUL );
|
|
}
|
|
}
|
|
|
|
//Remeber the fact that the player has sold somehting to the player
|
|
gArmsDealerStatus[ gbSelectedArmsDealerID ].fHasSoldSomethingToPlayer = TRUE;
|
|
#endif
|
|
|
|
//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;
|
|
}
|
|
|
|
void MoveAllArmsDealersItemsInOfferAreaToPlayersOfferArea( )
|
|
{
|
|
//for all items in the dealers items offer area
|
|
INT16 bSlotID=0;
|
|
#ifdef JA2UB
|
|
BOOLEAN fAddItemToPlayer=TRUE;
|
|
#endif
|
|
//loop through all the slots in the shopkeeper's offer area
|
|
for ( int uiCnt = 0; uiCnt<gDealersOfferActiveRegions; ++uiCnt )
|
|
{
|
|
//if there is an item here
|
|
if( ArmsDealerOfferArea[ uiCnt ].fActive )
|
|
{
|
|
#ifdef JA2UB
|
|
//JA25 UB
|
|
fAddItemToPlayer = TRUE;
|
|
|
|
//if the dealer is betty
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_BETTY )
|
|
{
|
|
//if the item is the laptop transmitter
|
|
if( ArmsDealerOfferArea[ uiCnt ].sItemIndex == LAPTOP_TRANSMITTER ) //4500
|
|
{
|
|
//Dont transfer the item
|
|
fAddItemToPlayer = FALSE;
|
|
|
|
//Tell the user we are going to attach the transmitter to the laptop
|
|
//( need to wait 1 frame caus ewe are currently in a msg box )
|
|
gubDisplayMsgBoxAskingUserToAttachTransmitter = TRNSMTR_MSG_BOX__1_FRAME_WAIT;
|
|
}
|
|
|
|
//if the item is the porno mag
|
|
if( ArmsDealerOfferArea[ uiCnt ].sItemIndex == PORNOS )
|
|
{
|
|
StartShopKeeperTalking( SK_QUOTES_WHEN_PLAYER_BUYS_PORNO );
|
|
}
|
|
|
|
//if the item is Tex's videos
|
|
if( ArmsDealerOfferArea[ uiCnt ].sItemIndex == TEX_MOVIE_ATTACK_CLYDESDALES ||//1356 ||
|
|
ArmsDealerOfferArea[ uiCnt ].sItemIndex == TEX_MOVIE_WILD_EAST ||//1357 ||
|
|
ArmsDealerOfferArea[ uiCnt ].sItemIndex == TEX_MOVIE_HAVE_HONDA )//1358 )
|
|
{
|
|
SetFactTrue( FACT_PLAYER_BOUGHT_A_TEX_VIDEO_FROM_BETTY );
|
|
}
|
|
}
|
|
|
|
if( fAddItemToPlayer ) //JA25 UB
|
|
{
|
|
#endif
|
|
bSlotID = AddItemToPlayersOfferArea( NO_PROFILE, &ArmsDealerOfferArea[ uiCnt ], -1 );
|
|
|
|
if( bSlotID != -1 )
|
|
{
|
|
PlayersOfferArea[ bSlotID ].uiFlags |= ARMS_INV_JUST_PURCHASED;
|
|
|
|
#ifdef JA2UB
|
|
|
|
//if the player has just purchased the BArrett form Raul
|
|
if( ( gbSelectedArmsDealerID == ARMS_DEALER_RAUL ) && ( ArmsDealerOfferArea[ uiCnt ].sItemIndex == BARRETT_UB ) )
|
|
{
|
|
// set a special flag
|
|
gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags |= ARMS_DEALER_FLAG__RAUL_HAS_SOLD_BARRETT_TO_PLAYER;
|
|
}
|
|
|
|
#endif
|
|
//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;
|
|
}
|
|
}
|
|
#ifdef JA2UB
|
|
}
|
|
#endif
|
|
|
|
//Remove the items out of the dealers inventory
|
|
RemoveItemFromDealersInventory( &ArmsDealerOfferArea[ uiCnt ], (UINT16)ArmsDealerOfferArea[ uiCnt ].bSlotIdInOtherLocation );
|
|
|
|
//Remove the items from the Shopkeepers Offer area
|
|
if( !RemoveItemFromArmsDealerOfferArea( (UINT16)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 ( int uiCnt = 0; uiCnt < gDealersOfferActiveRegions; ++uiCnt )
|
|
{
|
|
if( ArmsDealerOfferArea[uiCnt].fActive )
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
BOOLEAN RemoveItemFromDealersInventory( INVENTORY_IN_SLOT* pInvSlot, UINT16 ubSlot )
|
|
{
|
|
//Remove all of this item out of the specified inventory slot
|
|
RemoveItemFromArmsDealerInventory( gbSelectedArmsDealerID, gpTempDealersInventory[ubSlot].sItemIndex, pInvSlot->ItemObject.ubNumberOfObjects, &pInvSlot->ItemObject );
|
|
|
|
gfResetShopKeepIdleQuote = TRUE;
|
|
return( TRUE );
|
|
}
|
|
|
|
void MovePlayerOfferedItemsOfValueToArmsDealersInventory()
|
|
{
|
|
#ifdef JA2UB
|
|
BOOLEAN fAddItemToDealer=TRUE;
|
|
#endif
|
|
//loop through all the slots in the players offer area
|
|
for ( int uiCnt = 0; uiCnt < gPlayersOfferActiveRegions; ++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[0]->data.money.uiMoneyAmount;
|
|
}
|
|
#ifdef JA2UB
|
|
else
|
|
{
|
|
fAddItemToDealer = TRUE;
|
|
|
|
//if the dealer is raul
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_RAUL )
|
|
{
|
|
//if the item is the cannon balls
|
|
if( PlayersOfferArea[ uiCnt ].sItemIndex == CLIP_CANNON_BALL )// 4499 )
|
|
{
|
|
fAddItemToDealer = FALSE;
|
|
}
|
|
|
|
//if the item is the antique musket
|
|
if( PlayersOfferArea[ uiCnt ].sItemIndex == HAND_CANNON )// 4498 )
|
|
{
|
|
//Only do this if the player knew about the cannon offer
|
|
if( gubQuest[ QUEST_FIND_ANTIQUE_MUSKET_FOR_RAUL ] == QUESTINPROGRESS )
|
|
{
|
|
//Have raul say a quote
|
|
StartShopKeeperTalking( SK_QUOTES_NPC_SPECIFIC_51 );
|
|
|
|
//Trigger Rauls action #52
|
|
TriggerNPCRecord( RAUL_UB, 52 );
|
|
|
|
//Remeber to discount the barrett
|
|
SetJa25GeneralFlag( JA_GF__BARRETT_IS_HALF_PRICE );
|
|
}
|
|
|
|
//Mark the quest done
|
|
EndQuest( QUEST_FIND_ANTIQUE_MUSKET_FOR_RAUL, -1, -1 );
|
|
|
|
fAddItemToDealer = FALSE;
|
|
}
|
|
}
|
|
|
|
//if we ARE to transfer the item
|
|
if( fAddItemToDealer )
|
|
{
|
|
//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 ) );
|
|
PlayersOfferArea[ uiCnt ].ItemObject.initialize();
|
|
}
|
|
|
|
}
|
|
}
|
|
#else
|
|
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 ) );
|
|
PlayersOfferArea[ uiCnt ].ItemObject.initialize();
|
|
}
|
|
}
|
|
#endif
|
|
//erase the item from the player's offer area
|
|
ClearPlayersOfferSlot( uiCnt );
|
|
}
|
|
}
|
|
}
|
|
|
|
gfResetShopKeepIdleQuote = TRUE;
|
|
}
|
|
|
|
void BeginSkiItemPointer( UINT8 ubSource, INT16 bSlotNum, BOOLEAN fOfferToDealerFirst )
|
|
{
|
|
SGPRect Rect;
|
|
|
|
/*
|
|
// 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.
|
|
gMoveingItem = ArmsDealerOfferArea[ bSlotNum ];
|
|
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;
|
|
if((UsingNewInventorySystem() == true)){
|
|
Rect.iBottom += 60;
|
|
}
|
|
|
|
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.
|
|
gMoveingItem = PlayersOfferArea[ bSlotNum ];
|
|
|
|
// 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!
|
|
PlayersOfferArea[ bSlotNum ].ItemObject.MoveThisObjectTo(gMoveingItem.ItemObject, 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;
|
|
if((UsingNewInventorySystem() == true)){
|
|
Rect.iBottom += 60;
|
|
}
|
|
|
|
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;
|
|
#ifdef JA2UB
|
|
//ja25 ub
|
|
//if the dealer is Raul
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_RAUL )
|
|
{
|
|
//if the item is the antique musket
|
|
if( gMoveingItem.ItemObject.usItem == HAND_CANNON ) //4498 )
|
|
{
|
|
if( gubQuest[ QUEST_FIND_ANTIQUE_MUSKET_FOR_RAUL ] == QUESTINPROGRESS )
|
|
{
|
|
//if the player hasnt said the quote before
|
|
if( !( gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags & ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_49 ) )
|
|
{
|
|
StartShopKeeperTalking( SK_QUOTES_NPC_SPECIFIC_49 );
|
|
gArmsDealerStatus[ gbSelectedArmsDealerID ].ubSpecificDealerFlags |= ARMS_DEALER_FLAG__RAUL_SAID_QUOTE_49;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
case PLAYERS_INVENTORY:
|
|
// better be a valid merc pocket index, or -1
|
|
Assert( ( bSlotNum >= -1 ) && ( bSlotNum < (INT8)gpSMCurrentMerc->inv.size() ) );
|
|
|
|
// if we're supposed to store the original pocket #, but that pocket still holds more of these
|
|
if ( ( bSlotNum != -1 ) && ( gpSMCurrentMerc->inv[ bSlotNum ].exists() == true ) )
|
|
{
|
|
// 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!
|
|
gTempObject = *gpItemPointer;
|
|
|
|
//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.
|
|
gMoveingItem.initialize();
|
|
|
|
//Get the item from the pointer
|
|
gMoveingItem.ItemObject = gTempObject;
|
|
|
|
gMoveingItem.fActive = TRUE;
|
|
gMoveingItem.sItemIndex = gTempObject.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;
|
|
if((UsingNewInventorySystem() == true)){
|
|
Rect.iBottom += 60;
|
|
}
|
|
|
|
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 = g_bUsePngItemImages ? 0 : 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 < gMoveingItem.ItemObject[0]->attachments.size(); ++ubCnt)
|
|
{
|
|
if( gItemDescAttachmentRegions[ubCnt].uiFlags & MSYS_REGION_EXISTS )
|
|
MSYS_ChangeRegionCursor( &gItemDescAttachmentRegions[ubCnt], usCursor );
|
|
}
|
|
|
|
for ( ubCnt = 0; ubCnt<gDealersOfferActiveRegions; ++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
|
|
{
|
|
gMoveingItem.initialize();
|
|
|
|
// 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<gDealersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
MSYS_ChangeRegionCursor( &gDealersOfferSlotsMouseRegions[ ubCnt ], usCursor );
|
|
|
|
//if the dealer repairs
|
|
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
MSYS_ChangeRegionCursor( &gDealersOfferSlotsSmallFaceMouseRegions[ ubCnt ], usCursor );
|
|
}
|
|
}
|
|
|
|
for ( ubCnt = 0; ubCnt<gPlayersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
MSYS_ChangeRegionCursor( &gPlayersOfferSlotsMouseRegions[ubCnt], usCursor );
|
|
MSYS_ChangeRegionCursor( &gPlayersOfferSlotsSmallFaceMouseRegions[ubCnt], usCursor );
|
|
}
|
|
|
|
//if the item desc window is up
|
|
if( gInvDesc.uiFlags & MSYS_REGION_EXISTS )
|
|
MSYS_ChangeRegionCursor( &gInvDesc, usCursor );
|
|
|
|
for( ubCnt = 0; ubCnt < gMoveingItem.ItemObject[0]->attachments.size(); ubCnt++)
|
|
{
|
|
if( gItemDescAttachmentRegions[ubCnt].uiFlags & MSYS_REGION_EXISTS )
|
|
MSYS_ChangeRegionCursor( &gItemDescAttachmentRegions[ubCnt], usCursor );
|
|
}
|
|
|
|
MSYS_ChangeRegionCursor( &gSkiInventoryMovementAreaMouseRegions, usCursor );
|
|
|
|
MSYS_SetCurrentCursor( usCursor );
|
|
|
|
SetCurrentCursorFromDatabase( usCursor );
|
|
|
|
FreeMouseCursor( TRUE );
|
|
|
|
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;
|
|
}
|
|
|
|
INT16 AddInventoryToSkiLocation( INVENTORY_IN_SLOT *pInv, UINT16 ubSpotLocation, UINT8 ubWhere )
|
|
{
|
|
INT16 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 )
|
|
{
|
|
ArmsDealerOfferArea[ ubSpotLocation ] = *pInv;
|
|
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
|
|
PlayersOfferArea[ ubSpotLocation ] = *pInv;
|
|
IfMercOwnedCopyItemToMercInv( pInv );
|
|
|
|
//if the item is money
|
|
if( Item[ PlayersOfferArea[ ubSpotLocation ].sItemIndex ].usItemClass == IC_MONEY && !(armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL) )
|
|
{
|
|
//Since money is always evaluated
|
|
PlayersOfferArea[ ubSpotLocation ].uiFlags |= ARMS_INV_PLAYERS_ITEM_HAS_VALUE;
|
|
PlayersOfferArea[ ubSpotLocation ].uiItemPrice = PlayersOfferArea[ ubSpotLocation ].ItemObject[0]->data.money.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
|
|
if ( giShopKeeperFaceIndex > -1 )
|
|
gFacesData[ giShopKeeperFaceIndex ].fDisabled = FALSE;
|
|
|
|
HandleDialogue();
|
|
|
|
//Gets handled when we render the tactical interface
|
|
HandleAutoFaces( );
|
|
|
|
HandleTalkingAutoFaces( );
|
|
HandleShopKeeperDialog( 0 );
|
|
|
|
gfIsTheShopKeeperTalking = FALSE;
|
|
if ( giShopKeeperFaceIndex > -1 )
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
#ifdef JA2UB
|
|
//ja25 UB
|
|
// if neither of the more precise quotes fit, or 33 percent of the time anyways
|
|
if ( ( sRandomQuoteToUse == -1 ) || Chance( 33 ) )
|
|
{
|
|
//If the dealer is Betty,
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_BETTY )
|
|
{
|
|
//she has 4 random quotes
|
|
UINT8 ubRandom = Random( 100 );
|
|
|
|
if( ubRandom > 75 )
|
|
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_PLAYER_DECIDING_1;
|
|
else if( ubRandom > 50 )
|
|
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_PLAYER_DECIDING_2;
|
|
else if( ubRandom > 25 )
|
|
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_PLAYER_DECIDING_3;
|
|
else
|
|
sRandomQuoteToUse = SK_QUOTES_RANDOM_QUOTE_WHILE_PLAYER_DECIDING_4;
|
|
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
|
|
#else
|
|
// 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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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 ) )
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
if( ValidAttachment( gpHighLightedItemObject->usItem, pItemObject ) )
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
void InitShopKeeperSubTitledText( STR16 pString )
|
|
{
|
|
//Clear the contents of the subtitle text
|
|
memset( gsShopKeeperTalkingText, 0, SKI_SUBTITLE_TEXT_SIZE );
|
|
|
|
swprintf( gsShopKeeperTalkingText, L"\"%s\"", pString );
|
|
|
|
//Now setup the popup box
|
|
if( gGameSettings.fOptions[ TOPTION_SUBTITLES ] )
|
|
{
|
|
UINT16 usActualWidth=0;
|
|
UINT16 usActualHeight=0;
|
|
|
|
giPopUpBoxId = PrepareMercPopupBox( giPopUpBoxId, BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gsShopKeeperTalkingText, 300, 0, 0, 0, &usActualWidth, &usActualHeight);
|
|
|
|
// 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( )
|
|
{
|
|
//loop through the players offer area and see if there are any items there
|
|
for ( int ubCnt = 0; ubCnt < gDealersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
//if is an item here
|
|
if( ArmsDealerOfferArea[ ubCnt ].fActive )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN AreThereItemsInThePlayersOfferArea( )
|
|
{
|
|
//loop through the players offer area and see if there are any items there
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++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 ubCount=0;
|
|
|
|
//loop through the players offer area and see if there are any items there
|
|
for ( int ubCnt = 0; ubCnt<gPlayersOfferActiveRegions; ++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 ubCount=0;
|
|
|
|
//loop through the players offer area and see if there are any items there
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++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 ubItemCount=0;
|
|
|
|
//loop through the player's offer area and see if there are any items there
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
//if is an item here
|
|
if( PlayersOfferArea[ubCnt].fActive )
|
|
{
|
|
++ubItemCount;
|
|
}
|
|
}
|
|
return( ubItemCount );
|
|
}
|
|
|
|
UINT8 CountNumberOfItemsInTheArmsDealersOfferArea( )
|
|
{
|
|
UINT8 ubItemCount=0;
|
|
|
|
//loop through the dealer's offer area and see if there are any items there
|
|
for ( int ubCnt = 0; ubCnt < gDealersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
//if is an item here
|
|
if( ArmsDealerOfferArea[ubCnt].fActive )
|
|
{
|
|
++ubItemCount;
|
|
}
|
|
}
|
|
|
|
return( ubItemCount );
|
|
}
|
|
|
|
INT8 GetSlotNumberForMerc( UINT8 ubProfile )
|
|
{
|
|
for( INT8 bCnt = 0; bCnt < gubNumberMercsInArray; ++bCnt )
|
|
{
|
|
if( gubArrayOfEmployedMercs[ bCnt ] == ubProfile )
|
|
return( bCnt );
|
|
}
|
|
|
|
// not found - not currently working for the player
|
|
return( -1 );
|
|
}
|
|
|
|
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 EnableDisableShopkeeperButtons(UINT32 uiCurrentItemDescriptionScreen, int bpAction)
|
|
{
|
|
if(uiCurrentItemDescriptionScreen != SHOPKEEPER_SCREEN)
|
|
return;
|
|
|
|
switch (bpAction)
|
|
{
|
|
case ACTIVATE_BUTTON:
|
|
if(guiSKI_TransactionButton != 0)
|
|
RemoveButton( guiSKI_TransactionButton );
|
|
if(guiSKI_TransactionButtonImage != 0)
|
|
UnloadButtonImage( guiSKI_TransactionButtonImage );
|
|
if(guiSKI_DoneButton != 0)
|
|
RemoveButton( guiSKI_DoneButton );
|
|
if(guiSKI_DoneButtonImage != 0)
|
|
UnloadButtonImage( guiSKI_DoneButtonImage );
|
|
|
|
guiSKI_TransactionButtonImage = LoadButtonImage("INTERFACE\\TradeButtons.sti", -1,0,-1,1,-1 );
|
|
guiSKI_DoneButtonImage = UseLoadedButtonImage( guiSKI_TransactionButtonImage, -1,0,-1,1,-1 );
|
|
|
|
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 ] );
|
|
break;
|
|
case DEACTIVATE_BUTTON:
|
|
if(guiSKI_TransactionButton != 0)
|
|
RemoveButton( guiSKI_TransactionButton );
|
|
if(guiSKI_DoneButton != 0)
|
|
RemoveButton( guiSKI_DoneButton );
|
|
EnableDisableShopkeeperButtons(uiCurrentItemDescriptionScreen, UNLOAD_BUTTON);
|
|
guiSKI_TransactionButtonImage = 0;
|
|
guiSKI_TransactionButton = 0;
|
|
guiSKI_DoneButtonImage = 0;
|
|
guiSKI_DoneButton = 0;
|
|
break;
|
|
case ENABLE_BUTTON:
|
|
if(guiSKI_TransactionButton == 0 || guiSKI_DoneButton == 0)
|
|
{
|
|
EnableDisableShopkeeperButtons(uiCurrentItemDescriptionScreen, DEACTIVATE_BUTTON);
|
|
EnableDisableShopkeeperButtons(uiCurrentItemDescriptionScreen, ACTIVATE_BUTTON);
|
|
}
|
|
if(guiSKI_TransactionButton != 0)
|
|
EnableButton( guiSKI_TransactionButton );
|
|
if(guiSKI_DoneButton != 0)
|
|
EnableButton( guiSKI_DoneButton );
|
|
break;
|
|
case DISABLE_BUTTON:
|
|
if(guiSKI_TransactionButton != 0)
|
|
DisableButton( guiSKI_TransactionButton );
|
|
if(guiSKI_DoneButton != 0)
|
|
DisableButton( guiSKI_DoneButton );
|
|
break;
|
|
case UNLOAD_BUTTON:
|
|
if(guiSKI_TransactionButtonImage != 0)
|
|
UnloadButtonImage( guiSKI_TransactionButtonImage );
|
|
if(guiSKI_DoneButtonImage != 0)
|
|
UnloadButtonImage( guiSKI_DoneButtonImage );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EnableDisableEvaluateAndTransactionButtons()
|
|
{
|
|
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 ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++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 &&
|
|
!( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL ) )
|
|
fItemEvaluated = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int ubCnt = 0; ubCnt < gDealersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
//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;
|
|
}
|
|
}
|
|
}
|
|
|
|
//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 );
|
|
}
|
|
|
|
INT32 balance = LaptopSaveInfo.iCurrentBalance;
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
balance = GetIntel();
|
|
|
|
if( uiArmsDealerTotalCost > uiPlayersOfferAreaTotalCost + balance )
|
|
{
|
|
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 )
|
|
{
|
|
EnableDisableShopkeeperButtons(SHOPKEEPER_SCREEN, DISABLE_BUTTON);
|
|
}
|
|
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)
|
|
{
|
|
gItemToAdd.fActive = TRUE;
|
|
gItemToAdd.ItemObject = *pItemObject;
|
|
}
|
|
|
|
BOOLEAN IsMoneyTheOnlyItemInThePlayersOfferArea( )
|
|
{
|
|
// we can't substitute money for intel
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
return FALSE;
|
|
|
|
BOOLEAN fFoundMoney = FALSE;
|
|
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++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 );
|
|
}
|
|
|
|
UINT32 CalculateHowMuchMoneyIsInPlayersOfferArea( )
|
|
{
|
|
// we can't substitute money for intel
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
return 0;
|
|
|
|
UINT32 uiTotalMoneyValue=0;
|
|
|
|
for ( int ubCnt = 0; ubCnt < gPlayersOfferActiveRegions; ++ubCnt )
|
|
{
|
|
//if there is an item here
|
|
if( PlayersOfferArea[ ubCnt ].fActive )
|
|
{
|
|
if( Item[ PlayersOfferArea[ ubCnt ].sItemIndex ].usItemClass == IC_MONEY )
|
|
{
|
|
uiTotalMoneyValue += PlayersOfferArea[ ubCnt ].ItemObject[0]->data.money.uiMoneyAmount;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( uiTotalMoneyValue );
|
|
}
|
|
|
|
void MovePlayersItemsToBeRepairedToArmsDealersInventory()
|
|
{
|
|
//loop through all the slots in the shopkeeper's offer area
|
|
for ( int uiCnt = 0; uiCnt<gDealersOfferActiveRegions; ++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 );
|
|
|
|
//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( INT16 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 )
|
|
{
|
|
//loop through the soldier's inventory
|
|
INT8 invsize = (INT8)pSoldier->inv.size();
|
|
for( INT8 bCnt=0; bCnt < invsize; ++bCnt)
|
|
{
|
|
// Look for MONEY only, not Gold or Silver!!! And look for a slot not already full
|
|
if( ( pSoldier->inv[ bCnt ].usItem == MONEY ) && ( pSoldier->inv[ bCnt ][0]->data.money.uiMoneyAmount < MoneySlotLimit( bCnt ) ) )
|
|
{
|
|
return( bCnt );
|
|
}
|
|
}
|
|
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
void ClearArmsDealerOfferSlot( INT32 ubSlotToClear )
|
|
{
|
|
// Clear the contents
|
|
ArmsDealerOfferArea[ ubSlotToClear ].initialize();
|
|
|
|
//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
|
|
PlayersOfferArea[ ubSlotToClear ].initialize();
|
|
|
|
//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)
|
|
|
|
#ifdef JA2UB
|
|
//no UB
|
|
#else
|
|
if( !gfDealerHasSaidTheEvaluateQuoteOnceThisSession && ( gbSelectedArmsDealerID != ARMS_DEALER_DEVIN ) )
|
|
{
|
|
gfDealerHasSaidTheEvaluateQuoteOnceThisSession = TRUE;
|
|
StartShopKeeperTalking( SK_QUOTES_PLAYER_REQUESTED_EVALUATION );
|
|
}
|
|
#endif
|
|
|
|
//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[0]->data.objectStatus < 100 ) || fRocketRifleWasEvaluated )
|
|
{
|
|
INT16 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[0]->data.objectStatus < 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:
|
|
#ifdef JA2UB
|
|
//JA25 UB
|
|
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
|
|
{
|
|
//if the dealer is BETTY
|
|
if( gbSelectedArmsDealerID == ARMS_DEALER_BETTY &&
|
|
( Item[ PlayersOfferArea[ bSlotID ].sItemIndex ].usItemClass == IC_AMMO ||
|
|
Item[ PlayersOfferArea[ bSlotID ].sItemIndex ].usItemClass == IC_GUN
|
|
)
|
|
)
|
|
{
|
|
// she accepts items, but not this one
|
|
sQuoteNum = SK_QUOTES_NPC_SPECIFIC_40;
|
|
}
|
|
else
|
|
{
|
|
// he accepts items, but not this one
|
|
sQuoteNum = SK_QUOTES_DURING_EVALUATION_STUFF_REJECTED;
|
|
}
|
|
}
|
|
#endif
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void ConfirmToDeductIntelFromPlayersAccountMessageBoxCallBack( 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 );
|
|
|
|
AddIntel( -iMoneyToDeduct, TRUE );
|
|
}
|
|
|
|
// 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 WillShopKeeperRejectItemFromPlayer( INT8 bDealerId, UINT16 usItem )
|
|
{
|
|
BOOLEAN fRejected = TRUE;
|
|
|
|
if ( Item[usItem].usItemClass == IC_MONEY )
|
|
{
|
|
// we can't substitute money for intel
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].uiFlags & ARMS_DEALER_DEALWITHINTEL )
|
|
fRejected = TRUE;
|
|
else
|
|
fRejected = FALSE;
|
|
}
|
|
else if ( CanDealerTransactItem( gbSelectedArmsDealerID, usItem, TRUE ) )
|
|
{
|
|
fRejected = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fRejected = TRUE;
|
|
}
|
|
|
|
return fRejected;
|
|
}
|
|
|
|
BOOLEAN DoesCurrentDealerRefuseToTradeItem( UINT16 usItem )
|
|
{
|
|
//if non-repairman
|
|
if ( armsDealerInfo[gbSelectedArmsDealerID].ubTypeOfArmsDealer != ARMS_DEALER_REPAIRS )
|
|
{
|
|
// don't evaluate anything he wouldn't buy!
|
|
if ( WillShopKeeperRejectItemFromPlayer( gbSelectedArmsDealerID, usItem ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// 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 )
|
|
{
|
|
return WillShopKeeperRejectItemFromPlayer( bDealerId, PlayersOfferArea[bSlotId].sItemIndex );
|
|
}
|
|
|
|
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<gPlayersOfferActiveRegions; ++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;
|
|
}
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
INT16 GetNumberOfItemsInPlayerOfferArea( void )
|
|
{
|
|
INT16 sCounter = 0;
|
|
INT32 iCounter = 0;
|
|
|
|
// find number of active slot in player offer area
|
|
for ( iCounter = 0; iCounter < gPlayersOfferActiveRegions; ++iCounter )
|
|
{
|
|
if( PlayersOfferArea[ iCounter ].fActive )
|
|
{
|
|
++sCounter;
|
|
}
|
|
}
|
|
|
|
return( sCounter );
|
|
}
|
|
|
|
void HandleCheckIfEnoughOnTheTable( void )
|
|
{
|
|
static INT32 iLastTime = 0;
|
|
INT32 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;
|
|
}
|
|
}
|
|
|
|
void InitShopKeeperItemDescBox( OBJECTTYPE *pObject, UINT16 ubPocket, UINT8 ubFromLocation )
|
|
{
|
|
INT16 sPosX, sPosY;
|
|
|
|
bool showItemDescriptionBox = false;
|
|
switch( ubFromLocation )
|
|
{
|
|
case ARMS_DEALER_INVENTORY:
|
|
{
|
|
showItemDescriptionBox = true;
|
|
|
|
UINT16 ubSelectedInvSlot = ubPocket - gSelectArmsDealerInfo.ubFirstItemIndexOnPage;
|
|
|
|
if( gGameSettings.fOptions[ TOPTION_ENHANCED_DESC_BOX ] == FALSE)
|
|
{
|
|
sPosX = SKI_TRADER_INVENTORY_BOXES_BEGIN_X;
|
|
sPosY = SKI_TRADER_INVENTORY_BOXES_BEGIN_Y;
|
|
}
|
|
else
|
|
{
|
|
sPosX = SCREEN_X_OFFSET + 2;
|
|
sPosY = SCREEN_Y_OFFSET + 146;
|
|
}
|
|
|
|
//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:
|
|
{
|
|
showItemDescriptionBox = false;
|
|
|
|
sPosX = SKI_TRADER_OFFER_BOXES_BEGIN_X;
|
|
sPosY = SKI_TRADER_OFFER_BOXES_BEGIN_Y;
|
|
|
|
//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;
|
|
}
|
|
|
|
// WANNE: Only allow right click (item desription box) in the arms dealer inventory
|
|
if (showItemDescriptionBox)
|
|
{
|
|
pShopKeeperItemDescObject = pObject;
|
|
|
|
InitItemDescriptionBox( gpSMCurrentMerc, 255, sPosX, sPosY, 0 );
|
|
|
|
StartSKIDescriptionBox( );
|
|
}
|
|
}
|
|
|
|
void StartSKIDescriptionBox( void )
|
|
{
|
|
//shadow the entire screen
|
|
DrawHatchOnInventory( FRAME_BUFFER, SKI_TOTAL_BEGIN_X, SKI_TOTAL_BEGIN_Y, SKI_TOTAL_END_X - SKI_TOTAL_BEGIN_X, SKI_TOTAL_END_Y - SKI_TOTAL_BEGIN_Y );
|
|
|
|
InvalidateRegion( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
|
|
// disable almost everything!
|
|
|
|
gfSMDisableForItems = TRUE;
|
|
DisableInvRegions( gfSMDisableForItems );
|
|
|
|
DisableButton( guiSKI_InvPageUpButton );
|
|
DisableButton( guiSKI_InvPageDownButton );
|
|
EnableDisableShopkeeperButtons(SHOPKEEPER_SCREEN, DISABLE_BUTTON);
|
|
|
|
DisableAllDealersInventorySlots();
|
|
DisableAllDealersOfferSlots();
|
|
|
|
for ( int iCnt = 0; iCnt < gPlayersOfferActiveRegions; ++iCnt )
|
|
{
|
|
MSYS_DisableRegion( &gPlayersOfferSlotsMouseRegions[ iCnt ] );
|
|
MSYS_DisableRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
|
|
}
|
|
|
|
if( gShopKeeperSubTitleMouseRegion.uiFlags & MSYS_REGION_EXISTS )
|
|
{
|
|
MSYS_DisableRegion( &gShopKeeperSubTitleMouseRegion );
|
|
}
|
|
|
|
RenderItemDescriptionBox( );
|
|
}
|
|
|
|
void DeleteShopKeeperItemDescBox()
|
|
{
|
|
pShopKeeperItemDescObject = NULL;
|
|
gubSkiDirtyLevel = SKI_DIRTY_LEVEL2;
|
|
|
|
//Redraw the face
|
|
if ( giShopKeeperFaceIndex > -1 )
|
|
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 );
|
|
EnableDisableShopkeeperButtons(SHOPKEEPER_SCREEN, ENABLE_BUTTON);
|
|
|
|
EnableDisableDealersInventoryPageButtons();
|
|
EnableDisableEvaluateAndTransactionButtons();
|
|
|
|
EnableAllDealersInventorySlots();
|
|
EnableAllDealersOfferSlots();
|
|
|
|
for ( INT32 iCnt = 0; iCnt < gPlayersOfferActiveRegions; ++iCnt )
|
|
{
|
|
MSYS_EnableRegion( &gPlayersOfferSlotsMouseRegions[ iCnt ] );
|
|
MSYS_EnableRegion( &gPlayersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
|
|
}
|
|
|
|
if( gShopKeeperSubTitleMouseRegion.uiFlags & MSYS_REGION_EXISTS )
|
|
{
|
|
MSYS_EnableRegion( &gShopKeeperSubTitleMouseRegion );
|
|
}
|
|
}
|
|
|
|
BOOLEAN OfferObjectToDealer( OBJECTTYPE *pComplexObject, UINT8 ubOwnerProfileId, INT16 bOwnerSlotId )
|
|
{
|
|
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, &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++;
|
|
}
|
|
|
|
//this is a silly assert, was it meant to be something else?
|
|
Assert( SKI_MAX_AMOUNT_OF_ITEMS_DEALER_CAN_REPAIR_AT_A_TIME < (SKI_PLAYER_OFFER_BOXES_PER_ROW * SKI_PLAYER_OFFER_BOXES_PER_COL) );
|
|
/*
|
|
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_PLAYER_OFFER_BOXES_PER_ROW * SKI_PLAYER_OFFER_BOXES_PER_COL) )
|
|
{
|
|
gfDisplayNoRoomMsg = TRUE;
|
|
return(FALSE); // no room
|
|
}
|
|
|
|
// we have room, so move them all to the appropriate slots
|
|
for ( ubSubObject = 0; ubSubObject < subObjects.size(); ubSubObject++ )
|
|
{
|
|
// if it's the main item itself (always in the very first subobject), and it has no other subobjects
|
|
if ( ( ubSubObject == 0 ) && ( subObjects.size() == 1) )
|
|
{
|
|
// store its owner merc as the owner, and store the correct slot
|
|
fSuccess = AddObjectForEvaluation( &subObjects[ 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( &subObjects[ 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 )
|
|
{
|
|
Assert( pComplexObject );
|
|
Assert( pComplexObject->exists() == true );
|
|
|
|
subObjects.clear();
|
|
int usItem = pComplexObject->usItem;
|
|
//CHRISL: This won't work. As we his MoveThisObjectTo, we reduce ubNumberOfObjects. If we started with ubNumberOfObjects=4 & x=0,
|
|
// our first iteration would be ubNumberOfObjects=3 & x=1. Then ubNumberOfObjects=2 & x=2, which ends the loop. We want to
|
|
// run the loop ubNumberOfObjects number of times regardless of whether ubNumberOfObjects is reduced. Use a while loop.
|
|
//for (int x = 0; x < pComplexObject->ubNumberOfObjects; ++x) {
|
|
while(pComplexObject->ubNumberOfObjects > 0) {
|
|
//we need not worry about attachments!!!!
|
|
|
|
if (pComplexObject->MoveThisObjectTo(gTempObject, 1) == 0) {
|
|
subObjects.push_back(gTempObject);
|
|
StackedObjectData* pData = subObjects.back()[0];
|
|
|
|
// if it's a gun
|
|
if ( Item [ usItem ].usItemClass == IC_GUN )
|
|
{
|
|
int usGunAmmoItem = pData->data.gun.usGunAmmoItem;
|
|
int ubGunShotsLeft = pData->data.gun.ubGunShotsLeft;
|
|
int bGunAmmoStatus = pData->data.gun.bGunAmmoStatus;
|
|
|
|
// strip off any loaded ammo/payload
|
|
// Exception: don't do this with rocket launchers, their "shots left" are fake and this screws 'em up!
|
|
if ( !Item[usItem].singleshotrocketlauncher ) // Madd rpg - still do this
|
|
{
|
|
pData->data.gun.usGunAmmoItem = NONE;
|
|
pData->data.gun.ubGunShotsLeft = 0;
|
|
pData->data.gun.ubGunState = 0;
|
|
pData->data.gun.ubGunAmmoType = 0;
|
|
pData->data.gun.bGunAmmoStatus = 0;
|
|
}
|
|
|
|
// and it has ammo/payload
|
|
if ( usGunAmmoItem != NONE )
|
|
{
|
|
// if it's bullets
|
|
if ( Item[ usGunAmmoItem ].usItemClass == IC_AMMO )
|
|
{
|
|
// and there are some left
|
|
if ( ubGunShotsLeft > 0 )
|
|
{
|
|
// make the bullets into another subobject
|
|
CreateAmmo( usGunAmmoItem, &gTempObject, ubGunShotsLeft );
|
|
subObjects.push_back(gTempObject);
|
|
}
|
|
// ignore this if it's out of bullets
|
|
}
|
|
else // non-ammo payload
|
|
{
|
|
// if the gun was jammed, fix up the payload's status
|
|
if ( bGunAmmoStatus < 0 )
|
|
{
|
|
bGunAmmoStatus *= -1;
|
|
}
|
|
|
|
// make the payload into another subobject
|
|
CreateItem( usGunAmmoItem, bGunAmmoStatus, &gTempObject );
|
|
subObjects.push_back(gTempObject);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CountSubObjectsInObject( OBJECTTYPE *pComplexObject, UINT8 *pubRepairableSubObjects, UINT8 *pubNonRepairableSubObjects )
|
|
{
|
|
UINT8 ubSubObject;
|
|
|
|
*pubRepairableSubObjects = 0;
|
|
*pubNonRepairableSubObjects = 0;
|
|
|
|
// check every subobject and count it as either repairable or non-
|
|
for ( ubSubObject = 0; ubSubObject < subObjects.size(); ubSubObject++ )
|
|
{
|
|
// 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 ( ( subObjects[ ubSubObject ][0]->data.objectStatus != 100 ) &&
|
|
CanDealerRepairItem( gbSelectedArmsDealerID, subObjects[ ubSubObject ].usItem ) )
|
|
{
|
|
( *pubRepairableSubObjects )++;
|
|
}
|
|
else
|
|
{
|
|
( *pubNonRepairableSubObjects )++;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN AddObjectForEvaluation(OBJECTTYPE *pObject, UINT8 ubOwnerProfileId, INT16 bOwnerSlotId, BOOLEAN fFirstOne )
|
|
{
|
|
INVENTORY_IN_SLOT InvSlot;
|
|
INT8 bAddedToSlotID;
|
|
|
|
// Make a new inv slot out of the subobject
|
|
InvSlot.ItemObject = *pObject;
|
|
|
|
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 )
|
|
{
|
|
// 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
|
|
OBJECTTYPE movingObject;
|
|
|
|
while ( pObject->exists() == true )
|
|
{
|
|
// figure out how many to place during this loop iteration. Can't do more than MAX_OBJECTS_PER_SLOT at a time
|
|
int numToMove = min( MAX_OBJECTS_PER_SLOT, pObject->ubNumberOfObjects);
|
|
|
|
pObject->MoveThisObjectTo(movingObject, numToMove);
|
|
if (!AutoPlaceObject( pSoldier, &movingObject, fNewItem ))
|
|
//if (!AutoPlaceObject( pSoldier, pObject, fNewItem ))
|
|
{
|
|
//CHRISL: When we call this, we don't care about cap limits so stack up to max
|
|
// no more room, didn't all fit - add back in any that we didn't even get to yet
|
|
pObject->AddObjectsToStack(movingObject, -1, 0, NUM_INV_SLOTS, MAX_OBJECTS_PER_SLOT);
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
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( INT32 sGridNo, OBJECTTYPE *pObject, INT8 bVisible, UINT8 ubLevel, UINT16 usFlags, INT8 bRenderZHeightAboveLevel )
|
|
{
|
|
// 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
|
|
OBJECTTYPE movingObject;
|
|
|
|
while ( pObject->exists() == true )
|
|
{
|
|
// figure out how many to place during this loop iteration. Can't do more than MAX_OBJECTS_PER_SLOT at a time
|
|
int numToMove = min( MAX_OBJECTS_PER_SLOT, pObject->ubNumberOfObjects);
|
|
|
|
pObject->MoveThisObjectTo(movingObject, numToMove);
|
|
AddItemToPool( sGridNo, &movingObject, bVisible, ubLevel, usFlags, bRenderZHeightAboveLevel );
|
|
}
|
|
}
|
|
|
|
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 ) )
|
|
{
|
|
// get soldier
|
|
sSoldierID = GetSoldierIDFromMercID( pInv->ubIdOfMercWhoOwnsTheItem );
|
|
Assert( sSoldierID != -1 );
|
|
Assert( CanMercInteractWithSelectedShopkeeper( MercPtrs[ sSoldierID ] ) );
|
|
|
|
// then it better be a valid slot #
|
|
Assert( pInv->bSlotIdInOtherLocation < (INT8)Menptr[ sSoldierID ].inv.size() );
|
|
// and it better have a valid merc who owned it
|
|
Assert( pInv->ubIdOfMercWhoOwnsTheItem != NO_PROFILE );
|
|
|
|
//Copy the object back into that merc's original inventory slot
|
|
Menptr[ sSoldierID ].inv[ pInv->bSlotIdInOtherLocation ] = pInv->ItemObject;
|
|
}
|
|
}
|
|
|
|
void IfMercOwnedRemoveItemFromMercInv( INVENTORY_IN_SLOT *pInv )
|
|
{
|
|
IfMercOwnedRemoveItemFromMercInv2( pInv->ubIdOfMercWhoOwnsTheItem, pInv->bSlotIdInOtherLocation );
|
|
}
|
|
|
|
void IfMercOwnedRemoveItemFromMercInv2( UINT8 ubOwnerProfileId, INT16 bOwnerSlotId )
|
|
{
|
|
//if this item was in a previous location, and that location is on a merc's inventory
|
|
if ( ( bOwnerSlotId != -1 ) && ( ubOwnerProfileId != NO_PROFILE ) )
|
|
{
|
|
// and it better have a valid merc who owned it
|
|
Assert( ubOwnerProfileId != NO_PROFILE );
|
|
INT16 sSoldierID = GetSoldierIDFromMercID( ubOwnerProfileId );
|
|
Assert( sSoldierID != -1 );
|
|
// then it better be a valid slot #
|
|
Assert( bOwnerSlotId < (INT8)Menptr[ sSoldierID ].inv.size() );
|
|
|
|
Assert( CanMercInteractWithSelectedShopkeeper( MercPtrs[ sSoldierID ] ) );
|
|
|
|
//remove the object from that merc's original inventory slot
|
|
DeleteObj(&(Menptr[ sSoldierID ].inv[bOwnerSlotId]));
|
|
}
|
|
}
|
|
|
|
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[0]->data.money.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;
|
|
INT32 sDestGridNo;
|
|
INT8 bDestLevel;
|
|
UINT32 uiRange;
|
|
|
|
Assert( pSoldier!= NULL );
|
|
Assert( gbSelectedArmsDealerID != -1 );
|
|
|
|
if ( gusIDOfCivTrader != NOBODY )
|
|
pShopkeeper = MercPtrs[gusIDOfCivTrader];
|
|
else
|
|
pShopkeeper = FindSoldierByProfileID( armsDealerInfo[gbSelectedArmsDealerID].ubShopKeeperID, FALSE );
|
|
|
|
Assert( pShopkeeper != NULL );
|
|
Assert( pShopkeeper->bActive );
|
|
Assert( pShopkeeper->bInSector );
|
|
|
|
if ( pShopkeeper->stats.bLife < OKLIFE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( pSoldier->bActive && pSoldier->bInSector && IsMercOnCurrentSquad( pSoldier ) && ( pSoldier->stats.bLife >= OKLIFE ) &&
|
|
!( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
sDestGridNo = pShopkeeper->sGridNo;
|
|
bDestLevel = pShopkeeper->pathing.bLevel;
|
|
// If he has LOS...
|
|
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, sDestGridNo, bDestLevel, 3, TRUE, CALC_FROM_ALL_DIRS ) )
|
|
{
|
|
// 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, INT32 sGridNo )
|
|
{
|
|
SOLDIERCREATE_STRUCT MercCreateStruct;
|
|
INT16 sSectorX, sSectorY;
|
|
UINT8 ubID;
|
|
|
|
GetCurrentWorldSector( &sSectorX, &sSectorY );
|
|
|
|
MercCreateStruct.initialize();
|
|
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()
|
|
{
|
|
// reset flags for quotes said
|
|
for ( UINT8 uiCnt = 0; uiCnt < NUM_EVAL_RESULTS; ++uiCnt )
|
|
{
|
|
gfEvalResultQuoteSaid[ uiCnt ] = FALSE;
|
|
}
|
|
|
|
guiLastTimeDealerSaidNormalEvaluationQuote = 0;
|
|
}
|
|
|
|
void DealWithItemsStillOnTheTable()
|
|
{
|
|
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 ( int ubCnt = 0; ubCnt < (SKI_PLAYER_OFFER_BOXES_PER_ROW * SKI_PLAYER_OFFER_BOXES_PER_COL); ++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 ( int ubCnt = 0; ubCnt < (SKI_TRADER_OFFER_BOXES_PER_ROW * SKI_TRADER_OFFER_BOXES_PER_COL); ++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->pathing.bLevel, 0, 0 );
|
|
}
|
|
}
|
|
|
|
//CHRISL: We need to handle LBENODE items a little differently so we don't lose anything stored in them. Instead of
|
|
// trying to return the item, simply drop the item to the ground.
|
|
if(UsingNewInventorySystem() == true && pInvSlot->ItemObject.IsActiveLBE(0) == true)
|
|
{
|
|
pDropSoldier->inv[pInvSlot->bSlotIdInOtherLocation].initialize();
|
|
ShopkeeperAddItemToPool( pDropSoldier->sGridNo, &pInvSlot->ItemObject, VISIBLE, pDropSoldier->pathing.bLevel, 0, 0 );
|
|
}
|
|
}
|
|
|
|
void GivePlayerSomeChange( UINT32 uiAmount )
|
|
{
|
|
INVENTORY_IN_SLOT 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
|
|
#ifdef JA2UB
|
|
if ( ( gbSelectedArmsDealerID == ARMS_DEALER_FREDO ) || ( gbSelectedArmsDealerID == ARMS_DEALER_RAUL ) )
|
|
#else
|
|
if ( ( gbSelectedArmsDealerID == ARMS_DEALER_FREDO ) || ( gbSelectedArmsDealerID == ARMS_DEALER_PERKO ) )
|
|
#endif
|
|
|
|
{
|
|
// 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 )
|
|
{
|
|
//if the dealer is not a repair dealer, return
|
|
if( !DoesDealerDoRepairs( gbSelectedArmsDealerID ) )
|
|
return( FALSE );
|
|
|
|
BOOLEAN fFoundOne = FALSE;
|
|
UINT32 uiMinutesSinceItWasDone;
|
|
UINT32 uiMinutesShopClosedSinceItWasDone;
|
|
UINT32 uiWorkingHoursSinceThisItemRepaired;
|
|
|
|
*puiHoursSinceOldestItemRepaired = 0;
|
|
|
|
UINT32 currentTime = GetWorldTotalMin();
|
|
//loop through the dealers inventory and check if there are only unrepaired items
|
|
for (DealerItemList::iterator iter = gArmsDealersInventory[gbSelectedArmsDealerID].begin();
|
|
iter != gArmsDealersInventory[gbSelectedArmsDealerID].end(); ++iter) {
|
|
if ( iter->ItemIsInInventory() == true )
|
|
{
|
|
if( iter->IsUnderRepair() == true )
|
|
{
|
|
//if the repairs are done
|
|
if( iter->uiRepairDoneTime <= currentTime )
|
|
{
|
|
// at least one item is supposed to be done by now
|
|
fFoundOne = TRUE;
|
|
|
|
uiMinutesSinceItWasDone = currentTime - iter->uiRepairDoneTime;
|
|
uiMinutesShopClosedSinceItWasDone = CalculateMinutesClosedBetween( gbSelectedArmsDealerID, iter->uiRepairDoneTime, currentTime );
|
|
|
|
// 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 )
|
|
{
|
|
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 (DealerItemList::iterator iter = gArmsDealersInventory[gbSelectedArmsDealerID].begin();
|
|
iter != gArmsDealersInventory[gbSelectedArmsDealerID].end(); ++iter) {
|
|
if ( iter->ItemIsInInventory() == true )
|
|
{
|
|
if( iter->IsUnderRepair() == true )
|
|
{
|
|
uiMinutesShopClosedBeforeItsDone = CalculateOvernightRepairDelay( gbSelectedArmsDealerID, iter->uiRepairDoneTime, uiMinutesDelayed );
|
|
// add this many minutes to the repair time estimate
|
|
iter->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->pathing.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()
|
|
{
|
|
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 );
|
|
}
|
|
|
|
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[0]->data.objectStatus < 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 );
|
|
}
|
|
|
|
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, INVENTORY_IN_SLOT* pObject )
|
|
{
|
|
UINT32 uiDoneTime;
|
|
UINT32 uiDay, uiHour, uiMin;
|
|
|
|
//dealer must be a repair dealer
|
|
Assert( DoesDealerDoRepairs( ubArmsDealer ) );
|
|
|
|
DEALER_SPECIAL_ITEM* pSpecial = 0;
|
|
for (DealerItemList::iterator iter = gArmsDealersInventory[ubArmsDealer].begin();
|
|
iter != gArmsDealersInventory[ubArmsDealer].end(); ++iter) {
|
|
if (iter->ItemIsInInventory() == true && iter->IsUnderRepair() == true) {
|
|
if (pObject->ItemObject == iter->object && pObject->uiRepairDoneTime == iter->uiRepairDoneTime) {
|
|
pSpecial = &(*iter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Assert(pSpecial);
|
|
// that item must be in repair
|
|
Assert( pSpecial->IsUnderRepair() == true );
|
|
|
|
//if the item has already been repaired
|
|
uiDoneTime = pSpecial->uiRepairDoneTime;
|
|
if( uiDoneTime <= GetWorldTotalMin() )
|
|
{
|
|
wcscpy( sString, L"" );
|
|
return;
|
|
}
|
|
|
|
// 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 )
|
|
{
|
|
for ( int iCnt = 0; iCnt < gDealersInventoryActiveRegions; ++iCnt )
|
|
{
|
|
MSYS_DisableRegion( &gDealersInventoryMouseRegions[ iCnt ] );
|
|
|
|
//if the dealer repairs
|
|
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
MSYS_DisableRegion( &gRepairmanInventorySmallFaceMouseRegions[ iCnt ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnableAllDealersInventorySlots( void )
|
|
{
|
|
for ( int iCnt = 0; iCnt < gDealersInventoryActiveRegions; ++iCnt )
|
|
{
|
|
MSYS_EnableRegion( &gDealersInventoryMouseRegions[ iCnt ] );
|
|
|
|
//if the dealer repairs
|
|
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
MSYS_EnableRegion( &gRepairmanInventorySmallFaceMouseRegions[ iCnt ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void DisableAllDealersOfferSlots( void )
|
|
{
|
|
for ( int iCnt = 0; iCnt < gDealersOfferActiveRegions; ++iCnt )
|
|
{
|
|
MSYS_DisableRegion( &gDealersOfferSlotsMouseRegions[ iCnt ] );
|
|
|
|
//if the dealer repairs
|
|
if( armsDealerInfo[ gbSelectedArmsDealerID ].ubTypeOfArmsDealer == ARMS_DEALER_REPAIRS )
|
|
{
|
|
MSYS_DisableRegion( &gDealersOfferSlotsSmallFaceMouseRegions[ iCnt ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void EnableAllDealersOfferSlots( void )
|
|
{
|
|
for ( int iCnt = 0; iCnt < gDealersOfferActiveRegions; ++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 );
|
|
}
|
|
#ifdef JA2UB
|
|
//ja25 UB
|
|
void AskUserToAttachTransmitterToLaptop()
|
|
{
|
|
DoSkiMessageBox( MSG_BOX_BASIC_STYLE, zNewTacticalMessages[ TCTL_MSG__ATTACH_TRANSMITTER_TO_LAPTOP ], SHOPKEEPER_SCREEN, MSG_BOX_FLAG_OK, AttachLaptopTransmitterToLaptop );
|
|
}
|
|
|
|
void AttachLaptopTransmitterToLaptop( UINT8 ubExitValue )
|
|
{
|
|
//
|
|
// Get the laptop working again
|
|
//
|
|
|
|
//Mark the quest done
|
|
if ( gGameUBOptions.LaptopQuestEnabled == TRUE )
|
|
EndQuest( QUEST_FIX_LAPTOP, -1, -1 );
|
|
}
|
|
#endif
|