1 #include "Directories.h"
2 #include "Font.h"
3 #include "Laptop.h"
4 #include "Finances.h"
5 #include "Game_Clock.h"
6 #include "LoadSaveData.h"
7 #include "Map_Screen_Interface_Bottom.h"
8 #include "VObject.h"
9 #include "Debug.h"
10 #include "Render_Dirty.h"
11 #include "Cursors.h"
12 #include "Soldier_Profile.h"
13 #include "Text.h"
14 #include "Strategic_Mines.h"
15 #include "LaptopSave.h"
16 #include "Campaign_Types.h"
17 #include "StrategicMap.h"
18 #include "VSurface.h"
19 #include "MemMan.h"
20 #include "Button_System.h"
21 #include "Font_Control.h"
22 #include "FileMan.h"
23 
24 #include "ContentManager.h"
25 #include "GameInstance.h"
26 
27 #include <string_theory/format>
28 #include <string_theory/string>
29 
30 
31 #define FINANCE_HEADER_SIZE 4
32 #define FINANCE_RECORD_SIZE (1 + 1 + 4 + 4 + 4)
33 
34 
35 // the financial structure
36 struct FinanceUnit
37 {
38 	UINT8 ubCode; // the code index in the finance code table
39 	UINT8 ubSecondCode; // secondary code
40 	UINT32 uiDate; // time in the world in global time
41 	INT32 iAmount; // the amount of the transaction
42 	INT32 iBalanceToDate;
43 	FinanceUnit* Next; // next unit in the list
44 };
45 
46 
47 // the global defines
48 
49 // graphical positions
50 #define TOP_X 0+LAPTOP_SCREEN_UL_X
51 #define TOP_Y LAPTOP_SCREEN_UL_Y
52 #define BLOCK_HEIGHT 10
53 #define TOP_DIVLINE_Y (102 + STD_SCREEN_Y)
54 #define DIVLINE_X (130 + STD_SCREEN_X)
55 #define MID_DIVLINE_Y (205 + STD_SCREEN_Y)
56 #define BOT_DIVLINE_Y (180 + STD_SCREEN_Y)
57 #define MID_DIVLINE_Y2 (263 + 20 + STD_SCREEN_Y)
58 #define BOT_DIVLINE_Y2 MID_DIVLINE_Y2 + MID_DIVLINE_Y - BOT_DIVLINE_Y
59 #define TITLE_X (140 + STD_SCREEN_X)
60 #define TITLE_Y (33 + STD_SCREEN_Y)
61 #define TEXT_X (140 + STD_SCREEN_X)
62 #define PAGE_SIZE 17
63 
64 // yesterdyas/todays income and balance text positions
65 #define YESTERDAYS_INCOME               (STD_SCREEN_Y + 114)
66 #define YESTERDAYS_OTHER                (STD_SCREEN_Y + 138)
67 #define YESTERDAYS_DEBITS               (STD_SCREEN_Y + 162)
68 #define YESTERDAYS_BALANCE              (STD_SCREEN_Y + 188)
69 #define TODAYS_INCOME                   (STD_SCREEN_Y + 215)
70 #define TODAYS_OTHER                    (STD_SCREEN_Y + 239)
71 #define TODAYS_DEBITS                   (STD_SCREEN_Y + 263)
72 #define TODAYS_CURRENT_BALANCE          (STD_SCREEN_Y + 263 + 28)
73 #define TODAYS_CURRENT_FORCAST_INCOME   (STD_SCREEN_Y + 330)
74 #define TODAYS_CURRENT_FORCAST_BALANCE  (STD_SCREEN_Y + 354)
75 #define FINANCE_HEADER_FONT FONT14ARIAL
76 #define FINANCE_TEXT_FONT FONT12ARIAL
77 #define NUM_RECORDS_PER_PAGE PAGE_SIZE
78 
79 // records text positions
80 #define RECORD_CREDIT_WIDTH (106-47)
81 #define RECORD_DEBIT_WIDTH RECORD_CREDIT_WIDTH
82 #define RECORD_DATE_X TOP_X+10
83 #define RECORD_TRANSACTION_X RECORD_DATE_X+RECORD_DATE_WIDTH
84 #define RECORD_TRANSACTION_WIDTH 500-280
85 #define RECORD_DEBIT_X RECORD_TRANSACTION_X+RECORD_TRANSACTION_WIDTH
86 #define RECORD_CREDIT_X RECORD_DEBIT_X+RECORD_DEBIT_WIDTH
87 #define RECORD_Y (107-10 + STD_SCREEN_Y)
88 #define RECORD_DATE_WIDTH 47
89 #define RECORD_BALANCE_X RECORD_DATE_X+385
90 #define RECORD_BALANCE_WIDTH 479-385
91 #define RECORD_HEADER_Y (90 + STD_SCREEN_Y)
92 
93 
94 #define PAGE_NUMBER_X TOP_X+297 //345
95 #define PAGE_NUMBER_Y TOP_Y+33
96 
97 
98 // BUTTON defines
99 enum{
100 	PREV_PAGE_BUTTON=0,
101 	NEXT_PAGE_BUTTON,
102 	FIRST_PAGE_BUTTON,
103 	LAST_PAGE_BUTTON,
104 };
105 
106 
107 // button positions
108 
109 #define FIRST_PAGE_X	(STD_SCREEN_X + 505)
110 #define NEXT_BTN_X	(STD_SCREEN_X + 553)
111 #define PREV_BTN_X	(STD_SCREEN_X + 529)
112 #define LAST_PAGE_X	(STD_SCREEN_X + 577)
113 #define BTN_Y		(STD_SCREEN_Y +  53)
114 
115 
116 
117 // sizeof one record
118 #define RECORD_SIZE ( sizeof( UINT32 ) + sizeof( INT32 ) + sizeof( INT32 ) + sizeof( UINT8 ) + sizeof( UINT8 ) )
119 
120 
121 
122 
123 // the financial record list
124 static FinanceUnit* pFinanceListHead = NULL;
125 
126 // current page displayed
127 static INT32 iCurrentPage = 0;
128 
129 // video object id's
130 static SGPVObject* guiTITLE;
131 static SGPVObject* guiTOP;
132 static SGPVObject* guiLINE;
133 static SGPVObject* guiLONGLINE;
134 static SGPVObject* guiLISTCOLUMNS;
135 
136 // are in the financial system right now?
137 static BOOLEAN fInFinancialMode = FALSE;
138 
139 
140 // the last page altogether
141 static UINT32 guiLastPageInRecordsList = 0;
142 
143 // finance screen buttons
144 static GUIButtonRef giFinanceButton[4];
145 static BUTTON_PICS* giFinanceButtonImage[4];
146 static MOUSE_REGION g_scroll_region;
147 
148 // internal functions
149 static void ProcessAndEnterAFinacialRecord(UINT8 ubCode, UINT32 uiDate, INT32 iAmount, UINT8 ubSecondCode, INT32 iBalanceToDate);
150 static void LoadFinances(void);
151 static void RemoveFinances(void);
152 static void ClearFinanceList(void);
153 static void DrawRecordsColumnHeadersText(void);
154 static void CreateFinanceButtons(void);
155 static void DestroyFinanceButtons(void);
156 static void GetBalanceFromDisk(void);
157 static void WriteBalanceToDisk(void);
158 static void AppendFinanceToEndOfFile(void);
159 static void SetLastPageInRecords(void);
160 static void LoadInRecords(UINT32 page);
161 
162 static void SetFinanceButtonStates(void);
163 static INT32 GetTodaysDebits(void);
164 static INT32 GetYesterdaysDebits(void);
165 
166 
AddTransactionToPlayersBook(UINT8 ubCode,UINT8 ubSecondCode,UINT32 uiDate,INT32 iAmount)167 void AddTransactionToPlayersBook(UINT8 ubCode, UINT8 ubSecondCode, UINT32 uiDate, INT32 iAmount)
168 {
169 	// adds transaction to player's book(Financial List)
170 	// outside of the financial system(the code in this .c file), this is the only function you'll ever need
171 
172 	// read in balance from file
173 
174 	GetBalanceFromDisk( );
175 	// process the actual data
176 
177 
178 	//
179 	// If this transaction is for the hiring/extending of a mercs contract
180 	//
181 	if( ubCode == HIRED_MERC ||
182 			ubCode == IMP_PROFILE ||
183 			ubCode == PAYMENT_TO_NPC ||
184 			ubCode == EXTENDED_CONTRACT_BY_1_DAY ||
185 			ubCode == EXTENDED_CONTRACT_BY_1_WEEK ||
186 			ubCode == EXTENDED_CONTRACT_BY_2_WEEKS
187 		)
188 	{
189 		gMercProfiles[ ubSecondCode ].uiTotalCostToDate += -iAmount;
190 	}
191 
192 	// clear list
193 	ClearFinanceList( );
194 
195 	// update balance
196 	LaptopSaveInfo.iCurrentBalance += iAmount;
197 
198 	ProcessAndEnterAFinacialRecord(ubCode, uiDate, iAmount, ubSecondCode, LaptopSaveInfo.iCurrentBalance);
199 
200 	// write balance to disk
201 	WriteBalanceToDisk( );
202 
203 	// append to end of file
204 	AppendFinanceToEndOfFile();
205 
206 	// set number of pages
207 	SetLastPageInRecords( );
208 
209 	if( !fInFinancialMode )
210 	{
211 		ClearFinanceList( );
212 	}
213 	else
214 	{
215 		SetFinanceButtonStates( );
216 
217 		// force update
218 		fPausedReDrawScreenFlag = TRUE;
219 	}
220 
221 	fMapScreenBottomDirty = TRUE;
222 }
223 
224 
GetCurrentBalance(void)225 INT32 GetCurrentBalance( void )
226 {
227 	// get balance to this minute
228 	return ( LaptopSaveInfo.iCurrentBalance );
229 }
230 
231 
GetProjectedTotalDailyIncome(void)232 INT32 GetProjectedTotalDailyIncome( void )
233 {
234 	// return total  projected income, including what is earned today already
235 
236 	// CJC: I DON'T THINK SO!
237 	// The point is:  PredictIncomeFromPlayerMines isn't dependant on the time of day
238 	// (anymore) and this would report income of 0 at midnight!
239 	/*
240 	if (GetWorldMinutesInDay() <= 0)
241 	{
242 		return ( 0 );
243 	}
244 	*/
245 	// look at we earned today
246 
247 	// then there is how many deposits have been made, now look at how many mines we have, thier rate, amount of ore left and predict if we still
248 	// had these mines how much more would we get?
249 
250 	return( PredictIncomeFromPlayerMines() );
251 }
252 
253 
GameInitFinances()254 void GameInitFinances()
255 {
256 	// initialize finances on game start up
257 	GCM->deleteTempFile(NEWTMP_FINANCES_DATA_FILE);
258 	GetBalanceFromDisk( );
259 }
260 
EnterFinances()261 void EnterFinances()
262 {
263 	//entry into finanacial system, load graphics, set variables..draw screen once
264 	// set the fact we are in the financial display system
265 
266 	fInFinancialMode=TRUE;
267 
268 	// get the balance
269 	GetBalanceFromDisk( );
270 
271 	// set number of pages
272 	SetLastPageInRecords( );
273 
274 	// load graphics into memory
275 	LoadFinances( );
276 
277 	// create buttons
278 	CreateFinanceButtons( );
279 
280 	// reset page we are on
281 	LoadInRecords(LaptopSaveInfo.iCurrentFinancesPage);
282 
283 	RenderFinances( );
284 }
285 
ExitFinances(void)286 void ExitFinances( void )
287 {
288 	LaptopSaveInfo.iCurrentFinancesPage = iCurrentPage;
289 
290 
291 	// not in finance system anymore
292 	fInFinancialMode=FALSE;
293 
294 	// destroy buttons
295 	DestroyFinanceButtons( );
296 
297 	// clear out list
298 	ClearFinanceList( );
299 
300 
301 	// remove graphics
302 	RemoveFinances( );
303 }
304 
305 
306 static void DisplayFinancePageNumberAndDateRange(void);
307 static void DrawAPageOfRecords(void);
308 static void DrawFinanceTitleText(void);
309 static void DrawSummary(void);
310 static void RenderBackGround(void);
311 
312 
RenderFinances(void)313 void RenderFinances(void)
314 {
315 	RenderBackGround();
316 
317 	// if we are on the first page, draw the summary
318 	if(iCurrentPage==0)
319 		DrawSummary( );
320 	else
321 		DrawAPageOfRecords( );
322 
323 	DrawFinanceTitleText( );
324 
325 	DisplayFinancePageNumberAndDateRange( );
326 
327 	BltVideoObject(FRAME_BUFFER, guiLaptopBACKGROUND, 0, STD_SCREEN_X + 108, STD_SCREEN_Y + 23);
328 
329 	BlitTitleBarIcons(  );
330 }
331 
332 
LoadFinances(void)333 static void LoadFinances(void)
334 {
335 	// load Finance video objects into memory
336 
337 	// title bar
338 	guiTITLE = AddVideoObjectFromFile(LAPTOPDIR "/programtitlebar.sti");
339 
340 	// top portion of the screen background
341 	guiTOP = AddVideoObjectFromFile(LAPTOPDIR "/financeswindow.sti");
342 
343 	// black divider line - long ( 480 length)
344 	guiLONGLINE = AddVideoObjectFromFile(LAPTOPDIR "/divisionline480.sti");
345 
346 	// the records columns
347 	guiLISTCOLUMNS = AddVideoObjectFromFile(LAPTOPDIR "/recordcolumns.sti");
348 
349 	// black divider line - long ( 480 length)
350 	guiLINE = AddVideoObjectFromFile(LAPTOPDIR "/divisionline.sti");
351 }
352 
353 
RemoveFinances(void)354 static void RemoveFinances(void)
355 {
356 	// delete Finance video objects from memory
357 	DeleteVideoObject(guiLONGLINE);
358 	DeleteVideoObject(guiLINE);
359 	DeleteVideoObject(guiLISTCOLUMNS);
360 	DeleteVideoObject(guiTOP);
361 	DeleteVideoObject(guiTITLE);
362 }
363 
364 
RenderBackGround(void)365 static void RenderBackGround(void)
366 {
367 	// render generic background for Finance system
368 	BltVideoObject(FRAME_BUFFER, guiTITLE, 0, TOP_X, TOP_Y -  2);
369 	BltVideoObject(FRAME_BUFFER, guiTOP,   0, TOP_X, TOP_Y + 22);
370 }
371 
372 
373 static void DrawSummaryLines(void);
374 static void DrawSummaryText(void);
375 
376 
DrawSummary(void)377 static void DrawSummary(void)
378 {
379 	// draw day's summary to screen
380 	DrawSummaryLines( );
381 	DrawSummaryText( );
382 }
383 
384 
DrawSummaryLines(void)385 static void DrawSummaryLines(void)
386 {
387 	// draw divider lines on screen
388 	// blit summary LINE object to screen
389 	BltVideoObject(FRAME_BUFFER, guiLINE, 0,DIVLINE_X, TOP_DIVLINE_Y);
390 	BltVideoObject(FRAME_BUFFER, guiLINE, 0,DIVLINE_X, TOP_DIVLINE_Y+2);
391 	//BltVideoObject(FRAME_BUFFER, guiLINE, 0,DIVLINE_X, MID_DIVLINE_Y);
392 	BltVideoObject(FRAME_BUFFER, guiLINE, 0,DIVLINE_X, BOT_DIVLINE_Y);
393 	BltVideoObject(FRAME_BUFFER, guiLINE, 0,DIVLINE_X, MID_DIVLINE_Y2);
394 	//BltVideoObject(FRAME_BUFFER, guiLINE, 0,DIVLINE_X, BOT_DIVLINE_Y2);
395 }
396 
397 
398 static void DrawRecordsBackGround(void);
399 static void DrawRecordsText(void);
400 
401 
DrawAPageOfRecords(void)402 static void DrawAPageOfRecords(void)
403 {
404 	// this procedure will draw a series of financial records to the screen
405 
406 	// (re-)render background
407 	DrawRecordsBackGround( );
408 
409 	// error check
410 	if(iCurrentPage==-1)
411 		return;
412 
413 
414 	// current page is found, render  from here
415 	DrawRecordsText( );
416 }
417 
418 
DrawRecordsBackGround(void)419 static void DrawRecordsBackGround(void)
420 {
421 	// proceudre will draw the background for the list of financial records
422 	INT32 iCounter;
423 
424 	// now the columns
425 	for (iCounter = 6; iCounter < 35; iCounter++)
426 	{
427 		BltVideoObject(FRAME_BUFFER, guiLISTCOLUMNS, 0, TOP_X + 10, TOP_Y + 18 + iCounter * BLOCK_HEIGHT + 1);
428 	}
429 
430 	// the divisorLines
431 	BltVideoObject(FRAME_BUFFER, guiLONGLINE, 0, TOP_X + 10, TOP_Y + 17 + 6 * BLOCK_HEIGHT);
432 	BltVideoObject(FRAME_BUFFER, guiLONGLINE, 0, TOP_X + 10, TOP_Y + 19 + 6 * BLOCK_HEIGHT);
433 	BltVideoObject(FRAME_BUFFER, guiLONGLINE, 0, TOP_X + 10, TOP_Y + 19 + iCounter * BLOCK_HEIGHT);
434 
435 	// the header text
436 	DrawRecordsColumnHeadersText( );
437 }
438 
439 
DrawRecordsColumnHeadersText(void)440 static void DrawRecordsColumnHeadersText(void)
441 {
442 	// write the headers text for each column
443 	SetFontAttributes(FINANCE_TEXT_FONT, FONT_BLACK, NO_SHADOW);
444 
445 	INT16 usX;
446 	INT16 usY;
447 
448 	// the date header
449 	FindFontCenterCoordinates(RECORD_DATE_X,0,RECORD_DATE_WIDTH,0, pFinanceHeaders[0], FINANCE_TEXT_FONT,&usX, &usY);
450 	MPrint(usX, RECORD_HEADER_Y, pFinanceHeaders[0]);
451 
452 	// debit header
453 	FindFontCenterCoordinates(RECORD_DEBIT_X,0,RECORD_DEBIT_WIDTH,0, pFinanceHeaders[1], FINANCE_TEXT_FONT,&usX, &usY);
454 	MPrint(usX, RECORD_HEADER_Y, pFinanceHeaders[1]);
455 
456 	// credit header
457 	FindFontCenterCoordinates(RECORD_CREDIT_X,0,RECORD_CREDIT_WIDTH,0, pFinanceHeaders[2], FINANCE_TEXT_FONT,&usX, &usY);
458 	MPrint(usX, RECORD_HEADER_Y, pFinanceHeaders[2]);
459 
460 	// balance header
461 	FindFontCenterCoordinates(RECORD_BALANCE_X,0,RECORD_BALANCE_WIDTH,0, pFinanceHeaders[4], FINANCE_TEXT_FONT,&usX, &usY);
462 	MPrint(usX, RECORD_HEADER_Y, pFinanceHeaders[4]);
463 
464 	// transaction header
465 	FindFontCenterCoordinates(RECORD_TRANSACTION_X,0,RECORD_TRANSACTION_WIDTH,0, pFinanceHeaders[3], FINANCE_TEXT_FONT,&usX, &usY);
466 	MPrint(usX, RECORD_HEADER_Y, pFinanceHeaders[3]);
467 
468 	SetFontShadow(DEFAULT_SHADOW);
469 }
470 
471 
DrawStringCentered(INT32 x,INT32 y,INT32 w,const ST::string & str)472 static void DrawStringCentered(INT32 x, INT32 y, INT32 w, const ST::string& str)
473 {
474 	INT16 sx;
475 	INT16 sy;
476 	FindFontCenterCoordinates(x, 0, w, 0, str, FINANCE_TEXT_FONT, &sx, &sy);
477 	MPrint(sx, y, str);
478 }
479 
480 
481 static ST::string ProcessTransactionString(const FinanceUnit* pFinance);
482 
483 
484 // draws the text of the records
DrawRecordsText(void)485 static void DrawRecordsText(void)
486 {
487 	SetFont(FINANCE_TEXT_FONT);
488 	SetFontBackground(FONT_BLACK);
489 	SetFontShadow(NO_SHADOW);
490 
491 	const FinanceUnit* fu = pFinanceListHead;
492 	for (INT32 i = 0; i < NUM_RECORDS_PER_PAGE && fu != NULL; ++i, fu = fu->Next)
493 	{
494 		const INT32 y = 12 + RECORD_Y + i * (GetFontHeight(FINANCE_TEXT_FONT) + 6);
495 
496 		SetFontForeground(FONT_BLACK);
497 
498 		// get and write the date
499 		DrawStringCentered(RECORD_DATE_X, y, RECORD_DATE_WIDTH, ST::format("{}", fu->uiDate / (24 * 60)));
500 
501 		// get and write debit/credit
502 		if (fu->iAmount >= 0)
503 		{
504 			// increase in asset - debit
505 			DrawStringCentered(RECORD_DEBIT_X, y, RECORD_DEBIT_WIDTH, SPrintMoney(fu->iAmount));
506 		}
507 		else
508 		{
509 			// decrease in asset - credit
510 			SetFontForeground(FONT_RED);
511 			DrawStringCentered(RECORD_CREDIT_X, y, RECORD_CREDIT_WIDTH, SPrintMoney(-fu->iAmount));
512 		}
513 
514 		// the balance to this point
515 		INT32 balance = fu->iBalanceToDate;
516 		if (balance >= 0)
517 		{
518 			SetFontForeground(FONT_BLACK);
519 		}
520 		else
521 		{
522 			SetFontForeground(FONT_RED);
523 			balance = -balance;
524 		}
525 		DrawStringCentered(RECORD_BALANCE_X, y, RECORD_BALANCE_WIDTH, SPrintMoney(balance));
526 
527 		// transaction string
528 		DrawStringCentered(RECORD_TRANSACTION_X, y, RECORD_TRANSACTION_WIDTH, ProcessTransactionString(fu));
529 	}
530 }
531 
532 
DrawFinanceTitleText(void)533 static void DrawFinanceTitleText(void)
534 {
535 	// draw the pages title
536 	SetFontAttributes(FINANCE_HEADER_FONT, FONT_WHITE);
537 	MPrint(TITLE_X, TITLE_Y, pFinanceTitle);
538 }
539 
540 
541 static INT32 GetPreviousDaysIncome(void);
542 static INT32 GetTodaysBalance(void);
543 static INT32 GetTodaysDaysIncome(void);
544 static INT32 GetTodaysOtherDeposits(void);
545 static INT32 GetYesterdaysOtherDeposits(void);
546 static ST::string SPrintMoneyNoDollarOnZero(INT32 Amount);
547 
548 
DrawSummaryText(void)549 static void DrawSummaryText(void)
550 {
551 	INT16 usX, usY;
552 	ST::string pString;
553 	INT32 iBalance = 0;
554 
555 	SetFontAttributes(FINANCE_TEXT_FONT, FONT_BLACK, NO_SHADOW);
556 
557 	// draw summary text to the screen
558 	MPrint(TEXT_X, YESTERDAYS_INCOME,              pFinanceSummary[2]);
559 	MPrint(TEXT_X, YESTERDAYS_OTHER,               pFinanceSummary[3]);
560 	MPrint(TEXT_X, YESTERDAYS_DEBITS,              pFinanceSummary[4]);
561 	MPrint(TEXT_X, YESTERDAYS_BALANCE,             pFinanceSummary[5]);
562 	MPrint(TEXT_X, TODAYS_INCOME,                  pFinanceSummary[6]);
563 	MPrint(TEXT_X, TODAYS_OTHER,                   pFinanceSummary[7]);
564 	MPrint(TEXT_X, TODAYS_DEBITS,                  pFinanceSummary[8]);
565 	MPrint(TEXT_X, TODAYS_CURRENT_BALANCE,         pFinanceSummary[9]);
566 	MPrint(TEXT_X, TODAYS_CURRENT_FORCAST_INCOME,  pFinanceSummary[10]);
567 	MPrint(TEXT_X, TODAYS_CURRENT_FORCAST_BALANCE, pFinanceSummary[11]);
568 
569 	// draw the actual numbers
570 
571 
572 
573 	// yesterdays income
574 	pString = SPrintMoneyNoDollarOnZero(GetPreviousDaysIncome());
575 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
576 	MPrint(usX, YESTERDAYS_INCOME, pString);
577 
578 	SetFontForeground( FONT_BLACK );
579 
580 	// yesterdays other
581 	pString = SPrintMoneyNoDollarOnZero(GetYesterdaysOtherDeposits());
582 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
583 	MPrint(usX, YESTERDAYS_OTHER, pString);
584 
585 	SetFontForeground( FONT_RED );
586 
587 	// yesterdays debits
588 	iBalance =  GetYesterdaysDebits( );
589 	if( iBalance < 0 )
590 	{
591 		SetFontForeground( FONT_RED );
592 		iBalance *= -1;
593 	}
594 
595 	pString = SPrintMoneyNoDollarOnZero(iBalance);
596 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
597 	MPrint(usX, YESTERDAYS_DEBITS, pString);
598 
599 	SetFontForeground( FONT_BLACK );
600 
601 	// yesterdays balance..ending balance..so todays balance then
602 	iBalance =  GetTodaysBalance( );
603 
604 	if( iBalance < 0 )
605 	{
606 		SetFontForeground( FONT_RED );
607 		iBalance *= -1;
608 	}
609 
610 	pString = SPrintMoneyNoDollarOnZero(iBalance);
611 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
612 	MPrint(usX, YESTERDAYS_BALANCE, pString);
613 
614 	SetFontForeground( FONT_BLACK );
615 
616 	// todays income
617 	pString = SPrintMoneyNoDollarOnZero(GetTodaysDaysIncome());
618 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
619 	MPrint(usX, TODAYS_INCOME, pString);
620 
621 	SetFontForeground( FONT_BLACK );
622 
623 	// todays other
624 	pString = SPrintMoneyNoDollarOnZero(GetTodaysOtherDeposits());
625 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
626 	MPrint(usX, TODAYS_OTHER, pString);
627 
628 	SetFontForeground( FONT_RED );
629 
630 	// todays debits
631 	iBalance =  GetTodaysDebits( );
632 
633 	// absolute value
634 	if( iBalance < 0 )
635 	{
636 		iBalance *= ( -1 );
637 	}
638 
639 	pString = SPrintMoneyNoDollarOnZero(iBalance);
640 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
641 	MPrint(usX, TODAYS_DEBITS, pString);
642 
643 	SetFontForeground( FONT_BLACK );
644 
645 	// todays current balance
646 	iBalance = GetCurrentBalance( );
647 	if( iBalance < 0 )
648 	{
649 		iBalance *= -1;
650 		SetFontForeground( FONT_RED );
651 	}
652 
653 	pString = SPrintMoneyNoDollarOnZero(iBalance);
654 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
655 	MPrint(usX, TODAYS_CURRENT_BALANCE, pString);
656 
657 	SetFontForeground( FONT_BLACK );
658 
659 	// todays forcast income
660 	pString = SPrintMoneyNoDollarOnZero(GetProjectedTotalDailyIncome());
661 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
662 	MPrint(usX, TODAYS_CURRENT_FORCAST_INCOME, pString);
663 
664 	SetFontForeground( FONT_BLACK );
665 
666 
667 	// todays forcast balance
668 	iBalance = GetCurrentBalance( ) + GetProjectedTotalDailyIncome( );
669 	if( iBalance < 0 )
670 	{
671 		iBalance *= -1;
672 		SetFontForeground( FONT_RED );
673 	}
674 
675 	pString = SPrintMoneyNoDollarOnZero(iBalance);
676 	FindFontRightCoordinates(STD_SCREEN_X, 0, 580, 0,pString,FINANCE_TEXT_FONT, &usX, &usY);
677 	MPrint(usX, TODAYS_CURRENT_FORCAST_BALANCE, pString);
678 
679 	SetFontForeground( FONT_BLACK );
680 
681 	// reset the shadow
682 	SetFontShadow(DEFAULT_SHADOW);
683 }
684 
685 
ClearFinanceList(void)686 static void ClearFinanceList(void)
687 {
688 	// remove each element from list of transactions
689 	FinanceUnit* pFinanceList = pFinanceListHead;
690 	FinanceUnit* pFinanceNode = pFinanceList;
691 
692 	// while there are elements in the list left, delete them
693 	while( pFinanceList )
694 	{
695 		// set node to list head
696 		pFinanceNode=pFinanceList;
697 
698 		// set list head to next node
699 		pFinanceList=pFinanceList->Next;
700 
701 		// delete current node
702 		delete pFinanceNode;
703 	}
704 	pFinanceListHead = NULL;
705 }
706 
707 
ProcessAndEnterAFinacialRecord(const UINT8 ubCode,const UINT32 uiDate,const INT32 iAmount,const UINT8 ubSecondCode,const INT32 iBalanceToDate)708 static void ProcessAndEnterAFinacialRecord(const UINT8 ubCode, const UINT32 uiDate, const INT32 iAmount, const UINT8 ubSecondCode, const INT32 iBalanceToDate)
709 {
710 	FinanceUnit* const fu = new FinanceUnit{};
711 	fu->Next           = NULL;
712 	fu->ubCode         = ubCode;
713 	fu->ubSecondCode   = ubSecondCode;
714 	fu->uiDate         = uiDate;
715 	fu->iAmount        = iAmount;
716 	fu->iBalanceToDate = iBalanceToDate;
717 
718 	// Append to end of list
719 	FinanceUnit** i = &pFinanceListHead;
720 	while (*i != NULL) i = &(*i)->Next;
721 	*i = fu;
722 }
723 
724 
725 static void LoadPreviousPage(void);
726 static void LoadNextPage(void);
727 
728 
ScrollRegionCallback(MOUSE_REGION * const,INT32 const reason)729 static void ScrollRegionCallback(MOUSE_REGION* const, INT32 const reason)
730 {
731 	if (reason & MSYS_CALLBACK_REASON_WHEEL_UP)
732 	{
733 		LoadPreviousPage();
734 	}
735 	else if (reason & MSYS_CALLBACK_REASON_WHEEL_DOWN)
736 	{
737 		LoadNextPage();
738 	}
739 }
740 
741 
BtnFinanceDisplayPrevPageCallBack(GUI_BUTTON * const,INT32 const reason)742 static void BtnFinanceDisplayPrevPageCallBack(GUI_BUTTON* const, INT32 const reason)
743 {
744 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
745 	{
746 		LoadPreviousPage();
747 	}
748 }
749 
750 
BtnFinanceDisplayNextPageCallBack(GUI_BUTTON * const,INT32 const reason)751 static void BtnFinanceDisplayNextPageCallBack(GUI_BUTTON* const, INT32 const reason)
752 {
753 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
754 	{
755 		LoadNextPage();
756 	}
757 }
758 
759 
BtnFinanceFirstPageCallBack(GUI_BUTTON * const,INT32 const reason)760 static void BtnFinanceFirstPageCallBack(GUI_BUTTON* const, INT32 const reason)
761 {
762 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
763 	{
764 		LoadInRecords(0);
765 	}
766 }
767 
768 
BtnFinanceLastPageCallBack(GUI_BUTTON * const,INT32 const reason)769 static void BtnFinanceLastPageCallBack(GUI_BUTTON* const, INT32 const reason)
770 {
771 	if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
772 	{
773 		LoadInRecords(guiLastPageInRecordsList + 1);
774 	}
775 }
776 
777 
MakeButton(size_t const idx,BUTTON_PICS * const img,INT16 const x,GUI_CALLBACK const callback)778 static void MakeButton(size_t const idx, BUTTON_PICS* const img, INT16 const x, GUI_CALLBACK const callback)
779 {
780 	giFinanceButtonImage[idx] = img;
781 	GUIButtonRef const btn    = QuickCreateButton(img, x, BTN_Y, MSYS_PRIORITY_HIGHEST - 1, callback);
782 	giFinanceButton[idx]      = btn;
783 	btn->SetCursor(CURSOR_LAPTOP_SCREEN);
784 }
785 
786 
CreateFinanceButtons(void)787 static void CreateFinanceButtons(void)
788 {
789 	BUTTON_PICS* const img = LoadButtonImage(LAPTOPDIR "/arrows.sti", 0, 1);
790 	MakeButton(PREV_PAGE_BUTTON,  img,                              PREV_BTN_X,   BtnFinanceDisplayPrevPageCallBack);
791 	MakeButton(NEXT_PAGE_BUTTON,  UseLoadedButtonImage(img, 6,  7), NEXT_BTN_X,   BtnFinanceDisplayNextPageCallBack);
792 	MakeButton(FIRST_PAGE_BUTTON, UseLoadedButtonImage(img, 3,  4), FIRST_PAGE_X, BtnFinanceFirstPageCallBack);
793 	MakeButton(LAST_PAGE_BUTTON,  UseLoadedButtonImage(img, 9, 10), LAST_PAGE_X,  BtnFinanceLastPageCallBack);
794 
795 	UINT16 const x = TOP_X +  8;
796 	UINT16 const y = TOP_Y + 53;
797 	UINT16 const w = 482;
798 	UINT16 const h = 354;
799 	MSYS_DefineRegion(&g_scroll_region, x, y, x + w, y + h, MSYS_PRIORITY_HIGH, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ScrollRegionCallback);
800 }
801 
802 
DestroyFinanceButtons(void)803 static void DestroyFinanceButtons(void)
804 {
805 	MSYS_RemoveRegion(&g_scroll_region);
806 	for (UINT32 i = 0; i != 4; ++i)
807 	{
808 		RemoveButton(giFinanceButton[i]);
809 		UnloadButtonImage(giFinanceButtonImage[i]);
810 	}
811 }
812 
813 
ProcessTransactionString(const FinanceUnit * f)814 static ST::string ProcessTransactionString(const FinanceUnit* f)
815 {
816 	UINT8 code = f->ubCode;
817 	switch (code)
818 	{
819 		case DEPOSIT_FROM_SILVER_MINE:
820 			code = DEPOSIT_FROM_GOLD_MINE;
821 			/* FALLTHROUGH */
822 
823 		case ACCRUED_INTEREST:
824 		case ANONYMOUS_DEPOSIT:
825 		case BOBBYR_PURCHASE:
826 		case DEPOSIT_FROM_GOLD_MINE:
827 		case IMP_PROFILE:
828 		case PAY_SPECK_FOR_MERC:
829 		case PURCHASED_FLOWERS:
830 		case TRANSACTION_FEE:
831 			return pTransactionText[code];
832 
833 		case CANCELLED_INSURANCE:
834 		case EXTENDED_CONTRACT_BY_1_DAY:
835 		case EXTENDED_CONTRACT_BY_1_WEEK:
836 		case EXTENDED_CONTRACT_BY_2_WEEKS:
837 		case EXTENDED_INSURANCE:
838 		case FULL_MEDICAL_REFUND:
839 		case HIRED_MERC:
840 		case INSURANCE_PAYOUT:
841 		case MEDICAL_DEPOSIT:
842 		case MERC_DEPOSITED_MONEY_TO_PLAYER_ACCOUNT:
843 		case NO_MEDICAL_REFUND:
844 		case PARTIAL_MEDICAL_REFUND:
845 		case PAYMENT_TO_NPC:
846 		case PURCHASED_INSURANCE:
847 		case PURCHASED_ITEM_FROM_DEALER:
848 		case REDUCED_INSURANCE:
849 		case TRANSFER_FUNDS_FROM_MERC:
850 		case TRANSFER_FUNDS_TO_MERC:
851 			return st_format_printf(pTransactionText[code], GetProfile(f->ubSecondCode).zNickname);
852 
853 		case TRAIN_TOWN_MILITIA:
854 		{
855 			const UINT8 ubSectorX = SECTORX(f->ubSecondCode);
856 			const UINT8 ubSectorY = SECTORY(f->ubSecondCode);
857 			return st_format_printf(pTransactionText[TRAIN_TOWN_MILITIA], GetSectorIDString(ubSectorX, ubSectorY, 0, TRUE));
858 		}
859 
860 		default:
861 			return ST::null;
862 	}
863 }
864 
865 
DisplayFinancePageNumberAndDateRange(void)866 static void DisplayFinancePageNumberAndDateRange(void)
867 {
868 	SetFontAttributes(FINANCE_TEXT_FONT, FONT_BLACK, NO_SHADOW);
869 	MPrint(PAGE_NUMBER_X, PAGE_NUMBER_Y, ST::format("{} {} / {}", pFinanceHeaders[5], iCurrentPage + 1, guiLastPageInRecordsList + 2));
870 	SetFontShadow(DEFAULT_SHADOW);
871 }
872 
873 
WriteBalanceToDisk(void)874 static void WriteBalanceToDisk(void)
875 {
876 	// will write the current balance to disk
877 	AutoSGPFile hFileHandle(GCM->openTempFileForWriting(NEWTMP_FINANCES_DATA_FILE, false));
878 	FileWrite(hFileHandle, &LaptopSaveInfo.iCurrentBalance, sizeof(INT32));
879 }
880 
881 
GetBalanceFromDisk(void)882 static void GetBalanceFromDisk(void)
883 {
884 	// will grab the current blanace from disk
885 	// assuming file already openned
886 	// this procedure will open and read in data to the finance list
887 	AutoSGPFile f;
888 	try
889 	{
890 		f = GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE);
891 	}
892 	catch (...)
893 	{
894 		LaptopSaveInfo.iCurrentBalance = 0;
895 		return; /* XXX TODO0019 ignore */
896 	}
897 
898 	// get balance from disk first
899 	FileRead(f, &LaptopSaveInfo.iCurrentBalance, sizeof(INT32));
900 }
901 
902 
903 // will write the current finance to disk
AppendFinanceToEndOfFile(void)904 static void AppendFinanceToEndOfFile(void)
905 {
906 	AutoSGPFile f(GCM->openTempFileForAppend(NEWTMP_FINANCES_DATA_FILE));
907 
908 	const FinanceUnit* const fu = pFinanceListHead;
909 	BYTE  data[FINANCE_RECORD_SIZE];
910 	DataWriter d{data};
911 	INJ_U8(d, fu->ubCode);
912 	INJ_U8(d, fu->ubSecondCode);
913 	INJ_U32(d, fu->uiDate);
914 	INJ_I32(d, fu->iAmount);
915 	INJ_I32(d, fu->iBalanceToDate);
916 	Assert(d.getConsumed() == lengthof(data));
917 
918 	FileWrite(f, data, sizeof(data));
919 }
920 
921 
922 // Grabs the size of the file and interprets number of pages it will take up
SetLastPageInRecords(void)923 static void SetLastPageInRecords(void)
924 {
925 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
926 
927 	const UINT32 size = FileGetSize(f);
928 
929 	if (size < FINANCE_HEADER_SIZE + FINANCE_RECORD_SIZE)
930 	{
931 		guiLastPageInRecordsList = 0;
932 		return;
933 	}
934 
935 	guiLastPageInRecordsList =
936 		(size - FINANCE_HEADER_SIZE - FINANCE_RECORD_SIZE) /
937 		(FINANCE_RECORD_SIZE * NUM_RECORDS_PER_PAGE);
938 }
939 
940 
LoadPreviousPage(void)941 static void LoadPreviousPage(void)
942 {
943 	if (iCurrentPage == 0) return;
944 	LoadInRecords(iCurrentPage - 1);
945 }
946 
947 
LoadNextPage(void)948 static void LoadNextPage(void)
949 {
950 	if (static_cast<UINT32>(iCurrentPage) > guiLastPageInRecordsList) return;
951 	LoadInRecords(iCurrentPage + 1);
952 }
953 
954 
955 // Loads in records belonging to page
LoadInRecords(UINT32 const page)956 static void LoadInRecords(UINT32 const page)
957 {
958 	iCurrentPage      = page;
959 	fReDrawScreenFlag = TRUE;
960 	SetFinanceButtonStates();
961 	ClearFinanceList();
962 	if (page == 0) return; // check if bad page
963 
964 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
965 
966 	UINT32 const size = FileGetSize(f);
967 	if (size < FINANCE_HEADER_SIZE) return;
968 
969 	UINT32       records      = (size - FINANCE_HEADER_SIZE) / FINANCE_RECORD_SIZE;
970 	UINT32 const skip_records = NUM_RECORDS_PER_PAGE * (page - 1);
971 	if (records <= skip_records) return;
972 
973 	records -= skip_records;
974 	FileSeek(f, FINANCE_HEADER_SIZE + FINANCE_RECORD_SIZE * skip_records, FILE_SEEK_FROM_START);
975 
976 	if (records > NUM_RECORDS_PER_PAGE) records = NUM_RECORDS_PER_PAGE;
977 	for (; records > 0; --records)
978 	{
979 		BYTE data[FINANCE_RECORD_SIZE];
980 		FileRead(f, data, sizeof(data));
981 
982 		UINT8  code;
983 		UINT8  second_code;
984 		UINT32 date;
985 		INT32  amount;
986 		INT32  balance_to_date;
987 		DataReader d{data};
988 		EXTR_U8(d, code);
989 		EXTR_U8(d, second_code);
990 		EXTR_U32(d, date);
991 		EXTR_I32(d, amount);
992 		EXTR_I32(d, balance_to_date);
993 		Assert(d.getConsumed() == lengthof(data));
994 
995 		ProcessAndEnterAFinacialRecord(code, date, amount, second_code, balance_to_date);
996 	}
997 }
998 
999 
InternalSPrintMoney(bool dollar,INT32 amount)1000 static ST::string InternalSPrintMoney(bool dollar, INT32 amount)
1001 {
1002 	ST::utf32_buffer codepoints = ST::format("{}", amount).to_utf32();
1003 	size_t start = amount < 0 ? 1 : 0;
1004 	size_t end = codepoints.size();
1005 	ST::string money;
1006 	if (dollar)
1007 	{
1008 		money += U'$';
1009 	}
1010 	for (size_t i = 0; i < end; i++)
1011 	{
1012 		if (i > start && (end - i) % 3 == 0)
1013 		{
1014 			money += U',';
1015 		}
1016 		money += codepoints[i];
1017 	}
1018 	return money;
1019 }
1020 
1021 
SPrintMoney(INT32 amount)1022 ST::string SPrintMoney(INT32 amount)
1023 {
1024 	return InternalSPrintMoney(true, amount);
1025 }
1026 
1027 
SPrintMoneyNoDollarOnZero(INT32 amount)1028 static ST::string SPrintMoneyNoDollarOnZero(INT32 amount)
1029 {
1030 	return InternalSPrintMoney(amount != 0, amount);
1031 }
1032 
1033 
1034 // find out what today is, then go back 2 days, get balance for that day
GetPreviousDaysBalance(void)1035 static INT32 GetPreviousDaysBalance(void)
1036 {
1037 	const UINT32 date_in_minutes = GetWorldTotalMin() - 60 * 24;
1038 	const UINT32 date_in_days    = date_in_minutes / (24 * 60);
1039 
1040 	if (date_in_days < 2) return 0;
1041 
1042 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
1043 
1044 	INT32 balance = 0;
1045 	// start at the end, move back until Date / 24 * 60 on the record equals date_in_days - 2
1046 	// loop, make sure we don't pass beginning of file, if so, we have an error, and check for condifition above
1047 	for (UINT32 pos = FileGetSize(f); pos >= FINANCE_HEADER_SIZE + RECORD_SIZE;)
1048 	{
1049 		FileSeek(f, pos -= RECORD_SIZE, FILE_SEEK_FROM_START);
1050 
1051 		BYTE data[RECORD_SIZE];
1052 		FileRead(f, data, sizeof(data));
1053 
1054 		UINT32 date;
1055 		INT32 balance_to_date;
1056 		DataReader d{data};
1057 		EXTR_SKIP(d, 2);
1058 		EXTR_U32(d, date);
1059 		EXTR_SKIP(d, 4);
1060 		EXTR_I32(d, balance_to_date);
1061 		Assert(d.getConsumed() == lengthof(data));
1062 
1063 		// check to see if we are far enough
1064 		if (date / (24 * 60) == date_in_days - 2)
1065 		{
1066 			balance = balance_to_date;
1067 			break;
1068 		}
1069 
1070 		// there are no entries for the previous day
1071 		if (date / (24 * 60) < date_in_days - 2) break;
1072 	}
1073 
1074 	return balance;
1075 }
1076 
1077 
GetTodaysBalance(void)1078 static INT32 GetTodaysBalance(void)
1079 {
1080 	const UINT32 date_in_minutes = GetWorldTotalMin();
1081 	const UINT32 date_in_days    = date_in_minutes / (24 * 60);
1082 
1083 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
1084 
1085 	INT32 balance = 0;
1086 	// loop, make sure we don't pass beginning of file, if so, we have an error, and check for condifition above
1087 	for (UINT32 pos = FileGetSize(f); pos >= FINANCE_HEADER_SIZE + RECORD_SIZE;)
1088 	{
1089 		FileSeek(f, pos -= RECORD_SIZE, FILE_SEEK_FROM_START);
1090 
1091 		BYTE data[RECORD_SIZE];
1092 		FileRead(f, data, sizeof(data));
1093 
1094 		UINT32 date;
1095 		INT32 balance_to_date;
1096 		DataReader d{data};
1097 		EXTR_SKIP(d, 2);
1098 		EXTR_U32(d, date);
1099 		EXTR_SKIP(d, 4);
1100 		EXTR_I32(d, balance_to_date);
1101 		Assert(d.getConsumed() == lengthof(data));
1102 
1103 		// check to see if we are far enough
1104 		if (date / (24 * 60) == date_in_days - 1)
1105 		{
1106 			balance = balance_to_date;
1107 			break;
1108 		}
1109 	}
1110 
1111 	return balance;
1112 }
1113 
1114 
1115 /* will return the income from the previous day, which is todays starting
1116  * balance - yesterdays starting balance */
GetPreviousDaysIncome(void)1117 static INT32 GetPreviousDaysIncome(void)
1118 {
1119 	const UINT32 date_in_minutes = GetWorldTotalMin();
1120 	const UINT32 date_in_days    = date_in_minutes / (24 * 60);
1121 
1122 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
1123 
1124 	INT32 iTotalPreviousIncome = 0;
1125 	// start at the end, move back until Date / 24 * 60 on the record is = date_in_days - 2
1126 	// loop, make sure we don't pass beginning of file, if so, we have an error, and check for condifition above
1127 	BOOLEAN fOkToIncrement = FALSE;
1128 	for (UINT32 pos = FileGetSize(f); pos >= FINANCE_HEADER_SIZE + RECORD_SIZE;)
1129 	{
1130 		FileSeek(f, pos -= RECORD_SIZE, FILE_SEEK_FROM_START);
1131 
1132 		BYTE data[RECORD_SIZE];
1133 		FileRead(f, data, sizeof(data));
1134 
1135 		UINT8  code;
1136 		UINT32 date;
1137 		INT32  amount;
1138 		DataReader d{data};
1139 		EXTR_U8(d, code);
1140 		EXTR_SKIP(d, 1);
1141 		EXTR_U32(d, date);
1142 		EXTR_I32(d, amount);
1143 		EXTR_SKIP(d, 4);
1144 		Assert(d.getConsumed() == lengthof(data));
1145 
1146 		// now ok to increment amount
1147 		if (date / (24 * 60) == date_in_days - 1) fOkToIncrement = TRUE;
1148 
1149 		if (fOkToIncrement && (code == DEPOSIT_FROM_GOLD_MINE || code == DEPOSIT_FROM_SILVER_MINE))
1150 		{
1151 			// increment total
1152 			iTotalPreviousIncome += amount;
1153 		}
1154 
1155 		// check to see if we are far enough
1156 		if (date / (24 * 60) <= date_in_days - 2) break;
1157 	}
1158 
1159 	return iTotalPreviousIncome;
1160 }
1161 
1162 
GetTodaysDaysIncome(void)1163 static INT32 GetTodaysDaysIncome(void)
1164 {
1165 	const UINT32 date_in_minutes = GetWorldTotalMin();
1166 	const UINT32 date_in_days    = date_in_minutes / (24 * 60);
1167 
1168 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
1169 
1170 	INT32 iTotalIncome = 0;
1171 	// loop, make sure we don't pass beginning of file, if so, we have an error, and check for condifition above
1172 	BOOLEAN fOkToIncrement = FALSE;
1173 	for (UINT32 pos = FileGetSize(f); pos >= FINANCE_HEADER_SIZE + RECORD_SIZE;)
1174 	{
1175 		FileSeek(f, pos -= RECORD_SIZE, FILE_SEEK_FROM_START);
1176 
1177 		BYTE data[RECORD_SIZE];
1178 		FileRead(f, data, sizeof(data));
1179 
1180 		UINT8  code;
1181 		UINT32 date;
1182 		INT32  amount;
1183 		DataReader d{data};
1184 		EXTR_U8(d, code);
1185 		EXTR_SKIP(d, 1);
1186 		EXTR_U32(d, date);
1187 		EXTR_I32(d, amount);
1188 		EXTR_SKIP(d, 4);
1189 		Assert(d.getConsumed() == lengthof(data));
1190 
1191 		// now ok to increment amount
1192 		if (date / (24 * 60) > date_in_days - 1) fOkToIncrement = TRUE;
1193 
1194 		if (fOkToIncrement && (code == DEPOSIT_FROM_GOLD_MINE || code == DEPOSIT_FROM_SILVER_MINE))
1195 		{
1196 			// increment total
1197 			iTotalIncome += amount;
1198 			fOkToIncrement = FALSE;
1199 		}
1200 
1201 		// check to see if we are far enough
1202 		if (date / (24 * 60) == date_in_days - 1) break;
1203 	}
1204 
1205 	return iTotalIncome;
1206 }
1207 
1208 
SetFinanceButtonStates(void)1209 static void SetFinanceButtonStates(void)
1210 {
1211 	// this function will look at what page we are viewing, enable and disable buttons as needed
1212 
1213 	bool const has_prev = iCurrentPage != 0;
1214 	EnableButton(giFinanceButton[PREV_PAGE_BUTTON],  has_prev);
1215 	EnableButton(giFinanceButton[FIRST_PAGE_BUTTON], has_prev);
1216 
1217 	bool const has_next = iCurrentPage <= static_cast<INT32>(guiLastPageInRecordsList);
1218 	EnableButton(giFinanceButton[NEXT_PAGE_BUTTON], has_next);
1219 	EnableButton(giFinanceButton[LAST_PAGE_BUTTON], has_next);
1220 }
1221 
1222 
1223 // grab todays other deposits
GetTodaysOtherDeposits(void)1224 static INT32 GetTodaysOtherDeposits(void)
1225 {
1226 	const UINT32 date_in_minutes = GetWorldTotalMin();
1227 	const UINT32 date_in_days    = date_in_minutes / (24 * 60);
1228 
1229 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
1230 
1231 	INT32 iTotalIncome = 0;
1232 	// loop, make sure we don't pass beginning of file, if so, we have an error, and check for condifition above
1233 	BOOLEAN fOkToIncrement = FALSE;
1234 	for (UINT32 pos = FileGetSize(f); pos >= FINANCE_HEADER_SIZE + RECORD_SIZE;)
1235 	{
1236 		FileSeek(f, pos -= RECORD_SIZE, FILE_SEEK_FROM_START);
1237 
1238 		BYTE data[RECORD_SIZE];
1239 		FileRead(f, data, sizeof(data));
1240 
1241 		UINT8  code;
1242 		UINT32 date;
1243 		INT32  amount;
1244 		DataReader d{data};
1245 		EXTR_U8(d, code);
1246 		EXTR_SKIP(d, 1);
1247 		EXTR_U32(d, date);
1248 		EXTR_I32(d, amount);
1249 		EXTR_SKIP(d, 4);
1250 		Assert(d.getConsumed() == lengthof(data));
1251 
1252 		// now ok to increment amount
1253 		if (date / (24 * 60) > date_in_days - 1) fOkToIncrement = TRUE;
1254 
1255 		if (fOkToIncrement &&
1256 				(code != DEPOSIT_FROM_GOLD_MINE && code != DEPOSIT_FROM_SILVER_MINE) &&
1257 				amount > 0)
1258 		{
1259 			// increment total
1260 			iTotalIncome += amount;
1261 			fOkToIncrement = FALSE;
1262 		}
1263 
1264 		// check to see if we are far enough
1265 		if (date / (24 * 60) == date_in_days - 1) break;
1266 	}
1267 
1268 	return iTotalIncome;
1269 }
1270 
1271 
GetYesterdaysOtherDeposits(void)1272 static INT32 GetYesterdaysOtherDeposits(void)
1273 {
1274 	const UINT32 iDateInMinutes = GetWorldTotalMin();
1275 	const UINT32 date_in_days   = iDateInMinutes / (24 * 60);
1276 
1277 	AutoSGPFile f(GCM->openTempFileForReading(NEWTMP_FINANCES_DATA_FILE));
1278 
1279 	INT32 iTotalPreviousIncome = 0;
1280 	// start at the end, move back until Date / 24 * 60 on the record is =  date_in_days - 2
1281 	// loop, make sure we don't pass beginning of file, if so, we have an error, and check for condifition above
1282 	BOOLEAN fOkToIncrement = FALSE;
1283 	for (UINT32 pos = FileGetSize(f); pos >= FINANCE_HEADER_SIZE + RECORD_SIZE;)
1284 	{
1285 		FileSeek(f, pos -= RECORD_SIZE, FILE_SEEK_FROM_START);
1286 
1287 		BYTE data[RECORD_SIZE];
1288 		FileRead(f, data, sizeof(data));
1289 
1290 		UINT8  code;
1291 		UINT32 date;
1292 		INT32  amount;
1293 		DataReader d{data};
1294 		EXTR_U8(d, code);
1295 		EXTR_SKIP(d, 1);
1296 		EXTR_U32(d, date);
1297 		EXTR_I32(d, amount);
1298 		EXTR_SKIP(d, 4);
1299 		Assert(d.getConsumed() == lengthof(data));
1300 
1301 		// now ok to increment amount
1302 		if (date / (24 * 60) == date_in_days - 1) fOkToIncrement = TRUE;
1303 
1304 		if (fOkToIncrement &&
1305 				(code != DEPOSIT_FROM_GOLD_MINE && code != DEPOSIT_FROM_SILVER_MINE) &&
1306 				amount > 0)
1307 		{
1308 			// increment total
1309 			iTotalPreviousIncome += amount;
1310 		}
1311 
1312 		// check to see if we are far enough
1313 		if (date / (24 * 60) <= date_in_days - 2) break;
1314 	}
1315 
1316 	return iTotalPreviousIncome;
1317 }
1318 
1319 
GetTodaysDebits(void)1320 static INT32 GetTodaysDebits(void)
1321 {
1322 	// return the expenses for today
1323 
1324 	// currentbalance - todays balance - Todays income - other deposits
1325 
1326 	return( GetCurrentBalance( ) - GetTodaysBalance( ) - GetTodaysDaysIncome( ) - GetTodaysOtherDeposits( ) );
1327 }
1328 
1329 
GetYesterdaysDebits(void)1330 static INT32 GetYesterdaysDebits(void)
1331 {
1332 	// return the expenses for yesterday
1333 
1334 	return( GetTodaysBalance( ) - GetPreviousDaysBalance( ) - GetPreviousDaysIncome( ) - GetYesterdaysOtherDeposits( ) );
1335 }
1336