1 #include "Directories.h"
2 #include "Font.h"
3 #include "Laptop.h"
4 #include "Merc_Hiring.h"
5 #include "Mercs_Account.h"
6 #include "Mercs.h"
7 #include "MessageBoxScreen.h"
8 #include "VObject.h"
9 #include "WordWrap.h"
10 #include "Cursors.h"
11 #include "Soldier_Profile.h"
12 #include "Finances.h"
13 #include "Game_Clock.h"
14 #include "Soldier_Add.h"
15 #include "Overhead.h"
16 #include "History.h"
17 #include "LaptopSave.h"
18 #include "Text.h"
19 #include "Speck_Quotes.h"
20 #include "Multi_Language_Graphic_Utils.h"
21 #include "Button_System.h"
22 #include "Video.h"
23 #include "VSurface.h"
24 #include "ScreenIDs.h"
25 #include "Font_Control.h"
26 #include "GameInstance.h"
27 #include "ContentManager.h"
28
29 #include <string_theory/format>
30 #include <string_theory/string>
31
32
33 #define MERC_ACCOUNT_TEXT_FONT FONT14ARIAL
34 #define MERC_ACCOUNT_TEXT_COLOR FONT_MCOLOR_WHITE
35
36 #define MERC_ACCOUNT_DYNAMIC_TEXT_FONT FONT12ARIAL
37 #define MERC_ACCOUNT_DYNAMIC_TEXT_COLOR FONT_MCOLOR_WHITE
38 #define MERC_ACCOUNT_DEAD_TEXT_COLOR FONT_MCOLOR_RED
39
40 #define MERC_AC_ORDER_GRID_X LAPTOP_SCREEN_UL_X + 23
41 #define MERC_AC_ORDER_GRID_Y LAPTOP_SCREEN_WEB_UL_Y + 59
42
43 #define MERC_AC_ACCOUNT_NUMBER_X LAPTOP_SCREEN_UL_X + 23
44 #define MERC_AC_ACCOUNT_NUMBER_Y LAPTOP_SCREEN_WEB_UL_Y + 13
45
46 #define MERC_AC_AUTHORIZE_BUTTON_X (STD_SCREEN_X + 128)
47 #define MERC_AC_CANCEL_BUTTON_X (STD_SCREEN_X + 490)
48 #define MERC_AC_BUTTON_Y (STD_SCREEN_Y + 380)
49
50 #define MERC_AC_ACCOUNT_NUMBER_TEXT_X MERC_AC_ACCOUNT_NUMBER_X + 5
51 #define MERC_AC_ACCOUNT_NUMBER_TEXT_Y MERC_AC_ACCOUNT_NUMBER_Y + 12
52
53 #define MERC_AC_MERC_TITLE_Y MERC_AC_ORDER_GRID_Y + 14
54 #define MERC_AC_TOTAL_COST_Y MERC_AC_ORDER_GRID_Y + 242
55
56 #define MERC_AC_FIRST_COLUMN_X MERC_AC_ORDER_GRID_X + 2
57 #define MERC_AC_SECOND_COLUMN_X MERC_AC_ORDER_GRID_X + 222
58 #define MERC_AC_THIRD_COLUMN_X MERC_AC_ORDER_GRID_X + 292
59 #define MERC_AC_FOURTH_COLUMN_X MERC_AC_ORDER_GRID_X + 382
60
61 #define MERC_AC_FIRST_COLUMN_WIDTH 218
62 #define MERC_AC_SECOND_COLUMN_WIDTH 68
63 #define MERC_AC_THIRD_COLUMN_WIDTH 88
64 #define MERC_AC_FOURTH_COLUMN_WIDTH 76
65
66 #define MERC_AC_FIRST_ROW_Y MERC_AC_ORDER_GRID_Y + 42
67 #define MERC_AC_ROW_SIZE 16
68
69
70 static SGPVObject* guiMercOrderGrid;
71 static SGPVObject* guiAccountNumberGrid;
72
73
74 INT32 giMercTotalContractCharge;
75
76 BOOLEAN gfMercPlayerDoesntHaveEnoughMoney_DisplayWarning = FALSE;
77
78 // The Authorize button
79 static BUTTON_PICS* guiMercAuthorizeButtonImage;
80 GUIButtonRef guiMercAuthorizeBoxButton;
81
82
83 // The Back button
84 GUIButtonRef guiMercBackBoxButton;
85
86
MakeButton(const ST::string & text,INT16 x,GUI_CALLBACK click)87 static GUIButtonRef MakeButton(const ST::string& text, INT16 x, GUI_CALLBACK click)
88 {
89 const INT16 shadow_col = DEFAULT_SHADOW;
90 GUIButtonRef const btn = CreateIconAndTextButton(guiMercAuthorizeButtonImage, text, FONT12ARIAL, MERC_BUTTON_UP_COLOR, shadow_col, MERC_BUTTON_DOWN_COLOR, shadow_col, x, MERC_AC_BUTTON_Y, MSYS_PRIORITY_HIGH, click);
91 btn->SetCursor(CURSOR_LAPTOP_SCREEN);
92 return btn;
93 }
94
95
96 static void BtnMercAuthorizeButtonCallback(GUI_BUTTON* btn, INT32 reason);
97 static void BtnMercBackButtonCallback(GUI_BUTTON* btn, INT32 reason);
98
99
EnterMercsAccount()100 void EnterMercsAccount()
101 {
102 InitMercBackGround();
103
104 // load the Arrow graphic and add it
105 const char* const ImageFile = GetMLGFilename(MLG_ORDERGRID);
106 guiMercOrderGrid = AddVideoObjectFromFile(ImageFile);
107
108 // load the Arrow graphic and add it
109 guiAccountNumberGrid = AddVideoObjectFromFile(LAPTOPDIR "/accountnumber.sti");
110
111 guiMercAuthorizeButtonImage = LoadButtonImage(LAPTOPDIR "/bigbuttons.sti", 0, 1);
112 guiMercAuthorizeBoxButton = MakeButton(MercAccountText[MERC_ACCOUNT_AUTHORIZE], MERC_AC_AUTHORIZE_BUTTON_X, BtnMercAuthorizeButtonCallback);
113 guiMercAuthorizeBoxButton->SpecifyDisabledStyle(GUI_BUTTON::DISABLED_STYLE_SHADED);
114 guiMercBackBoxButton = MakeButton(MercAccountText[MERC_ACCOUNT_HOME], MERC_AC_CANCEL_BUTTON_X, BtnMercBackButtonCallback);
115
116 //RenderMercsAccount();
117
118 //if true, will display a msgbox telling user that they dont have enough funds
119 gfMercPlayerDoesntHaveEnoughMoney_DisplayWarning = FALSE;
120 }
121
122
ExitMercsAccount()123 void ExitMercsAccount()
124 {
125 DeleteVideoObject(guiMercOrderGrid);
126 DeleteVideoObject(guiAccountNumberGrid);
127
128 UnloadButtonImage( guiMercAuthorizeButtonImage );
129 RemoveButton( guiMercAuthorizeBoxButton );
130 RemoveButton( guiMercBackBoxButton );
131
132 RemoveMercBackGround();
133 }
134
HandleMercsAccount()135 void HandleMercsAccount()
136 {
137 //if true, will display a msgbox telling user that they dont have enough funds
138 if( gfMercPlayerDoesntHaveEnoughMoney_DisplayWarning )
139 {
140 gfMercPlayerDoesntHaveEnoughMoney_DisplayWarning = FALSE;
141
142 DoLapTopMessageBox( MSG_BOX_BLUE_ON_GREY, "Transfer failed. No funds available.", LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL );
143 }
144 }
145
146
147 static void DisplayHiredMercs(void);
148
149
RenderMercsAccount()150 void RenderMercsAccount()
151 {
152 ST::string sText;
153
154 DrawMecBackGround();
155
156 BltVideoObject(FRAME_BUFFER, guiMercOrderGrid, 0, MERC_AC_ORDER_GRID_X, MERC_AC_ORDER_GRID_Y);
157 BltVideoObject(FRAME_BUFFER, guiAccountNumberGrid, 0, MERC_AC_ACCOUNT_NUMBER_X, MERC_AC_ACCOUNT_NUMBER_Y);
158
159 //Display Players account number
160 sText = ST::format("{} {05d}", MercAccountText[MERC_ACCOUNT_ACCOUNT], LaptopSaveInfo.guiPlayersMercAccountNumber);
161 DrawTextToScreen(sText, MERC_AC_ACCOUNT_NUMBER_TEXT_X, MERC_AC_ACCOUNT_NUMBER_TEXT_Y, 0, MERC_ACCOUNT_TEXT_FONT, MERC_ACCOUNT_TEXT_COLOR, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
162
163 //Display the order grid titles
164 DrawTextToScreen(MercAccountText[MERC_ACCOUNT_MERC], MERC_AC_FIRST_COLUMN_X, MERC_AC_MERC_TITLE_Y, MERC_AC_FIRST_COLUMN_WIDTH, MERC_ACCOUNT_TEXT_FONT, MERC_ACCOUNT_TEXT_COLOR, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
165 DrawTextToScreen(MercAccountText[MERC_ACCOUNT_DAYS], MERC_AC_SECOND_COLUMN_X, MERC_AC_MERC_TITLE_Y, MERC_AC_SECOND_COLUMN_WIDTH, MERC_ACCOUNT_TEXT_FONT, MERC_ACCOUNT_TEXT_COLOR, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
166 DrawTextToScreen(MercAccountText[MERC_ACCOUNT_RATE], MERC_AC_THIRD_COLUMN_X, MERC_AC_MERC_TITLE_Y, MERC_AC_THIRD_COLUMN_WIDTH, MERC_ACCOUNT_TEXT_FONT, MERC_ACCOUNT_TEXT_COLOR, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
167 DrawTextToScreen(MercAccountText[MERC_ACCOUNT_CHARGE], MERC_AC_FOURTH_COLUMN_X, MERC_AC_MERC_TITLE_Y, MERC_AC_FOURTH_COLUMN_WIDTH, MERC_ACCOUNT_TEXT_FONT, MERC_ACCOUNT_TEXT_COLOR, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
168 DrawTextToScreen(MercAccountText[MERC_ACCOUNT_TOTAL], MERC_AC_THIRD_COLUMN_X, MERC_AC_TOTAL_COST_Y, MERC_AC_THIRD_COLUMN_WIDTH, MERC_ACCOUNT_TEXT_FONT, MERC_ACCOUNT_TEXT_COLOR, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
169
170 DisplayHiredMercs();
171
172 // giMercTotalContractCharge gets set with the price in DisplayHiredMercs(), so if there is currently no charge, disable the button
173 if( giMercTotalContractCharge == 0 )
174 {
175 DisableButton( guiMercAuthorizeBoxButton );
176 }
177
178
179
180 MarkButtonsDirty( );
181 RenderWWWProgramTitleBar( );
182 InvalidateRegion(LAPTOP_SCREEN_UL_X,LAPTOP_SCREEN_WEB_UL_Y,LAPTOP_SCREEN_LR_X,LAPTOP_SCREEN_WEB_LR_Y);
183 }
184
185
186 static void MercAuthorizePaymentMessageBoxCallBack(MessageBoxReturnValue);
187
188
BtnMercAuthorizeButtonCallback(GUI_BUTTON * btn,INT32 reason)189 static void BtnMercAuthorizeButtonCallback(GUI_BUTTON *btn, INT32 reason)
190 {
191 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
192 {
193 ST::string wzAuthorizeString;
194 ST::string wzDollarAmount;
195
196 wzDollarAmount = SPrintMoney(giMercTotalContractCharge);
197
198 //create the string to show to the user
199 wzAuthorizeString = st_format_printf(MercAccountText[MERC_ACCOUNT_AUTHORIZE_CONFIRMATION], wzDollarAmount);
200
201 DoLapTopMessageBox(MSG_BOX_BLUE_ON_GREY, wzAuthorizeString, LAPTOP_SCREEN, MSG_BOX_FLAG_YESNO, MercAuthorizePaymentMessageBoxCallBack);
202 }
203 }
204
205
BtnMercBackButtonCallback(GUI_BUTTON * btn,INT32 reason)206 static void BtnMercBackButtonCallback(GUI_BUTTON *btn, INT32 reason)
207 {
208 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
209 {
210 guiCurrentLaptopMode = LAPTOP_MODE_MERC;
211 gubArrivedFromMercSubSite = MERC_CAME_FROM_ACCOUNTS_PAGE;
212 }
213 }
214
215
DisplayHiredMercs(void)216 static void DisplayHiredMercs(void)
217 {
218 UINT16 usPosY;
219 UINT32 uiContractCharge;
220 ST::string sTemp;
221 UINT8 ubFontColor;
222
223 giMercTotalContractCharge = 0;
224
225 usPosY = MERC_AC_FIRST_ROW_Y + 3;
226 for (const MERCListingModel* m : GCM->getMERCListings())
227 {
228 ProfileID const pid = GetProfileIDFromMERCListing(m);
229 MERCPROFILESTRUCT const& p = GetProfile(pid);
230
231 //is the merc on the team, or is owed money
232 if (IsMercOnTeam(pid) || p.iMercMercContractLength != 0)
233 {
234 //if the merc is dead, make the color red, else white
235 if (IsMercDead(p))
236 ubFontColor = MERC_ACCOUNT_DEAD_TEXT_COLOR;
237 else
238 ubFontColor = MERC_ACCOUNT_DYNAMIC_TEXT_COLOR;
239
240 //Display Mercs Name
241 DrawTextToScreen(p.zName, MERC_AC_FIRST_COLUMN_X + 5, usPosY, MERC_AC_FIRST_COLUMN_WIDTH, MERC_ACCOUNT_DYNAMIC_TEXT_FONT, ubFontColor, FONT_MCOLOR_BLACK, LEFT_JUSTIFIED);
242
243 //Display The # of days the merc has worked since last paid
244
245 sTemp = ST::format("{}", p.iMercMercContractLength);
246 DrawTextToScreen(sTemp, MERC_AC_SECOND_COLUMN_X, usPosY, MERC_AC_SECOND_COLUMN_WIDTH, MERC_ACCOUNT_DYNAMIC_TEXT_FONT, ubFontColor, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
247
248 //Display the mercs rate
249 sTemp = ST::format("${6d}", p.sSalary);
250 DrawTextToScreen(sTemp, MERC_AC_THIRD_COLUMN_X, usPosY, MERC_AC_THIRD_COLUMN_WIDTH, MERC_ACCOUNT_DYNAMIC_TEXT_FONT, ubFontColor, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
251
252 //Display the total charge
253 uiContractCharge = p.sSalary * p.iMercMercContractLength;
254 sTemp = ST::format("${6d}", uiContractCharge);
255 DrawTextToScreen(sTemp, MERC_AC_FOURTH_COLUMN_X, usPosY, MERC_AC_FOURTH_COLUMN_WIDTH, MERC_ACCOUNT_DYNAMIC_TEXT_FONT, ubFontColor, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
256
257 giMercTotalContractCharge += uiContractCharge;
258 usPosY += MERC_AC_ROW_SIZE;
259 }
260 }
261
262 sTemp = ST::format("${6d}", giMercTotalContractCharge);
263 DrawTextToScreen(sTemp, MERC_AC_FOURTH_COLUMN_X, MERC_AC_TOTAL_COST_Y, MERC_AC_FOURTH_COLUMN_WIDTH, MERC_ACCOUNT_DYNAMIC_TEXT_FONT, MERC_ACCOUNT_DYNAMIC_TEXT_COLOR, FONT_MCOLOR_BLACK, CENTER_JUSTIFIED);
264 }
265
266
SettleMercAccounts(void)267 static void SettleMercAccounts(void)
268 {
269 //SOLDIERTYPE *pSoldier;
270 INT32 iPartialPayment=0;
271 INT32 iContractCharge=0;
272
273
274 //loop through all the MERC mercs the player has on the team
275 for (const MERCListingModel* m : GCM->getMERCListings())
276 {
277 ProfileID ubMercID = GetProfileIDFromMERCListing(m);
278
279 //if the merc is on the team, or does the player owe money for a fired merc
280 if( IsMercOnTeam( ubMercID ) || ( gMercProfiles[ ubMercID ].iMercMercContractLength != 0 ) )
281 {
282 //Calc the contract charge
283 iContractCharge = gMercProfiles[ ubMercID ].sSalary * gMercProfiles[ ubMercID ].iMercMercContractLength;
284
285 //if the player can afford to pay this merc
286 if( LaptopSaveInfo.iCurrentBalance >= iPartialPayment + iContractCharge )
287 {
288 //Then reset the merc contract counter
289 gMercProfiles[ ubMercID ].iMercMercContractLength = 0;
290
291 //Add this mercs contract charge to the total
292 iPartialPayment += iContractCharge;
293
294 gMercProfiles[ ubMercID ].uiTotalCostToDate += iContractCharge;
295 }
296 }
297 }
298
299 if( iPartialPayment == 0 )
300 {
301 //if true, will display a msgbox telling user that they dont have enough funds
302 gfMercPlayerDoesntHaveEnoughMoney_DisplayWarning = TRUE;
303 return;
304 }
305
306 // add the transaction to the finance page
307 AddTransactionToPlayersBook( PAY_SPECK_FOR_MERC, GetProfileIDFromMERCListingIndex( gubCurMercIndex ), GetWorldTotalMin(), -iPartialPayment );
308 AddHistoryToPlayersLog( HISTORY_SETTLED_ACCOUNTS_AT_MERC, GetProfileIDFromMERCListingIndex( gubCurMercIndex ), GetWorldTotalMin(), -1, -1 );
309
310 //Increment the amount of money paid to speck
311 LaptopSaveInfo.uiTotalMoneyPaidToSpeck += iPartialPayment;
312
313 //If the player only made a partial payment
314 if( iPartialPayment != giMercTotalContractCharge )
315 gusMercVideoSpeckSpeech = SPECK_QUOTE_PLAYER_MAKES_PARTIAL_PAYMENT;
316 else
317 {
318 gusMercVideoSpeckSpeech = SPECK_QUOTE_PLAYER_MAKES_FULL_PAYMENT;
319
320 //if the merc's account was in suspense, re-enable it
321 // CJC Dec 1 2002: an invalid account become valid again.
322 //if( LaptopSaveInfo.gubPlayersMercAccountStatus != MERC_ACCOUNT_INVALID )
323 LaptopSaveInfo.gubPlayersMercAccountStatus = MERC_ACCOUNT_VALID;
324
325
326 // Since the player has paid, make sure speck wont complain about the lack of payment
327 LaptopSaveInfo.uiSpeckQuoteFlags &= ~SPECK_QUOTE__SENT_EMAIL_ABOUT_LACK_OF_PAYMENT;
328 }
329
330 //Go to the merc homepage to say the quote
331 guiCurrentLaptopMode = LAPTOP_MODE_MERC;
332 gubArrivedFromMercSubSite = MERC_CAME_FROM_ACCOUNTS_PAGE;
333
334
335 /*
336 //if the player doesnt have enough money to fully pay for the all the mercs contract
337 if( LaptopSaveInfo.iCurrentBalance < giMercTotalContractCharge )
338 {
339 INT32 iPartialPayment=0;
340 INT32 iContractCharge=0;
341
342 //try to make a partial payment by looping through all the mercs and settling them 1 at a time
343 for(i=0; i<NUMBER_OF_MERCS; i++)
344 {
345 ubMercID = GetMercIDFromMERCArray( (UINT8) i );
346
347 //if the merc is on the team
348 if( IsMercOnTeam( ubMercID ) )
349 {
350 SOLDIERTYPE* const pSoldier = FindSoldierByProfileIDOnPlayerTeam(ubMercID);
351
352 //if we can get the soldier pointer
353 if( pSoldier == NULL )
354 continue;
355
356 //Calc the contract charge
357 iContractCharge = gMercProfiles[ ubMercID ].sSalary * pSoldier->iTotalContractLength;
358
359 //if the player can afford to pay this merc
360 if( LaptopSaveInfo.iCurrentBalance > iContractCharge )
361 {
362 pSoldier = FindSoldierByProfileIDOnPlayerTeam(ubMercID);
363 pSoldier->iTotalContractLength = 0;
364
365 iPartialPayment += iContractCharge;
366 }
367 }
368 }
369
370 if( iPartialPayment != 0 )
371 {
372 // add the transaction to the finance page
373 AddTransactionToPlayersBook( PAY_SPECK_FOR_MERC, GetMercIDFromMERCArray( gubCurMercIndex ), GetWorldTotalMin(), -iPartialPayment );
374 AddHistoryToPlayersLog( HISTORY_SETTLED_ACCOUNTS_AT_MERC, GetMercIDFromMERCArray( gubCurMercIndex ), GetWorldTotalMin(), -1, -1 );
375 }
376
377
378 //DoLapTopMessageBox( MSG_BOX_BLUE_ON_GREY, MercAccountText[MERC_ACCOUNT_NOT_ENOUGH_MONEY], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL);
379 //return to the main page and have speck say quote
380 guiCurrentLaptopMode = LAPTOP_MODE_MERC;
381 gubArrivedFromMercSubSite = MERC_CAME_FROM_ACCOUNTS_PAGE;
382
383 gusMercVideoSpeckSpeech = SPECK_QUOTE_PLAYER_MAKES_PARTIAL_PAYMENT;
384
385 return;
386 }
387
388 // add the transaction to the finance page
389 AddTransactionToPlayersBook( PAY_SPECK_FOR_MERC, GetMercIDFromMERCArray( gubCurMercIndex ), GetWorldTotalMin(), -giMercTotalContractCharge);
390 AddHistoryToPlayersLog( HISTORY_SETTLED_ACCOUNTS_AT_MERC, GetMercIDFromMERCArray( gubCurMercIndex ), GetWorldTotalMin(), -1, -1 );
391
392 //reset all the mercs time
393 for(i=0; i<NUMBER_OF_MERCS; i++)
394 {
395 ubMercID = GetMercIDFromMERCArray( (UINT8) i );
396
397 if( IsMercOnTeam( ubMercID ) )
398 {
399 pSoldier = FindSoldierByProfileIDOnPlayerTeam(ubMercID);
400 pSoldier->iTotalContractLength = 0;
401 }
402 }
403
404 //if the merc's account was in suspense, re-enable it
405 if( LaptopSaveInfo.gubPlayersMercAccountStatus != MERC_ACCOUNT_INVALID )
406 LaptopSaveInfo.gubPlayersMercAccountStatus = MERC_ACCOUNT_VALID;
407
408
409 //Go to the merc homepage to say the quote
410 guiCurrentLaptopMode = LAPTOP_MODE_MERC;
411 gubArrivedFromMercSubSite = MERC_CAME_FROM_ACCOUNTS_PAGE;
412 gusMercVideoSpeckSpeech = SPECK_QUOTE_PLAYER_MAKES_FULL_PAYMENT;*/
413 }
414
415
MercAuthorizePaymentMessageBoxCallBack(MessageBoxReturnValue const bExitValue)416 static void MercAuthorizePaymentMessageBoxCallBack(MessageBoxReturnValue const bExitValue)
417 {
418 // yes, clear the form
419 if( bExitValue == MSG_BOX_RETURN_YES )
420 {
421 //if the player owes Speck money, then settle the accounts
422 if( giMercTotalContractCharge )
423 SettleMercAccounts();
424 }
425 }
426
427
CalculateHowMuchPlayerOwesSpeck()428 UINT32 CalculateHowMuchPlayerOwesSpeck()
429 {
430 UINT32 uiContractCharge=0;
431 for (auto m : GCM->getMERCListings())
432 {
433 ProfileID usMercID = GetProfileIDFromMERCListing(m);
434 //Calc salary for the # of days the merc has worked since last paid
435 uiContractCharge += gMercProfiles[ usMercID ].sSalary * gMercProfiles[ usMercID ].iMercMercContractLength;
436 }
437
438 return( uiContractCharge );
439 }
440