1 #include "Directories.h"
2 #include "Font.h"
3 #include "Laptop.h"
4 #include "EMail.h"
5 #include "Local.h"
6 #include "VObject.h"
7 #include "Debug.h"
8 #include "WordWrap.h"
9 #include "Render_Dirty.h"
10 #include "Cursors.h"
11 #include "Soldier_Profile.h"
12 #include "IMP_Compile_Character.h"
13 #include "IMP_Portraits.h"
14 #include "Game_Clock.h"
15 #include "Environment.h"
16 #include "AIMMembers.h"
17 #include "Random.h"
18 #include "Text.h"
19 #include "LaptopSave.h"
20 #include "Finances.h"
21 #include "Button_System.h"
22 #include "Video.h"
23 #include "VSurface.h"
24 #include "MemMan.h"
25 #include "Font_Control.h"
26 #include "UILayout.h"
27
28 #include "ContentManager.h"
29 #include "GameInstance.h"
30
31 #include <string_theory/format>
32 #include <string_theory/string>
33
34
35 #define MAX_MESSAGES_PAGE 18 // max number of messages per page
36
37 #define VIEWER_X (155 + STD_SCREEN_X)
38 #define VIEWER_Y (70 + 21 + STD_SCREEN_Y)
39 #define MAIL_STRING_SIZE 320
40
41
42 enum EMailSortCriteria
43 {
44 SENDER,
45 RECEIVED,
46 SUBJECT,
47 READ
48 };
49
50
51 struct Page
52 {
53 Email* Mail[MAX_MESSAGES_PAGE];
54 Page* Next;
55 };
56
57
58 struct Record
59 {
60 ST::string pRecord;
61 Record* Next;
62 };
63
64
65 struct EmailPageInfoStruct
66 {
67 Record* pFirstRecord;
68 Record* pLastRecord;
69 INT32 iPageNumber;
70 };
71
72
73 Email* pEmailList;
74 static Page* pPageList;
75 static INT32 iLastPage=-1;
76 static INT32 iCurrentPage=0;
77 Email* MailToDelete;
78 BOOLEAN fUnReadMailFlag=FALSE;
79 BOOLEAN fNewMailFlag=FALSE;
80 BOOLEAN fOldNewMailFlag=FALSE;
81 BOOLEAN fDisplayMessageFlag=FALSE;
82 static BOOLEAN fOldDisplayMessageFlag = FALSE;
83 static BOOLEAN fReDrawMessageFlag = FALSE;
84 BOOLEAN fOpenMostRecentUnReadFlag = FALSE;
85 static INT32 iViewerPositionY = 0;
86
87 static Email* CurrentMail;
88 static Email* PreviousMail;
89 static INT32 giMessagePage = -1;
90 static INT32 giNumberOfPagesToCurrentEmail = -1;
91 SGPVObject* guiEmailWarning;
92
93 #define EMAIL_TOP_BAR_HEIGHT 22
94
95 #define MIDDLE_X 0+LAPTOP_SCREEN_UL_X
96 #define MIDDLE_Y (72 + EMAIL_TOP_BAR_HEIGHT + STD_SCREEN_Y)
97 #define MIDDLE_WIDTH 19
98
99
100 // new graphics
101 #define EMAIL_LIST_WINDOW_Y 22
102
103 // email columns
104 #define SENDER_X LAPTOP_SCREEN_UL_X+65
105
106 #define DATE_X LAPTOP_SCREEN_UL_X+428
107
108 #define SUBJECT_X LAPTOP_SCREEN_UL_X+175
109 #define SUBJECT_WIDTH 254 //526-245
110 #define INDIC_X (128 + STD_SCREEN_X)
111
112 #define LINE_WIDTH 592-121
113
114 #define MESSAGE_X 5 //17
115 #define MESSAGE_WIDTH 528-125//150
116 #define MESSAGE_COLOR FONT_BLACK
117 #define MESSAGE_GAP 2
118
119
120 #define MESSAGE_HEADER_WIDTH 209-151
121 #define MESSAGE_HEADER_X VIEWER_X+4
122
123
124 #define EMAIL_WARNING_X (210 + STD_SCREEN_X)
125 #define EMAIL_WARNING_Y (140 + STD_SCREEN_Y)
126 #define EMAIL_WARNING_WIDTH 254
127 #define EMAIL_WARNING_HEIGHT 138
128
129
130 #define NEW_BTN_X EMAIL_WARNING_X +(338-245)
131 #define NEW_BTN_Y EMAIL_WARNING_Y +(278-195)
132
133 #define EMAIL_TEXT_FONT FONT10ARIAL
134 #define MESSAGE_FONT EMAIL_TEXT_FONT
135 #define EMAIL_HEADER_FONT FONT14ARIAL
136 #define EMAIL_WARNING_FONT FONT12ARIAL
137
138
139 // the max number of pages to an email
140 #define MAX_NUMBER_EMAIL_PAGES 100
141
142 #define NEXT_PAGE_X LAPTOP_UL_X + 562
143 #define NEXT_PAGE_Y (51 + STD_SCREEN_Y)
144
145 #define PREVIOUS_PAGE_X NEXT_PAGE_X - 21
146
147 #define ENVELOPE_BOX_X (116 + STD_SCREEN_X)
148
149 #define FROM_BOX_X (166 + STD_SCREEN_X)
150
151 #define SUBJECT_BOX_X (276 + STD_SCREEN_X)
152
153 #define DATE_BOX_X (530 + STD_SCREEN_X)
154
155 #define FROM_BOX_Y (51 + EMAIL_TOP_BAR_HEIGHT + STD_SCREEN_Y)
156
157 #define EMAIL_TITLE_FONT FONT14ARIAL
158 #define EMAIL_TITLE_X (140 + STD_SCREEN_X)
159 #define EMAIL_TITLE_Y (33 + STD_SCREEN_Y)
160 #define VIEWER_MESSAGE_BODY_START_Y VIEWER_Y+72
161 #define MIN_MESSAGE_HEIGHT_IN_LINES 5
162
163
164 #define INDENT_Y_OFFSET 310
165 #define INDENT_X_OFFSET 325
166 #define INDENT_X_WIDTH ( 544 - 481 )
167
168 // the position of the page number being displayed in the email program
169 #define PAGE_NUMBER_X (516 + STD_SCREEN_X)
170 #define PAGE_NUMBER_Y (58 + STD_SCREEN_Y)
171
172 // defines for location of message 'title'/'headers'
173
174 #define MESSAGE_FROM_Y VIEWER_Y+28
175
176 #define MESSAGE_DATE_Y MESSAGE_FROM_Y
177
178 #define MESSAGE_SUBJECT_Y MESSAGE_DATE_Y+16
179
180
181 #define SUBJECT_LINE_X VIEWER_X+47
182 #define SUBJECT_LINE_Y VIEWER_Y+42
183 #define SUBJECT_LINE_WIDTH 278-47
184
185
186 // maximum size of a email message page, so not to overrun the bottom of the screen
187 #define MAX_EMAIL_MESSAGE_PAGE_SIZE ( GetFontHeight( MESSAGE_FONT ) + MESSAGE_GAP ) * 20
188
189
190 // X button position
191 #define BUTTON_X VIEWER_X + 396
192 #define BUTTON_Y VIEWER_Y + 3 // was + 25
193 #define BUTTON_LOWER_Y BUTTON_Y + 22
194 #define PREVIOUS_PAGE_BUTTON_X VIEWER_X + 302
195 #define NEXT_PAGE_BUTTON_X VIEWER_X +395
196 #define DELETE_BUTTON_X NEXT_PAGE_BUTTON_X
197 #define LOWER_BUTTON_Y BUTTON_Y + 299
198
199
200 static BOOLEAN fSortDateUpwards = FALSE;
201 static BOOLEAN fSortSenderUpwards = FALSE;
202 static BOOLEAN fSortSubjectUpwards = FALSE;
203 static BOOLEAN gfPageButtonsWereCreated = FALSE;
204
205 // mouse regions
206 static MOUSE_REGION pEmailRegions[MAX_MESSAGES_PAGE];
207 static MOUSE_REGION pScreenMask;
208 static MOUSE_REGION pDeleteScreenMask;
209
210 // the email info struct to speed up email
211 static EmailPageInfoStruct pEmailPageInfo[MAX_NUMBER_EMAIL_PAGES];
212
213 //buttons
214 static GUIButtonRef giMessageButton;
215 static GUIButtonRef giDeleteMailButton[2];
216 static GUIButtonRef giSortButton[4];
217 static GUIButtonRef giNewMailButton;
218 static GUIButtonRef giMailMessageButtons[3];
219 static GUIButtonRef giMailPageButtons[2];
220 static MOUSE_REGION g_mail_scroll_region;
221
222
223 // the message record list, for the currently displayed message
224 static Record* pMessageRecordList = NULL;
225
226 // video handles
227 static SGPVObject* guiEmailTitle;
228 static SGPVObject* guiEmailBackground;
229 static SGPVObject* guiEmailIndicator;
230 static SGPVObject* guiEmailMessage;
231 static SGPVObject* guiMAILDIVIDER;
232
233
234 // the enumeration of headers
235 enum{
236 FROM_HEADER=0,
237 SUBJECT_HEADER,
238 RECD_HEADER,
239 };
240
241
242 // whther or not we need to redraw the new mail box
243 BOOLEAN fReDrawNewMailFlag = FALSE;
244 static INT32 iTotalHeight = 0;
245
246
247 static void CreateNextPreviousEmailPageButtons(void);
248 static void EmailBtnCallBack(MOUSE_REGION* pRegion, INT32 iReason);
249
250
InitializeMouseRegions(void)251 static void InitializeMouseRegions(void)
252 {
253 // init mouseregions
254 for (INT32 i = 0; i < MAX_MESSAGES_PAGE; ++i)
255 {
256 const UINT16 x = MIDDLE_X;
257 const UINT16 y = MIDDLE_Y + MIDDLE_WIDTH * i;
258 const UINT16 w = LINE_WIDTH;
259 const UINT16 h = MIDDLE_WIDTH;
260 MOUSE_REGION* const r = &pEmailRegions[i];
261 MSYS_DefineRegion(r, x, y, x + w, y + h, MSYS_PRIORITY_NORMAL + 2, MSYS_NO_CURSOR, NULL, EmailBtnCallBack);
262 MSYS_SetRegionUserData(r, 0, i);
263 }
264
265 CreateNextPreviousEmailPageButtons();
266 }
267
268
DeleteEmailMouseRegions()269 static void DeleteEmailMouseRegions()
270 {
271 FOR_EACH(MOUSE_REGION, i, pEmailRegions) MSYS_RemoveRegion(&*i);
272 FOR_EACH(GUIButtonRef, i, giMailPageButtons) RemoveButton(*i);
273 }
274
275
GameInitEmail()276 void GameInitEmail()
277 {
278 pEmailList=NULL;
279 pPageList=NULL;
280
281 iLastPage=-1;
282
283 iCurrentPage=0;
284 MailToDelete = NULL;
285
286 // reset display message flag
287 fDisplayMessageFlag=FALSE;
288
289 // reset page being displayed
290 giMessagePage = 0;
291 }
292
293
294 static void CreateMailScreenButtons(void);
295
296
EnterEmail()297 void EnterEmail()
298 {
299 // load graphics
300
301 iCurrentPage = LaptopSaveInfo.iCurrentEmailPage;
302
303 // title bar
304 guiEmailTitle = AddVideoObjectFromFile(LAPTOPDIR "/programtitlebar.sti");
305
306 // the list background
307 guiEmailBackground = AddVideoObjectFromFile(LAPTOPDIR "/mailwindow.sti");
308
309 // the indication/notification box
310 guiEmailIndicator = AddVideoObjectFromFile(LAPTOPDIR "/mailindicator.sti");
311
312 // the message background
313 guiEmailMessage = AddVideoObjectFromFile(LAPTOPDIR "/emailviewer.sti");
314
315 // the message background
316 guiMAILDIVIDER = AddVideoObjectFromFile(LAPTOPDIR "/maillistdivider.sti");
317
318 // initialize mouse regions
319 InitializeMouseRegions();
320
321 // create buttons
322 CreateMailScreenButtons( );
323
324 // marks these buttons dirty
325 MarkButtonsDirty( );
326
327 // reset current page of the message being displayed
328 giMessagePage = 0;
329
330 // render email background and text
331 RenderEmail();
332 }
333
334
335 static void AddDeleteRegionsToMessageRegion(INT32 iViewerY);
336 static void ClearOutEmailMessageRecordsList(void);
337 static void DestroyMailScreenButtons(void);
338
339
ExitEmail()340 void ExitEmail()
341 {
342 LaptopSaveInfo.iCurrentEmailPage = iCurrentPage;
343
344 // clear out message record list
345 ClearOutEmailMessageRecordsList( );
346
347 // displayed message?...get rid of it
348 if(fDisplayMessageFlag)
349 {
350 fDisplayMessageFlag = FALSE;
351 AddDeleteRegionsToMessageRegion( 0 );
352 fDisplayMessageFlag = TRUE;
353 fReDrawMessageFlag = TRUE;
354 }
355 else
356 {
357 CurrentMail = NULL;
358 }
359
360 // delete mail notice?...get rid of it
361 if (MailToDelete != NULL)
362 {
363 MailToDelete = NULL;
364 CreateDestroyDeleteNoticeMailButton();
365 }
366
367 // remove all mouse regions in use in email
368 DeleteEmailMouseRegions();
369
370 // remove video objects being used by email screen
371 DeleteVideoObject(guiEmailTitle);
372 DeleteVideoObject(guiEmailBackground);
373 DeleteVideoObject(guiMAILDIVIDER);
374 DeleteVideoObject(guiEmailIndicator);
375 DeleteVideoObject(guiEmailMessage);
376
377 // remove buttons
378 DestroyMailScreenButtons( );
379 }
380
381
382 static BOOLEAN DisplayDeleteNotice(Email* pMail);
383 static void DisplayEmailList(void);
384 static INT32 DisplayEmailMessage(Email* pMail);
385 static void HandleEmailViewerButtonStates(void);
386 static void OpenMostRecentUnreadEmail(void);
387 static void UpDateMessageRecordList(void);
388 static void UpdateStatusOfNextPreviousButtons(void);
389
390
HandleEmail(void)391 void HandleEmail( void )
392 {
393
394 INT32 iViewerY = 0;
395 static BOOLEAN fEmailListBeenDrawAlready = FALSE;
396
397
398 // check if email message record list needs to be updated
399 UpDateMessageRecordList( );
400
401 // does email list need to be draw, or can be drawn
402 if (!fDisplayMessageFlag && !fNewMailFlag && MailToDelete == NULL && !fEmailListBeenDrawAlready)
403 {
404 DisplayEmailList();
405 fEmailListBeenDrawAlready = TRUE;
406 }
407 // if the message flag, show message
408 else if((fDisplayMessageFlag)&&(fReDrawMessageFlag))
409 {
410 // redisplay list
411 DisplayEmailList();
412
413 // this simply redraws message without button manipulation
414 iViewerY = DisplayEmailMessage(CurrentMail);
415 fEmailListBeenDrawAlready = FALSE;
416
417 }
418 else if((fDisplayMessageFlag)&&(!fOldDisplayMessageFlag))
419 {
420
421 // redisplay list
422 DisplayEmailList();
423
424 // this simply redraws message with button manipulation
425 iViewerY = DisplayEmailMessage(CurrentMail);
426 AddDeleteRegionsToMessageRegion( iViewerY );
427 fEmailListBeenDrawAlready = FALSE;
428
429 }
430
431 // not displaying anymore?
432 if (!fDisplayMessageFlag && fOldDisplayMessageFlag)
433 {
434 // then clear it out
435 ClearOutEmailMessageRecordsList( );
436 }
437
438
439 // if new message is being displayed...check to see if it's buttons need to be created or destroyed
440 AddDeleteRegionsToMessageRegion( 0 );
441
442 // same with delete notice
443 CreateDestroyDeleteNoticeMailButton();
444
445 // if delete notice needs to be displayed?...display it
446 if (MailToDelete != NULL) DisplayDeleteNotice(MailToDelete);
447
448
449 // update buttons
450 HandleEmailViewerButtonStates( );
451
452 // handle buttons states
453 UpdateStatusOfNextPreviousButtons( );
454
455 if (fOpenMostRecentUnReadFlag)
456 {
457 // enter email due to email icon on program panel
458 OpenMostRecentUnreadEmail( );
459 fOpenMostRecentUnReadFlag = FALSE;
460
461 }
462 }
463
464
465 static void DisplayTextOnTitleBar(void);
466 static void DisplayWhichPageOfEmailProgramIsDisplayed(void);
467 static void DrawLineDividers(void);
468 static void ReDisplayBoxes(void);
469
470
RenderEmail(void)471 void RenderEmail( void )
472 {
473 BltVideoObject(FRAME_BUFFER, guiEmailBackground, 0, LAPTOP_SCREEN_UL_X, EMAIL_LIST_WINDOW_Y + LAPTOP_SCREEN_UL_Y);
474 BltVideoObject(FRAME_BUFFER, guiEmailTitle, 0, LAPTOP_SCREEN_UL_X, LAPTOP_SCREEN_UL_Y - 2);
475
476 // show text on titlebar
477 DisplayTextOnTitleBar( );
478
479 DisplayEmailList( );
480
481 // redraw line dividers
482 DrawLineDividers( );
483
484 BltVideoObject(FRAME_BUFFER, guiLaptopBACKGROUND, 0, STD_SCREEN_X + 108, STD_SCREEN_Y + 23);
485
486 ReDisplayBoxes( );
487
488 BlitTitleBarIcons( );
489
490 // show which page we are on
491 DisplayWhichPageOfEmailProgramIsDisplayed( );
492
493 InvalidateScreen();
494 }
495
496
AddEmailWithSpecialData(INT32 iMessageOffset,INT32 iMessageLength,UINT8 ubSender,INT32 iDate,INT32 iFirstData,UINT32 uiSecondData)497 void AddEmailWithSpecialData(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate, INT32 iFirstData, UINT32 uiSecondData )
498 {
499 AddEmailMessage(iMessageOffset, iMessageLength, iDate, ubSender, FALSE, iFirstData, uiSecondData);
500 }
501
502
AddEmail(INT32 iMessageOffset,INT32 iMessageLength,UINT8 ubSender,INT32 iDate)503 void AddEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate)
504 {
505 AddEmailMessage(iMessageOffset, iMessageLength, iDate, ubSender, FALSE, 0, 0);
506 }
507
508
AddPreReadEmail(INT32 iMessageOffset,INT32 iMessageLength,UINT8 ubSender,INT32 iDate)509 void AddPreReadEmail(INT32 iMessageOffset, INT32 iMessageLength, UINT8 ubSender, INT32 iDate)
510 {
511 AddEmailMessage(iMessageOffset, iMessageLength, iDate, ubSender, TRUE, 0, 0);
512 }
513
514
LoadEMailText(UINT32 entry)515 static ST::string LoadEMailText(UINT32 entry)
516 {
517 return GCM->loadEncryptedString(BINARYDATADIR "/email.edt", MAIL_STRING_SIZE * entry, MAIL_STRING_SIZE);
518 }
519
520
521 static void AddMessageToPages(Email* Mail);
522 static ST::string ReplaceMercNameAndAmountWithProperData(const ST::string& pFinishedString, const Email* pMail);
523
524
AddEmailMessage(INT32 iMessageOffset,INT32 iMessageLength,INT32 iDate,UINT8 ubSender,BOOLEAN fAlreadyRead,INT32 iFirstData,UINT32 uiSecondData)525 void AddEmailMessage(INT32 iMessageOffset, INT32 iMessageLength, INT32 iDate, UINT8 ubSender, BOOLEAN fAlreadyRead, INT32 iFirstData, UINT32 uiSecondData)
526 {
527 // will add a message to the list of messages
528
529 // add new element onto list
530 Email* const pTempEmail = new Email{};
531
532 // copy offset and length of the actual message in email.edt
533 pTempEmail->usOffset =(UINT16)iMessageOffset;
534 pTempEmail->usLength =(UINT16)iMessageLength;
535
536 // copy date and sender id's
537 pTempEmail->iDate=iDate;
538 pTempEmail->ubSender=ubSender;
539
540 // the special data
541 pTempEmail->iFirstData = iFirstData;
542 pTempEmail->uiSecondData = uiSecondData;
543
544 ST::string pSubject = LoadEMailText(iMessageOffset);
545 pSubject = ReplaceMercNameAndAmountWithProperData(pSubject, pTempEmail);
546 pTempEmail->pSubject = ST::format(" {}", pSubject);
547
548 // place into list
549 Email* pEmail = pEmailList;
550 if(pEmail)
551 {
552 // list exists, place at end
553 while (pEmail->Next != NULL) pEmail = pEmail->Next;
554 pEmail->Next = pTempEmail;
555 }
556 else
557 {
558 // no list, becomes head of a new list
559 pEmailList = pTempEmail;
560 }
561 pTempEmail->Prev = pEmail;
562
563 // reset Next ptr
564 pTempEmail->Next=NULL;
565
566 // set flag that new mail has arrived
567 fNewMailFlag=TRUE;
568
569 // add this message to the pages of email
570 AddMessageToPages(pTempEmail);
571
572 // reset read flag of this particular message
573 pTempEmail->fRead=fAlreadyRead;
574 }
575
576
RemoveEmailMessage(Email * Mail)577 static void RemoveEmailMessage(Email* Mail)
578 {
579 Email* Next = Mail->Next;
580 Email* Prev = Mail->Prev;
581 if (Next != NULL) Next->Prev = Prev;
582 if (Prev != NULL)
583 {
584 Prev->Next = Next;
585 }
586 else
587 {
588 Assert(pEmailList == Mail);
589 pEmailList = Next;
590 }
591 delete Mail;
592 }
593
594
AddEmailPage(void)595 static void AddEmailPage(void)
596 {
597 Page* const p = new Page{};
598 FOR_EACH(Email*, i, p->Mail) *i = 0;
599 p->Next = NULL;
600
601 if (pPageList)
602 {
603 Page* last = pPageList;
604 while (last->Next) last = last->Next;
605 last->Next = p;
606 }
607 else
608 {
609 pPageList = p;
610 }
611
612 iLastPage++;
613 }
614
615
AddMessageToPages(Email * Mail)616 static void AddMessageToPages(Email* Mail)
617 {
618 // go to end of page list
619 Page* pPage = pPageList;
620 INT32 iCounter=0;
621 if(!pPage)
622 AddEmailPage();
623 pPage=pPageList;
624 while (pPage->Next != NULL && pPage->Mail[MAX_MESSAGES_PAGE - 1] != NULL)
625 pPage=pPage->Next;
626 // if list is full, add new page
627 while(iCounter <MAX_MESSAGES_PAGE)
628 {
629 if (pPage->Mail[iCounter] == NULL) break;
630 iCounter++;
631 }
632 if(iCounter==MAX_MESSAGES_PAGE)
633 {
634 AddEmailPage();
635 AddMessageToPages(Mail);
636 }
637 else
638 {
639 pPage->Mail[iCounter] = Mail;
640 }
641 }
642
643
SortMessages(EMailSortCriteria Criterium)644 static void SortMessages(EMailSortCriteria Criterium)
645 {
646 Email* NewList = NULL;
647
648 for (Email* List = pEmailList; List != NULL;)
649 {
650 Email* Mail = List;
651 List = List->Next;
652
653 Email* InsAfter = NULL;
654 for (Email* Other = NewList; Other != NULL; Other = Other->Next)
655 {
656 INT Order; // XXX HACK000E
657 switch (Criterium)
658 {
659 case RECEIVED:
660 Order = Mail->iDate - Other->iDate;
661 if (fSortDateUpwards) Order = -Order;
662 break;
663
664 case SENDER:
665 Order = pSenderNameList[Mail->ubSender].compare(pSenderNameList[Other->ubSender]);
666 if (fSortSenderUpwards) Order = -Order;
667 break;
668
669 case SUBJECT:
670 Order = Mail->pSubject.compare(Other->pSubject);
671 if (fSortSubjectUpwards) Order = -Order;
672 break;
673
674 case READ:
675 Order = Other->fRead - Mail->fRead;
676 break;
677
678 default: abort(); // HACK000E
679 }
680 if (Order > 0) break;
681 InsAfter = Other;
682 }
683 Mail->Prev = InsAfter;
684 if (InsAfter == NULL)
685 {
686 Mail->Next = NewList;
687 NewList = Mail;
688 }
689 else
690 {
691 Mail->Next = InsAfter->Next;
692 InsAfter->Next = Mail;
693 }
694 if (Mail->Next != NULL) Mail->Next->Prev = Mail;
695 }
696 pEmailList = NewList;
697
698 fReDrawScreenFlag = TRUE;
699 }
700
701
ClearPages(void)702 static void ClearPages(void)
703 {
704 // run through list of message pages and set to -1
705 for (Page* i = pPageList; i;)
706 {
707 Page* const next = i->Next;
708 delete i;
709 i = next;
710 }
711
712 pPageList = NULL;
713 iLastPage = -1;
714 }
715
716
PlaceMessagesinPages(void)717 static void PlaceMessagesinPages(void)
718 {
719 Email* pEmail = pEmailList;
720 // run through the list of messages and add to pages
721 ClearPages();
722 while(pEmail)
723 {
724 AddMessageToPages(pEmail);
725 pEmail=pEmail->Next;
726
727 }
728 if(iCurrentPage >iLastPage)
729 iCurrentPage=iLastPage;
730 }
731
732
733 // Draw the icon, sender, date, subject
DrawEmailSummary(INT32 y,const Email * e)734 static void DrawEmailSummary(INT32 y, const Email* e)
735 {
736 const BOOLEAN read = e->fRead;
737 const SGPFont font = read ? MESSAGE_FONT : FONT10ARIALBOLD;
738
739 // will draw the icon for letter in mail list depending if the mail has been read or not
740 BltVideoObject(FRAME_BUFFER, guiEmailIndicator, read ? 0 : 1, INDIC_X, y + 2);
741
742 SetFont(font);
743
744 ST::string pTempSubject = e->pSubject;
745 pTempSubject = ReduceStringLength(pTempSubject, SUBJECT_WIDTH - 10, font);
746 MPrint(SUBJECT_X, y + 4, pTempSubject);
747 MPrint(SENDER_X, y + 4, pSenderNameList[e->ubSender]);
748
749 // draw date of message being displayed in mail viewer
750 MPrint(DATE_X, y + 4, ST::format("{} {}", pDayStrings, e->iDate / (24 * 60)));
751 }
752
753
GetCurrentPage(void)754 static Page* GetCurrentPage(void)
755 {
756 Page* i = pPageList;
757 if (i == NULL) return i;
758
759 INT32 PageID = 0;
760 while (i->Next != NULL && PageID++ != iCurrentPage) i = i->Next;
761 return i;
762 }
763
764
DisplayEmailList(void)765 static void DisplayEmailList(void)
766 {
767 // look at current page, and display
768
769 // if current page ever ends up negative, reset to 0
770 if (iCurrentPage == -1) iCurrentPage = 0;
771
772 const Page* const p = GetCurrentPage();
773 if (p == NULL) return;
774
775 // now we have current page, display it
776 SetFontForeground(FONT_BLACK);
777 SetFontBackground(FONT_BLACK);
778 SetFontShadow(NO_SHADOW);
779
780 // draw each line of the list for this page
781 INT32 y = MIDDLE_Y;
782 FOR_EACH(Email* const, e, p->Mail)
783 {
784 if (!*e) break;
785 DrawEmailSummary(y, *e);
786 y += MIDDLE_WIDTH;
787 }
788
789 InvalidateRegion(LAPTOP_SCREEN_UL_X,LAPTOP_SCREEN_UL_Y,LAPTOP_SCREEN_LR_X,LAPTOP_SCREEN_LR_Y);
790
791 SetFontShadow(DEFAULT_SHADOW);
792 }
793
794
LookForUnread()795 void LookForUnread()
796 {
797 BOOLEAN fStatusOfNewEmailFlag = fUnReadMailFlag;
798
799 // simply runrs through list of messages, if any unread, set unread flag
800
801 Email* pA = pEmailList;
802
803 // reset unread flag
804 fUnReadMailFlag=FALSE;
805
806 // look for unread mail
807 while(pA)
808 {
809 // unread mail found, set flag
810 if(!(pA->fRead))
811 fUnReadMailFlag=TRUE;
812 pA=pA->Next;
813 }
814
815 if( fStatusOfNewEmailFlag != fUnReadMailFlag )
816 {
817 //Since there is no new email, get rid of the hepl text
818 CreateFileAndNewEmailIconFastHelpText( LAPTOP_BN_HLP_TXT_YOU_HAVE_NEW_MAIL, (BOOLEAN )!fUnReadMailFlag );
819 }
820 }
821
822
PrevListPage()823 static void PrevListPage()
824 {
825 if (iCurrentPage == 0) return;
826 --iCurrentPage;
827 RenderEmail();
828 MarkButtonsDirty();
829 }
830
831
NextListPage()832 static void NextListPage()
833 {
834 if (iCurrentPage == iLastPage) return;
835 ++iCurrentPage;
836 RenderEmail();
837 MarkButtonsDirty();
838 }
839
840
EmailBtnCallBack(MOUSE_REGION * pRegion,INT32 iReason)841 static void EmailBtnCallBack(MOUSE_REGION* pRegion, INT32 iReason)
842 {
843 INT32 iCount;
844 if(fDisplayMessageFlag)
845 return;
846 if(iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
847 {
848 Page* pPage = GetCurrentPage();
849 if (pPage == NULL) return;
850
851 // error check
852 iCount=MSYS_GetRegionUserData(pRegion, 0);
853
854 Email* Mail = pPage->Mail[iCount];
855
856 // invalid message
857 if (Mail == NULL)
858 {
859 fDisplayMessageFlag=FALSE;
860 return;
861 }
862 // Get email and display
863 fDisplayMessageFlag=TRUE;
864 giMessagePage = 0;
865 PreviousMail = CurrentMail;
866 CurrentMail = Mail;
867 }
868 else if(iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
869 {
870 Page* pPage = GetCurrentPage();
871 if (pPage == NULL)
872 {
873 HandleRightButtonUpEvent();
874 return;
875 }
876
877 iCount=MSYS_GetRegionUserData(pRegion, 0);
878
879 giMessagePage = 0;
880
881 Email* Mail = pPage->Mail[iCount];
882 if (Mail == NULL)
883 {
884 // no mail here, handle right button up event
885 HandleRightButtonUpEvent( );
886 return;
887 }
888 else
889 {
890 MailToDelete = Mail;
891 }
892 }
893 else if (iReason & MSYS_CALLBACK_REASON_WHEEL_UP)
894 {
895 PrevListPage();
896 }
897 else if (iReason & MSYS_CALLBACK_REASON_WHEEL_DOWN)
898 {
899 NextListPage();
900 }
901 }
902
903
BtnMessageXCallback(GUI_BUTTON * btn,INT32 reason)904 static void BtnMessageXCallback(GUI_BUTTON *btn, INT32 reason)
905 {
906 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP || reason & MSYS_CALLBACK_REASON_RBUTTON_UP)
907 {
908 // X button has been pressed and let up, this means to stop displaying the currently displayed message
909
910 // reset display message flag
911 fDisplayMessageFlag = FALSE;
912
913 // reset page being displayed
914 giMessagePage = 0;
915
916 // force update of entire screen
917 fPausedReDrawScreenFlag = TRUE;
918 }
919 }
920
921
GetFirstRecordOnThisPage(Record * const RecordList,INT32 const iPage)922 static Record* GetFirstRecordOnThisPage(Record* const RecordList, INT32 const iPage)
923 {
924 // get the first record on this page - build pages up until this point
925
926 Record* CurrentRecord = NULL;
927
928 INT32 iCurrentPositionOnThisPage = 0;
929 INT32 iCurrentPage =0;
930
931
932
933 // null record list, nothing to do
934 if( RecordList == NULL )
935 {
936 return ( CurrentRecord );
937 }
938
939 CurrentRecord = RecordList;
940
941 // while we are not on the current page
942 SGPFont const font = MESSAGE_FONT;
943 while( iCurrentPage < iPage )
944 {
945 // build record list to this point
946 for (;;)
947 {
948 UINT16 const h = IanWrappedStringHeight(MESSAGE_WIDTH, MESSAGE_GAP, font, CurrentRecord->pRecord);
949 if (iCurrentPositionOnThisPage + h > MAX_EMAIL_MESSAGE_PAGE_SIZE) break;
950
951 // still room on this page
952 iCurrentPositionOnThisPage += h;
953
954 // next record
955 CurrentRecord = CurrentRecord -> Next;
956
957 // check if we have gone too far?
958 if( CurrentRecord == NULL )
959 {
960 return( CurrentRecord );
961 }
962 }
963
964 // reset position
965 iCurrentPositionOnThisPage = 0;
966
967 // next page
968 iCurrentPage++;
969 }
970
971 return ( CurrentRecord );
972 }
973
974
975 static void DisplayEmailMessageSubjectDateFromLines(Email* pMail, INT32 iViewerY);
976 static void DisplayNumberOfPagesToThisEmail(INT32 iViewerY);
977 static void DrawEmailMessageDisplayTitleText(INT32 iViewerY);
978 static void HandleAnySpecialEmailMessageEvents(INT32 iMessageId);
979 static void HandleMailSpecialMessages(UINT16 usMessageId, Email* pMail);
980 static void PreProcessEmail(Email* pMail);
981
982
DisplayEmailMessage(Email * const m)983 static INT32 DisplayEmailMessage(Email* const m)
984 {
985 if (!m) return 0;
986
987 // reset redraw email message flag
988 fReDrawMessageFlag = FALSE;
989
990 // we KNOW the player is going to "read" this, so mark it as so
991 m->fRead = TRUE;
992
993 INT32 const offset = m->usOffset;
994 HandleAnySpecialEmailMessageEvents(offset);
995 HandleMailSpecialMessages(offset, m);
996
997 PreProcessEmail(m);
998
999 INT32 const by = iViewerPositionY;
1000
1001 BltVideoObject(FRAME_BUFFER, guiEmailMessage, 0, VIEWER_X, VIEWER_Y + by);
1002 BltVideoObject(FRAME_BUFFER, guiTITLEBARICONS, 0, VIEWER_X + 5, VIEWER_Y + by + 2);
1003
1004 DisplayEmailMessageSubjectDateFromLines(m, by);
1005 DrawEmailMessageDisplayTitleText(by);
1006
1007 UINT16 const h = GetFontHeight(MESSAGE_FONT);
1008 INT32 y = VIEWER_MESSAGE_BODY_START_Y + by;
1009
1010 BltVideoObject(FRAME_BUFFER, guiEmailMessage, 1, VIEWER_X, y);
1011 y += h;
1012
1013 // Blit the text background based on height
1014 for (INT32 i = 1; i < iTotalHeight / h; ++i)
1015 {
1016 BltVideoObject(FRAME_BUFFER, guiEmailMessage, 1, VIEWER_X, y);
1017 y += h;
1018 }
1019
1020 BOOLEAN onlyOnePage = giNumberOfPagesToCurrentEmail <= 2;
1021
1022 // The bottom piece to the message viewer
1023 BltVideoObject(FRAME_BUFFER, guiEmailMessage, onlyOnePage ? 2 : 3, VIEWER_X, y);
1024
1025 // Draw body of text. Any particular email can encompass more than one
1026 // "record" in the email file. Draw each record (length is number of records)
1027 if (Record const* i = pEmailPageInfo[giMessagePage].pFirstRecord)
1028 {
1029 for (INT32 y = VIEWER_MESSAGE_BODY_START_Y + by + h;;)
1030 {
1031 y += IanDisplayWrappedString(VIEWER_X + MESSAGE_X + 4, y, MESSAGE_WIDTH, MESSAGE_GAP, MESSAGE_FONT, MESSAGE_COLOR, i->pRecord, 0, IAN_WRAP_NO_SHADOW);
1032
1033 i = i->Next;
1034 if (!i) break;
1035 if ( pEmailPageInfo[giMessagePage ].pLastRecord != i) continue;
1036 if (!pEmailPageInfo[giMessagePage + 1].pFirstRecord) continue;
1037 break;
1038 }
1039 }
1040
1041 if(!onlyOnePage)
1042 {
1043 DisplayNumberOfPagesToThisEmail(by);
1044 }
1045
1046 InvalidateRegion(LAPTOP_SCREEN_UL_X, LAPTOP_SCREEN_UL_Y, LAPTOP_SCREEN_LR_X, LAPTOP_SCREEN_LR_Y);
1047
1048 return by;
1049 }
1050
1051
BtnNewOkback(GUI_BUTTON * btn,INT32 reason)1052 static void BtnNewOkback(GUI_BUTTON *btn, INT32 reason)
1053 {
1054 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1055 {
1056 fNewMailFlag=FALSE;
1057 }
1058 }
1059
1060
MakeButtonNewMail(INT32 image,INT16 x,INT16 y,GUI_CALLBACK click)1061 static GUIButtonRef MakeButtonNewMail(INT32 image, INT16 x, INT16 y, GUI_CALLBACK click)
1062 {
1063 GUIButtonRef const btn = QuickCreateButtonImg(LAPTOPDIR "/newmailbuttons.sti", image, image + 3, x, y, MSYS_PRIORITY_HIGHEST - 1, click);
1064 btn->SetCursor(CURSOR_LAPTOP_SCREEN);
1065 return btn;
1066 }
1067
1068
PrevMailPage()1069 static void PrevMailPage()
1070 {
1071 if (giMessagePage == 0) return;
1072 --giMessagePage;
1073 MarkButtonsDirty();
1074 fReDrawScreenFlag = TRUE;
1075 }
1076
1077
NextMailPage()1078 static void NextMailPage()
1079 {
1080 if (giMessagePage + 1 >= giNumberOfPagesToCurrentEmail - 1) return;
1081 ++giMessagePage;
1082 MarkButtonsDirty();
1083 fReDrawScreenFlag = TRUE;
1084 }
1085
1086
MailScrollRegionCallback(MOUSE_REGION * const,INT32 const reason)1087 static void MailScrollRegionCallback(MOUSE_REGION* const, INT32 const reason)
1088 {
1089 if (reason & MSYS_CALLBACK_REASON_WHEEL_UP)
1090 {
1091 PrevMailPage();
1092 }
1093 else if (reason & MSYS_CALLBACK_REASON_WHEEL_DOWN)
1094 {
1095 NextMailPage();
1096 }
1097 }
1098
1099
1100 static void BtnDeleteCallback(GUI_BUTTON* btn, INT32 iReason);
1101 static void BtnNextEmailPageCallback(GUI_BUTTON* btn, INT32 reason);
1102 static void BtnPreviousEmailPageCallback(GUI_BUTTON* btn, INT32 reason);
1103
1104
AddDeleteRegionsToMessageRegion(INT32 iViewerY)1105 static void AddDeleteRegionsToMessageRegion(INT32 iViewerY)
1106 {
1107 // will create/destroy mouse region for message display
1108
1109 if((fDisplayMessageFlag)&&(!fOldDisplayMessageFlag))
1110 {
1111
1112 // set old flag
1113 fOldDisplayMessageFlag=TRUE;
1114
1115 // add X button
1116 giMessageButton = QuickCreateButtonImg(LAPTOPDIR "/x.sti", 0, 1, BUTTON_X + 2, BUTTON_Y + iViewerY + 1, MSYS_PRIORITY_HIGHEST - 1, BtnMessageXCallback);
1117 giMessageButton->SetCursor(CURSOR_LAPTOP_SCREEN);
1118
1119 if( giNumberOfPagesToCurrentEmail > 2 )
1120 {
1121 // add next and previous mail page buttons
1122 {
1123 INT16 const y = LOWER_BUTTON_Y + iViewerY + 2;
1124 giMailMessageButtons[0] = MakeButtonNewMail(0, PREVIOUS_PAGE_BUTTON_X, y, BtnPreviousEmailPageCallback);
1125 giMailMessageButtons[1] = MakeButtonNewMail(1, NEXT_PAGE_BUTTON_X, y, BtnNextEmailPageCallback);
1126 }
1127 {
1128 UINT16 const x = VIEWER_X + MESSAGE_X + 1;
1129 UINT16 const y = VIEWER_MESSAGE_BODY_START_Y + iViewerPositionY;
1130 UINT16 const w = MESSAGE_WIDTH + 3;
1131 UINT16 const h = 227;
1132 MSYS_DefineRegion(&g_mail_scroll_region, x, y, x + w, y + h, MSYS_PRIORITY_HIGHEST - 2, MSYS_NO_CURSOR, NULL, MailScrollRegionCallback);
1133 }
1134 gfPageButtonsWereCreated = TRUE;
1135 }
1136
1137 giMailMessageButtons[2] = MakeButtonNewMail(2, DELETE_BUTTON_X, BUTTON_LOWER_Y + iViewerY + 2, BtnDeleteCallback);
1138
1139 // force update of screen
1140 fReDrawScreenFlag=TRUE;
1141 }
1142 else if((!fDisplayMessageFlag)&&(fOldDisplayMessageFlag))
1143 {
1144 // delete region
1145 fOldDisplayMessageFlag=FALSE;
1146 RemoveButton(giMessageButton);
1147
1148 // net/previous email page buttons
1149 if( gfPageButtonsWereCreated )
1150 {
1151 MSYS_RemoveRegion(&g_mail_scroll_region);
1152 RemoveButton(giMailMessageButtons[0] );
1153 RemoveButton(giMailMessageButtons[1] );
1154 gfPageButtonsWereCreated = FALSE;
1155 }
1156 RemoveButton(giMailMessageButtons[2] );
1157 // force update of screen
1158 fReDrawScreenFlag=TRUE;
1159 }
1160 }
1161
1162
MakeButtonYesNo(INT32 image,INT16 x,GUI_CALLBACK click)1163 static GUIButtonRef MakeButtonYesNo(INT32 image, INT16 x, GUI_CALLBACK click)
1164 {
1165 GUIButtonRef const btn = QuickCreateButtonImg(LAPTOPDIR "/yesnobuttons.sti", image, image + 1, x, NEW_BTN_Y, MSYS_PRIORITY_HIGHEST - 2, click);
1166 btn->SetCursor(CURSOR_LAPTOP_SCREEN);
1167 return btn;
1168 }
1169
1170
CreateDestroyNewMailButton()1171 void CreateDestroyNewMailButton()
1172 {
1173 static BOOLEAN fOldNewMailFlag=FALSE;
1174
1175 // check if we are video conferencing, if so, do nothing
1176 if (gubVideoConferencingMode != AIM_VIDEO_NOT_DISPLAYED_MODE)
1177 {
1178 return ;
1179 }
1180
1181
1182 if((fNewMailFlag)&&(!fOldNewMailFlag))
1183 {
1184 // create new mail dialog box button
1185
1186 // set old flag (stating button has been created)
1187 fOldNewMailFlag=TRUE;
1188
1189 giNewMailButton = MakeButtonYesNo(0, NEW_BTN_X + 10, BtnNewOkback);
1190
1191 // set up screen mask region
1192 MSYS_DefineRegion(&pScreenMask, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST - 3, CURSOR_LAPTOP_SCREEN, MSYS_NO_CALLBACK, LapTopScreenCallBack);
1193 MarkAButtonDirty(giNewMailButton);
1194 fReDrawScreenFlag = TRUE;
1195 }
1196 else if((!fNewMailFlag)&&(fOldNewMailFlag))
1197 {
1198 // reset old flag
1199 fOldNewMailFlag=FALSE;
1200
1201 // remove the button
1202 RemoveButton(giNewMailButton);
1203
1204 // remove screen mask
1205 MSYS_RemoveRegion( &pScreenMask );
1206
1207 // redraw screen
1208 fPausedReDrawScreenFlag=TRUE;
1209 }
1210 }
1211
1212
DisplayNewMailBox(void)1213 void DisplayNewMailBox(void)
1214 {
1215 // will display a new mail box whenever new mail has arrived
1216
1217 // check if we are video conferencing, if so, do nothing
1218 if (gubVideoConferencingMode != AIM_VIDEO_NOT_DISPLAYED_MODE) return;
1219
1220 // not even set, leave NOW!
1221 if (!fNewMailFlag) return;
1222
1223 BltVideoObject(FRAME_BUFFER, guiEmailWarning, 0, EMAIL_WARNING_X, EMAIL_WARNING_Y);
1224 BltVideoObject(FRAME_BUFFER, guiTITLEBARICONS, 0, EMAIL_WARNING_X + 5, EMAIL_WARNING_Y + 2);
1225
1226 SetFontAttributes(EMAIL_HEADER_FONT, FONT_WHITE);
1227
1228 // print warning
1229 MPrint(EMAIL_WARNING_X + 30, EMAIL_WARNING_Y + 8, pEmailTitleText);
1230
1231 SetFontAttributes(EMAIL_WARNING_FONT, FONT_BLACK, NO_SHADOW);
1232
1233 // printf warning string
1234 MPrint(EMAIL_WARNING_X + 60, EMAIL_WARNING_Y + 63, pNewMailStrings);
1235
1236 // invalidate region
1237 InvalidateRegion( EMAIL_WARNING_X, EMAIL_WARNING_Y, EMAIL_WARNING_X + 270, EMAIL_WARNING_Y + 200 );
1238
1239 // mark button
1240 MarkAButtonDirty(giNewMailButton);
1241
1242 // reset shadow
1243 SetFontShadow( DEFAULT_SHADOW );
1244 }
1245
1246
ReDrawNewMailBox(void)1247 void ReDrawNewMailBox(void)
1248 { // check to see if the new mail region needs to be redrawn
1249 if (!fReDrawNewMailFlag) return;
1250 fReDrawNewMailFlag = FALSE;
1251 if (!fNewMailFlag) return;
1252 DisplayNewMailBox();
1253 }
1254
1255
NextRegionButtonCallback(GUI_BUTTON * btn,INT32 reason)1256 static void NextRegionButtonCallback(GUI_BUTTON *btn, INT32 reason)
1257 {
1258 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1259 {
1260 NextListPage();
1261 }
1262 }
1263
1264
BtnPreviousEmailPageCallback(GUI_BUTTON * btn,INT32 reason)1265 static void BtnPreviousEmailPageCallback(GUI_BUTTON *btn, INT32 reason)
1266 {
1267 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1268 {
1269 PrevMailPage();
1270 }
1271 }
1272
1273
BtnNextEmailPageCallback(GUI_BUTTON * btn,INT32 reason)1274 static void BtnNextEmailPageCallback(GUI_BUTTON *btn, INT32 reason)
1275 {
1276 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1277 {
1278 NextMailPage();
1279 }
1280 }
1281
1282
PreviousRegionButtonCallback(GUI_BUTTON * btn,INT32 reason)1283 static void PreviousRegionButtonCallback(GUI_BUTTON *btn, INT32 reason)
1284 {
1285 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1286 {
1287 PrevListPage();
1288 }
1289 }
1290
1291
BtnDeleteNoback(GUI_BUTTON * btn,INT32 reason)1292 static void BtnDeleteNoback(GUI_BUTTON* btn, INT32 reason)
1293 {
1294 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1295 {
1296 MailToDelete = NULL;
1297 fReDrawScreenFlag = TRUE;
1298 }
1299 }
1300
1301
1302 static void DeleteEmail(void);
1303
1304
BtnDeleteYesback(GUI_BUTTON * btn,INT32 reason)1305 static void BtnDeleteYesback(GUI_BUTTON* btn, INT32 reason)
1306 {
1307 if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1308 {
1309 fReDrawScreenFlag = TRUE;
1310 DeleteEmail();
1311 }
1312 }
1313
1314
CreateDestroyDeleteNoticeMailButton()1315 void CreateDestroyDeleteNoticeMailButton()
1316 {
1317 static BOOLEAN fOldDeleteMailFlag=FALSE;
1318 if (MailToDelete != NULL && !fOldDeleteMailFlag)
1319 {
1320 // confirm delete email buttons
1321
1322 // YES/NO buttons
1323 fOldDeleteMailFlag=TRUE;
1324 giDeleteMailButton[0] = MakeButtonYesNo(0, NEW_BTN_X + 1, BtnDeleteYesback);
1325 giDeleteMailButton[1] = MakeButtonYesNo(2, NEW_BTN_X + 40, BtnDeleteNoback);
1326
1327 // set up screen mask to prevent other actions while delete mail box is destroyed
1328 MSYS_DefineRegion(&pDeleteScreenMask, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST - 3, CURSOR_LAPTOP_SCREEN, MSYS_NO_CALLBACK, LapTopScreenCallBack);
1329
1330 // force update
1331 fReDrawScreenFlag = TRUE;
1332
1333 }
1334 else if (MailToDelete == NULL && fOldDeleteMailFlag)
1335 {
1336 // clear out the buttons and screen mask
1337 fOldDeleteMailFlag=FALSE;
1338 RemoveButton( giDeleteMailButton[0] );
1339 RemoveButton( giDeleteMailButton[1] );
1340
1341 // the region
1342 MSYS_RemoveRegion(&pDeleteScreenMask);
1343
1344 // force refresh
1345 fReDrawScreenFlag=TRUE;
1346 }
1347 }
1348
1349
DisplayDeleteNotice(Email * pMail)1350 static BOOLEAN DisplayDeleteNotice(Email* pMail)
1351 {
1352 // will display a delete mail box whenever delete mail has arrived
1353 if( !fReDrawScreenFlag )
1354 {
1355 // no redraw flag, leave
1356 return( FALSE );
1357 }
1358
1359 // error check.. no valid message passed
1360 if( pMail == NULL )
1361 {
1362 return ( FALSE );
1363 }
1364
1365 BltVideoObject(FRAME_BUFFER, guiEmailWarning, 0, EMAIL_WARNING_X, EMAIL_WARNING_Y);
1366
1367 SetFontAttributes(EMAIL_HEADER_FONT, FONT_WHITE);
1368
1369 BltVideoObject(FRAME_BUFFER, guiTITLEBARICONS, 0, EMAIL_WARNING_X + 5, EMAIL_WARNING_Y + 2);
1370
1371 // title
1372 MPrint(EMAIL_WARNING_X + 30, EMAIL_WARNING_Y + 8, pEmailTitleText);
1373
1374 SetFontAttributes(EMAIL_WARNING_FONT, FONT_BLACK, NO_SHADOW);
1375
1376 // draw text based on mail being read or not
1377 if((pMail->fRead))
1378 MPrint(EMAIL_WARNING_X + 95, EMAIL_WARNING_Y + 65, pDeleteMailStrings[0]);
1379 else
1380 MPrint(EMAIL_WARNING_X + 70, EMAIL_WARNING_Y + 65, pDeleteMailStrings[1]);
1381
1382
1383 // invalidate screen area, for refresh
1384
1385 if( ! fNewMailFlag )
1386 {
1387 // draw buttons
1388 MarkButtonsDirty( );
1389 InvalidateRegion(EMAIL_WARNING_X, EMAIL_WARNING_Y ,EMAIL_WARNING_X+EMAIL_WARNING_WIDTH,EMAIL_WARNING_Y+EMAIL_WARNING_HEIGHT);
1390 }
1391
1392 // reset font shadow
1393 SetFontShadow(DEFAULT_SHADOW);
1394
1395 return ( TRUE );
1396 }
1397
1398
DeleteEmail(void)1399 static void DeleteEmail(void)
1400 {
1401
1402 // error check, invalid mail, or not time to delete mail
1403 if (MailToDelete == NULL) return;
1404 // remove the message
1405 RemoveEmailMessage(MailToDelete);
1406 MailToDelete = NULL;
1407
1408 // stop displaying message, if so
1409 fDisplayMessageFlag = FALSE;
1410
1411 // upadte list
1412 PlaceMessagesinPages();
1413
1414 // if all of a sudden we are beyond last page, move back one
1415 if(iCurrentPage > iLastPage)
1416 iCurrentPage=iLastPage;
1417
1418 // rerender mail list
1419 RenderEmail();
1420
1421 fReDrawScreenFlag=TRUE;
1422
1423 InvalidateScreen();
1424 }
1425
1426
FromCallback(GUI_BUTTON * btn,INT32 iReason)1427 static void FromCallback(GUI_BUTTON *btn, INT32 iReason)
1428 {
1429 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1430 {
1431 // sort messages based on sender name, then replace into pages of email
1432 fSortSenderUpwards = !fSortSenderUpwards;
1433 SortMessages(SENDER);
1434 PlaceMessagesinPages();
1435 }
1436 }
1437
1438
SubjectCallback(GUI_BUTTON * btn,INT32 iReason)1439 static void SubjectCallback(GUI_BUTTON *btn, INT32 iReason)
1440 {
1441 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1442 {
1443 // sort message on subject and reorder list
1444 fSortSubjectUpwards = !fSortSubjectUpwards;
1445 SortMessages(SUBJECT);
1446 PlaceMessagesinPages();
1447 }
1448 }
1449
1450
BtnDeleteCallback(GUI_BUTTON * btn,INT32 iReason)1451 static void BtnDeleteCallback(GUI_BUTTON *btn, INT32 iReason)
1452 {
1453 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1454 {
1455 MailToDelete = CurrentMail;
1456 }
1457 }
1458
1459
DateCallback(GUI_BUTTON * btn,INT32 iReason)1460 static void DateCallback(GUI_BUTTON *btn, INT32 iReason)
1461 {
1462 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1463 {
1464 // sort messages based on date recieved and reorder lsit
1465 fSortDateUpwards = !fSortDateUpwards;
1466 SortMessages(RECEIVED);
1467 PlaceMessagesinPages();
1468 }
1469 }
1470
1471
ReadCallback(GUI_BUTTON * btn,INT32 iReason)1472 static void ReadCallback(GUI_BUTTON *btn, INT32 iReason)
1473 {
1474 if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
1475 {
1476 // sort messages based on date recieved and reorder lsit
1477 SortMessages(READ);
1478 PlaceMessagesinPages();
1479 }
1480 }
1481
1482
DisplayTextOnTitleBar(void)1483 static void DisplayTextOnTitleBar(void)
1484 {
1485 // draw email screen title text
1486 SetFontAttributes(EMAIL_TITLE_FONT, FONT_WHITE);
1487 MPrint(EMAIL_TITLE_X, EMAIL_TITLE_Y, pEmailTitleText);
1488 }
1489
1490
DestroyMailScreenButtons(void)1491 static void DestroyMailScreenButtons(void)
1492 {
1493 // this function will destory the buttons used in the email screen
1494
1495 // the sort email buttons
1496 RemoveButton( giSortButton[0] );
1497 RemoveButton( giSortButton[1] );
1498 RemoveButton( giSortButton[2] );
1499 RemoveButton( giSortButton[3] );
1500 }
1501
1502
MakeButton(UINT idx,INT16 x,GUI_CALLBACK click,const ST::string & text)1503 static void MakeButton(UINT idx, INT16 x, GUI_CALLBACK click, const ST::string& text)
1504 {
1505 GUIButtonRef const btn = QuickCreateButtonImg(LAPTOPDIR "/mailbuttons.sti", idx, idx + 4, x, FROM_BOX_Y, MSYS_PRIORITY_HIGHEST - 1, click);
1506 giSortButton[idx] = btn;
1507 btn->SetCursor(CURSOR_LAPTOP_SCREEN);
1508 if (!text.empty())
1509 {
1510 btn->SpecifyGeneralTextAttributes(text, EMAIL_WARNING_FONT, FONT_BLACK, FONT_BLACK);
1511 }
1512 }
1513
1514
CreateMailScreenButtons(void)1515 static void CreateMailScreenButtons(void)
1516 {
1517 // create sort buttons, right now - not finished
1518 MakeButton(0, ENVELOPE_BOX_X, ReadCallback, ST::null);
1519 MakeButton(1, FROM_BOX_X, FromCallback, pEmailHeaders[FROM_HEADER]);
1520 MakeButton(2, SUBJECT_BOX_X, SubjectCallback, pEmailHeaders[SUBJECT_HEADER]);
1521 MakeButton(3, DATE_BOX_X, DateCallback, pEmailHeaders[RECD_HEADER]);
1522 }
1523
1524
DisplayEmailMessageSubjectDateFromLines(Email * pMail,INT32 iViewerY)1525 static void DisplayEmailMessageSubjectDateFromLines(Email* pMail, INT32 iViewerY)
1526 {
1527 // this procedure will draw the title/headers to From, Subject, Date fields in the display
1528 // message box
1529
1530 SetFontAttributes(MESSAGE_FONT, FONT_BLACK, NO_SHADOW);
1531
1532 // all headers, but not info are right justified
1533 INT16 usX;
1534 INT16 usY;
1535
1536 // print from
1537 FindFontRightCoordinates(MESSAGE_HEADER_X - 20, MESSAGE_FROM_Y + iViewerY, MESSAGE_HEADER_WIDTH, MESSAGE_FROM_Y + GetFontHeight(MESSAGE_FONT), pEmailHeaders[0], MESSAGE_FONT, &usX, &usY);
1538 MPrint(usX, MESSAGE_FROM_Y + iViewerY, pEmailHeaders[0]);
1539
1540 // the actual from info
1541 MPrint( MESSAGE_HEADER_X+MESSAGE_HEADER_WIDTH-13, MESSAGE_FROM_Y + iViewerY, pSenderNameList[pMail->ubSender]);
1542
1543
1544 // print date
1545 FindFontRightCoordinates(MESSAGE_HEADER_X + 168, MESSAGE_DATE_Y + iViewerY, MESSAGE_HEADER_WIDTH, MESSAGE_DATE_Y + GetFontHeight(MESSAGE_FONT), pEmailHeaders[2], MESSAGE_FONT, &usX, &usY);
1546 MPrint(usX, MESSAGE_DATE_Y + iViewerY, pEmailHeaders[2]);
1547
1548 // the actual date info
1549 MPrint(MESSAGE_HEADER_X + 235, MESSAGE_DATE_Y + iViewerY, ST::format("{}", pMail->iDate / (24 * 60)));
1550
1551 // print subject
1552 FindFontRightCoordinates(MESSAGE_HEADER_X - 20, MESSAGE_SUBJECT_Y, MESSAGE_HEADER_WIDTH, MESSAGE_SUBJECT_Y + GetFontHeight(MESSAGE_FONT), pEmailHeaders[1], MESSAGE_FONT, &usX, &usY);
1553 MPrint(usX, MESSAGE_SUBJECT_Y + iViewerY, pEmailHeaders[1]);
1554
1555 // the actual subject info
1556 IanDisplayWrappedString(SUBJECT_LINE_X + 2, SUBJECT_LINE_Y + 2 + iViewerY, SUBJECT_LINE_WIDTH, MESSAGE_GAP, MESSAGE_FONT, MESSAGE_COLOR, pMail->pSubject, 0, 0);
1557
1558 // reset shadow
1559 SetFontShadow(DEFAULT_SHADOW);
1560 }
1561
1562
DrawEmailMessageDisplayTitleText(INT32 iViewerY)1563 static void DrawEmailMessageDisplayTitleText(INT32 iViewerY)
1564 {
1565 // this procedure will display the title of the email message display box
1566 SetFontAttributes(EMAIL_HEADER_FONT, FONT_WHITE);
1567 MPrint(VIEWER_X + 30, VIEWER_Y + 8 + iViewerY, pEmailTitleText);
1568 }
1569
1570
DrawLineDividers(void)1571 static void DrawLineDividers(void)
1572 {
1573 // this function draws divider lines between lines of text
1574 INT32 iCounter=0;
1575
1576 for(iCounter=1; iCounter < 19; iCounter++)
1577 {
1578 BltVideoObject(FRAME_BUFFER, guiMAILDIVIDER, 0, INDIC_X - 10, MIDDLE_Y + iCounter * MIDDLE_WIDTH - 1);
1579 }
1580 }
1581
1582
ClearOutEmailMessageRecordsList(void)1583 static void ClearOutEmailMessageRecordsList(void)
1584 {
1585 Record* pTempRecord;
1586 INT32 iCounter = 0;
1587
1588 // runt hrough list freeing records up
1589 while(pMessageRecordList)
1590 {
1591 // set temp to current
1592 pTempRecord = pMessageRecordList;
1593
1594 // next element
1595 pMessageRecordList = pMessageRecordList -> Next;
1596
1597 delete pTempRecord;
1598 }
1599
1600 for( iCounter = 0; iCounter < MAX_NUMBER_EMAIL_PAGES; iCounter++ )
1601 {
1602 pEmailPageInfo[ iCounter ].pFirstRecord = NULL;
1603 pEmailPageInfo[ iCounter ].pLastRecord = NULL;
1604 pEmailPageInfo[ iCounter ].iPageNumber = iCounter;
1605 }
1606
1607 // null out list
1608 pMessageRecordList = NULL;
1609 }
1610
1611
AddEmailRecordToList(const ST::string & text)1612 static void AddEmailRecordToList(const ST::string& text)
1613 {
1614 Record* const e = new Record{};
1615 e->Next = NULL;
1616 e->pRecord = text;
1617
1618 // Append node to list
1619 Record** anchor = &pMessageRecordList;
1620 while (*anchor != NULL) anchor = &(*anchor)->Next;
1621 *anchor = e;
1622 }
1623
1624
UpDateMessageRecordList(void)1625 static void UpDateMessageRecordList(void)
1626 {
1627
1628 // simply checks to see if old and new message ids are the same, if so, do nothing
1629 // otherwise clear list
1630
1631 if (CurrentMail != PreviousMail)
1632 {
1633 // if chenged, clear list
1634 ClearOutEmailMessageRecordsList( );
1635
1636 // set prev to current
1637 PreviousMail = CurrentMail;
1638 }
1639
1640 }
1641
1642
HandleAnySpecialEmailMessageEvents(INT32 iMessageId)1643 static void HandleAnySpecialEmailMessageEvents(INT32 iMessageId)
1644 {
1645 // handles any special message events
1646 switch( iMessageId )
1647 {
1648 case( IMP_EMAIL_AGAIN ):
1649 SetBookMark(IMP_BOOKMARK);
1650 break;
1651 case( IMP_EMAIL_INTRO ):
1652 SetBookMark(IMP_BOOKMARK);
1653 break;
1654 }
1655 }
1656
1657
ReDisplayBoxes(void)1658 static void ReDisplayBoxes(void)
1659 {
1660 // the email message itself
1661 if(fDisplayMessageFlag)
1662 {
1663 // this simply redraws message with button manipulation
1664 DisplayEmailMessage(CurrentMail);
1665 }
1666
1667 if (MailToDelete != NULL) DisplayDeleteNotice(MailToDelete);
1668
1669 if(fNewMailFlag)
1670 {
1671 // if new mail, redisplay box
1672 DisplayNewMailBox( );
1673 }
1674 }
1675
1676
1677 static void HandleIMPCharProfileResultsMessage(void);
1678 static void ModifyInsuranceEmails(UINT16 usMessageId, Email* pMail, UINT8 ubNumberOfRecords);
1679
1680
HandleMailSpecialMessages(UINT16 usMessageId,Email * pMail)1681 static void HandleMailSpecialMessages(UINT16 usMessageId, Email* pMail)
1682 {
1683 // this procedure will handle special cases of email messages that are not stored in email.edt, or need special processing
1684 switch( usMessageId )
1685 {
1686 case( IMP_EMAIL_PROFILE_RESULTS ):
1687
1688 HandleIMPCharProfileResultsMessage( );
1689 break;
1690 case( MERC_INTRO ):
1691 SetBookMark( MERC_BOOKMARK );
1692 fReDrawScreenFlag = TRUE;
1693 break;
1694
1695
1696 case INSUR_PAYMENT:
1697 case INSUR_SUSPIC:
1698 case INSUR_SUSPIC_2:
1699 case INSUR_INVEST_OVER:
1700 ModifyInsuranceEmails(usMessageId, pMail, INSUR_PAYMENT_LENGTH);
1701 break;
1702
1703 case INSUR_1HOUR_FRAUD:
1704 ModifyInsuranceEmails(usMessageId, pMail, INSUR_1HOUR_FRAUD_LENGTH);
1705 break;
1706
1707 case MERC_NEW_SITE_ADDRESS:
1708 //Set the book mark so the player can access the site
1709 SetBookMark( MERC_BOOKMARK );
1710 break;
1711
1712 case MERC_DIED_ON_OTHER_ASSIGNMENT:
1713 ModifyInsuranceEmails(usMessageId, pMail, MERC_DIED_ON_OTHER_ASSIGNMENT_LENGTH);
1714 break;
1715
1716 case AIM_MEDICAL_DEPOSIT_REFUND:
1717 case AIM_MEDICAL_DEPOSIT_NO_REFUND:
1718 case AIM_MEDICAL_DEPOSIT_PARTIAL_REFUND:
1719 ModifyInsuranceEmails(usMessageId, pMail, AIM_MEDICAL_DEPOSIT_REFUND_LENGTH);
1720 break;
1721 }
1722 }
1723
1724
1725
1726 #define IMP_RESULTS_INTRO_LENGTH 9
1727
1728 #define IMP_RESULTS_PERSONALITY_INTRO IMP_RESULTS_INTRO_LENGTH
1729 #define IMP_RESULTS_PERSONALITY_INTRO_LENGTH 5
1730 #define IMP_PERSONALITY_NORMAL IMP_RESULTS_PERSONALITY_INTRO + IMP_RESULTS_PERSONALITY_INTRO_LENGTH
1731 #define IMP_PERSONALITY_LENGTH 4
1732 #define IMP_PERSONALITY_HEAT IMP_PERSONALITY_NORMAL + IMP_PERSONALITY_LENGTH
1733 #define IMP_PERSONALITY_NERVOUS IMP_PERSONALITY_HEAT + IMP_PERSONALITY_LENGTH
1734 #define IMP_PERSONALITY_CLAUSTROPHOBIC IMP_PERSONALITY_NERVOUS + IMP_PERSONALITY_LENGTH
1735 #define IMP_PERSONALITY_NONSWIMMER IMP_PERSONALITY_CLAUSTROPHOBIC + IMP_PERSONALITY_LENGTH
1736 #define IMP_PERSONALITY_FEAR_OF_INSECTS IMP_PERSONALITY_NONSWIMMER + IMP_PERSONALITY_LENGTH
1737 #define IMP_PERSONALITY_FORGETFUL IMP_PERSONALITY_FEAR_OF_INSECTS + IMP_PERSONALITY_LENGTH + 1
1738 #define IMP_PERSONALITY_PSYCHO IMP_PERSONALITY_FORGETFUL + IMP_PERSONALITY_LENGTH
1739 #define IMP_RESULTS_ATTITUDE_INTRO IMP_PERSONALITY_PSYCHO + IMP_PERSONALITY_LENGTH + 1
1740 #define IMP_RESULTS_ATTITUDE_LENGTH 5
1741 #define IMP_ATTITUDE_LENGTH 5
1742 #define IMP_ATTITUDE_NORMAL IMP_RESULTS_ATTITUDE_INTRO + IMP_RESULTS_ATTITUDE_LENGTH
1743 #define IMP_ATTITUDE_FRIENDLY IMP_ATTITUDE_NORMAL + IMP_ATTITUDE_LENGTH
1744 #define IMP_ATTITUDE_LONER IMP_ATTITUDE_FRIENDLY + IMP_ATTITUDE_LENGTH + 1
1745 #define IMP_ATTITUDE_OPTIMIST IMP_ATTITUDE_LONER + IMP_ATTITUDE_LENGTH + 1
1746 #define IMP_ATTITUDE_PESSIMIST IMP_ATTITUDE_OPTIMIST + IMP_ATTITUDE_LENGTH + 1
1747 #define IMP_ATTITUDE_AGGRESSIVE IMP_ATTITUDE_PESSIMIST + IMP_ATTITUDE_LENGTH + 1
1748 #define IMP_ATTITUDE_ARROGANT IMP_ATTITUDE_AGGRESSIVE + IMP_ATTITUDE_LENGTH + 1
1749 #define IMP_ATTITUDE_ASSHOLE IMP_ATTITUDE_ARROGANT + IMP_ATTITUDE_LENGTH + 1
1750 #define IMP_ATTITUDE_COWARD IMP_ATTITUDE_ASSHOLE + IMP_ATTITUDE_LENGTH
1751 #define IMP_RESULTS_SKILLS IMP_ATTITUDE_COWARD + IMP_ATTITUDE_LENGTH + 1
1752 #define IMP_RESULTS_SKILLS_LENGTH 7
1753 #define IMP_SKILLS_IMPERIAL_SKILLS IMP_RESULTS_SKILLS + IMP_RESULTS_SKILLS_LENGTH + 1
1754 #define IMP_SKILLS_IMPERIAL_MARK IMP_SKILLS_IMPERIAL_SKILLS + 1
1755 #define IMP_SKILLS_IMPERIAL_MECH IMP_SKILLS_IMPERIAL_SKILLS + 2
1756 #define IMP_SKILLS_IMPERIAL_EXPL IMP_SKILLS_IMPERIAL_SKILLS + 3
1757 #define IMP_SKILLS_IMPERIAL_MED IMP_SKILLS_IMPERIAL_SKILLS + 4
1758
1759 #define IMP_SKILLS_NEED_TRAIN_SKILLS IMP_SKILLS_IMPERIAL_MED + 1
1760 #define IMP_SKILLS_NEED_TRAIN_MARK IMP_SKILLS_NEED_TRAIN_SKILLS + 1
1761 #define IMP_SKILLS_NEED_TRAIN_MECH IMP_SKILLS_NEED_TRAIN_SKILLS + 2
1762 #define IMP_SKILLS_NEED_TRAIN_EXPL IMP_SKILLS_NEED_TRAIN_SKILLS + 3
1763 #define IMP_SKILLS_NEED_TRAIN_MED IMP_SKILLS_NEED_TRAIN_SKILLS + 4
1764
1765 #define IMP_SKILLS_NO_SKILL IMP_SKILLS_NEED_TRAIN_MED + 1
1766 #define IMP_SKILLS_NO_SKILL_MARK IMP_SKILLS_NO_SKILL + 1
1767 #define IMP_SKILLS_NO_SKILL_MECH IMP_SKILLS_NO_SKILL + 2
1768 #define IMP_SKILLS_NO_SKILL_EXPL IMP_SKILLS_NO_SKILL + 3
1769 #define IMP_SKILLS_NO_SKILL_MED IMP_SKILLS_NO_SKILL + 4
1770
1771 #define IMP_SKILLS_SPECIAL_INTRO IMP_SKILLS_NO_SKILL_MED + 1
1772 #define IMP_SKILLS_SPECIAL_INTRO_LENGTH 2
1773 #define IMP_SKILLS_SPECIAL_LOCK IMP_SKILLS_SPECIAL_INTRO + IMP_SKILLS_SPECIAL_INTRO_LENGTH
1774 #define IMP_SKILLS_SPECIAL_HAND IMP_SKILLS_SPECIAL_LOCK + 1
1775 #define IMP_SKILLS_SPECIAL_ELEC IMP_SKILLS_SPECIAL_HAND + 1
1776 #define IMP_SKILLS_SPECIAL_NIGHT IMP_SKILLS_SPECIAL_ELEC + 1
1777 #define IMP_SKILLS_SPECIAL_THROW IMP_SKILLS_SPECIAL_NIGHT + 1
1778 #define IMP_SKILLS_SPECIAL_TEACH IMP_SKILLS_SPECIAL_THROW + 1
1779 #define IMP_SKILLS_SPECIAL_HEAVY IMP_SKILLS_SPECIAL_TEACH + 1
1780 #define IMP_SKILLS_SPECIAL_AUTO IMP_SKILLS_SPECIAL_HEAVY + 1
1781 #define IMP_SKILLS_SPECIAL_STEALTH IMP_SKILLS_SPECIAL_AUTO + 1
1782 #define IMP_SKILLS_SPECIAL_AMBI IMP_SKILLS_SPECIAL_STEALTH + 1
1783 #define IMP_SKILLS_SPECIAL_THIEF IMP_SKILLS_SPECIAL_AMBI + 1
1784 #define IMP_SKILLS_SPECIAL_MARTIAL IMP_SKILLS_SPECIAL_THIEF + 1
1785 #define IMP_SKILLS_SPECIAL_KNIFE IMP_SKILLS_SPECIAL_MARTIAL + 1
1786
1787 #define IMP_RESULTS_PHYSICAL IMP_SKILLS_SPECIAL_KNIFE + 1
1788 #define IMP_RESULTS_PHYSICAL_LENGTH 7
1789
1790 #define IMP_PHYSICAL_SUPER IMP_RESULTS_PHYSICAL + IMP_RESULTS_PHYSICAL_LENGTH
1791 #define IMP_PHYSICAL_SUPER_LENGTH 1
1792
1793 #define IMP_PHYSICAL_SUPER_HEALTH IMP_PHYSICAL_SUPER + IMP_PHYSICAL_SUPER_LENGTH
1794 #define IMP_PHYSICAL_SUPER_AGILITY IMP_PHYSICAL_SUPER_HEALTH + 1
1795 #define IMP_PHYSICAL_SUPER_DEXTERITY IMP_PHYSICAL_SUPER_AGILITY + 1
1796 #define IMP_PHYSICAL_SUPER_STRENGTH IMP_PHYSICAL_SUPER_DEXTERITY + 1
1797 #define IMP_PHYSICAL_SUPER_LEADERSHIP IMP_PHYSICAL_SUPER_STRENGTH + 1
1798 #define IMP_PHYSICAL_SUPER_WISDOM IMP_PHYSICAL_SUPER_LEADERSHIP + 1
1799
1800 #define IMP_PHYSICAL_LOW IMP_PHYSICAL_SUPER_WISDOM + 1
1801 #define IMP_PHYSICAL_LOW_LENGTH 1
1802
1803 #define IMP_PHYSICAL_LOW_HEALTH IMP_PHYSICAL_LOW + IMP_PHYSICAL_LOW_LENGTH
1804 #define IMP_PHYSICAL_LOW_AGILITY IMP_PHYSICAL_LOW_HEALTH + 1
1805 #define IMP_PHYSICAL_LOW_DEXTERITY IMP_PHYSICAL_LOW_AGILITY + 2
1806 #define IMP_PHYSICAL_LOW_STRENGTH IMP_PHYSICAL_LOW_DEXTERITY + 1
1807 #define IMP_PHYSICAL_LOW_LEADERSHIP IMP_PHYSICAL_LOW_STRENGTH + 1
1808 #define IMP_PHYSICAL_LOW_WISDOM IMP_PHYSICAL_LOW_LEADERSHIP + 1
1809
1810
1811 #define IMP_PHYSICAL_VERY_LOW IMP_PHYSICAL_LOW_WISDOM + 1
1812 #define IMP_PHYSICAL_VERY_LOW_LENGTH 1
1813
1814 #define IMP_PHYSICAL_VERY_LOW_HEALTH IMP_PHYSICAL_VERY_LOW + IMP_PHYSICAL_VERY_LOW_LENGTH
1815 #define IMP_PHYSICAL_VERY_LOW_AGILITY IMP_PHYSICAL_VERY_LOW_HEALTH + 1
1816 #define IMP_PHYSICAL_VERY_LOW_DEXTERITY IMP_PHYSICAL_VERY_LOW_AGILITY + 1
1817 #define IMP_PHYSICAL_VERY_LOW_STRENGTH IMP_PHYSICAL_VERY_LOW_DEXTERITY + 1
1818 #define IMP_PHYSICAL_VERY_LOW_LEADERSHIP IMP_PHYSICAL_VERY_LOW_STRENGTH + 1
1819 #define IMP_PHYSICAL_VERY_LOW_WISDOM IMP_PHYSICAL_VERY_LOW_LEADERSHIP + 1
1820
1821
1822 #define IMP_PHYSICAL_END IMP_PHYSICAL_VERY_LOW_WISDOM + 1
1823 #define IMP_PHYSICAL_END_LENGTH 3
1824
1825 #define IMP_RESULTS_PORTRAIT IMP_PHYSICAL_END + IMP_PHYSICAL_END_LENGTH
1826 #define IMP_RESULTS_PORTRAIT_LENGTH 6
1827
1828
1829 #define IMP_PORTRAIT_MALE_1 IMP_RESULTS_PORTRAIT + IMP_RESULTS_PORTRAIT_LENGTH
1830 #define IMP_PORTRAIT_MALE_2 IMP_PORTRAIT_MALE_1 + 4
1831 #define IMP_PORTRAIT_MALE_3 IMP_PORTRAIT_MALE_2 + 4
1832 #define IMP_PORTRAIT_MALE_4 IMP_PORTRAIT_MALE_3 + 4
1833 #define IMP_PORTRAIT_MALE_5 IMP_PORTRAIT_MALE_4 + 4
1834 #define IMP_PORTRAIT_MALE_6 IMP_PORTRAIT_MALE_5 + 4
1835
1836 #define IMP_PORTRAIT_FEMALE_1 IMP_PORTRAIT_MALE_6 + 4
1837 #define IMP_PORTRAIT_FEMALE_2 IMP_PORTRAIT_FEMALE_1 + 4
1838 #define IMP_PORTRAIT_FEMALE_3 IMP_PORTRAIT_FEMALE_2 + 4
1839 #define IMP_PORTRAIT_FEMALE_4 IMP_PORTRAIT_FEMALE_3 + 4
1840 #define IMP_PORTRAIT_FEMALE_5 IMP_PORTRAIT_FEMALE_4 + 4
1841 #define IMP_PORTRAIT_FEMALE_6 IMP_PORTRAIT_FEMALE_5 + 4
1842
1843
1844
1845 #define IMP_RESULTS_END IMP_PORTRAIT_FEMALE_6 + 1
1846 #define IMP_RESULTS_END_LENGTH 3
1847
1848
1849 enum SkillBits
1850 {
1851 SKILL_NONE = 0,
1852 SKILL_MECH = 1 << 0,
1853 SKILL_MARK = 1 << 1,
1854 SKILL_MED = 1 << 2,
1855 SKILL_EXPL = 1 << 3
1856 };
1857 ENUM_BITSET(SkillBits)
1858
1859
1860 enum PhysicalBits
1861 {
1862 PHYS_NONE = 0,
1863 PHYS_HLTH = 1 << 0,
1864 PHYS_DEX = 1 << 1,
1865 PHYS_STR = 1 << 2,
1866 PHYS_AGI = 1 << 3,
1867 PHYS_WIS = 1 << 4,
1868 PHYS_LDR = 1 << 5
1869 };
ENUM_BITSET(PhysicalBits)1870 ENUM_BITSET(PhysicalBits)
1871
1872
1873 static ST::string LoadIMPResultText(UINT32 Offset)
1874 {
1875 return GCM->loadEncryptedString(BINARYDATADIR "/impass.edt", MAIL_STRING_SIZE * Offset, MAIL_STRING_SIZE);
1876 }
1877
1878
AddIMPResultText(UINT32 Offset)1879 static void AddIMPResultText(UINT32 Offset)
1880 {
1881 ST::string Text = LoadIMPResultText(Offset);
1882 AddEmailRecordToList(Text);
1883 }
1884
1885
AddSkillTraitText(MERCPROFILESTRUCT const & imp,SkillTrait const Skill,UINT32 const Offset)1886 static void AddSkillTraitText(MERCPROFILESTRUCT const& imp, SkillTrait const Skill, UINT32 const Offset)
1887 {
1888 if (HasSkillTrait(imp, Skill)) AddIMPResultText(Offset);
1889 }
1890
1891
HandleIMPCharProfileResultsMessage(void)1892 static void HandleIMPCharProfileResultsMessage(void)
1893 {
1894 // special case, IMP profile return
1895 INT32 iOffSet;
1896 INT32 iEndOfSection;
1897
1898 INT32 iRand = Random(32767);
1899
1900 if (pMessageRecordList != NULL) return;
1901 // list doesn't exist, reload
1902
1903 MERCPROFILESTRUCT const& imp = GetProfile(PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId);
1904
1905 // load intro
1906 iEndOfSection = IMP_RESULTS_INTRO_LENGTH;
1907 for (INT32 i = 0; i < iEndOfSection; ++i)
1908 {
1909 ST::string pString = LoadIMPResultText(i);
1910
1911 // have to place players name into string for first record
1912 if (i == 0)
1913 {
1914 ST::string zTemp = ST::format(" {}", imp.zName);
1915 pString += zTemp;
1916 }
1917
1918 AddEmailRecordToList(pString);
1919 }
1920
1921 // now the personality intro
1922 iOffSet = IMP_RESULTS_PERSONALITY_INTRO;
1923 iEndOfSection = IMP_RESULTS_PERSONALITY_INTRO_LENGTH + 1;
1924 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
1925
1926 // personality itself
1927 switch (imp.bPersonalityTrait)
1928 {
1929 // normal as can be
1930 case NO_PERSONALITYTRAIT: iOffSet = IMP_PERSONALITY_NORMAL; break;
1931 case HEAT_INTOLERANT: iOffSet = IMP_PERSONALITY_HEAT; break;
1932 case NERVOUS: iOffSet = IMP_PERSONALITY_NERVOUS; break;
1933 case CLAUSTROPHOBIC: iOffSet = IMP_PERSONALITY_CLAUSTROPHOBIC; break;
1934 case NONSWIMMER: iOffSet = IMP_PERSONALITY_NONSWIMMER; break;
1935 case FEAR_OF_INSECTS: iOffSet = IMP_PERSONALITY_FEAR_OF_INSECTS; break;
1936 case FORGETFUL: iOffSet = IMP_PERSONALITY_FORGETFUL; break;
1937 case PSYCHO: iOffSet = IMP_PERSONALITY_PSYCHO; break;
1938 }
1939
1940 // personality tick
1941 // DEF: removed 1/12/99, cause it was changing the length of email that were already calculated
1942 // AddIMPResultText(iOffSet + Random(IMP_PERSONALITY_LENGTH - 1) + 1);
1943 AddIMPResultText(iOffSet + 1);
1944
1945 // persoanlity paragraph
1946 AddIMPResultText(iOffSet + IMP_PERSONALITY_LENGTH);
1947
1948 // extra paragraph for bugs
1949 if (imp.bPersonalityTrait == FEAR_OF_INSECTS)
1950 {
1951 // persoanlity paragraph
1952 AddIMPResultText(iOffSet + IMP_PERSONALITY_LENGTH + 1);
1953 }
1954
1955 // attitude intro
1956 // now the personality intro
1957 iOffSet = IMP_RESULTS_ATTITUDE_INTRO;
1958 iEndOfSection = IMP_RESULTS_ATTITUDE_LENGTH;
1959 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
1960
1961 // personality itself
1962 switch (imp.bAttitude)
1963 {
1964 // normal as can be
1965 case ATT_NORMAL: iOffSet = IMP_ATTITUDE_NORMAL; break;
1966 case ATT_FRIENDLY: iOffSet = IMP_ATTITUDE_FRIENDLY; break;
1967 case ATT_LONER: iOffSet = IMP_ATTITUDE_LONER; break;
1968 case ATT_OPTIMIST: iOffSet = IMP_ATTITUDE_OPTIMIST; break;
1969 case ATT_PESSIMIST: iOffSet = IMP_ATTITUDE_PESSIMIST; break;
1970 case ATT_AGGRESSIVE: iOffSet = IMP_ATTITUDE_AGGRESSIVE; break;
1971 case ATT_ARROGANT: iOffSet = IMP_ATTITUDE_ARROGANT; break;
1972 case ATT_ASSHOLE: iOffSet = IMP_ATTITUDE_ASSHOLE; break;
1973 case ATT_COWARD: iOffSet = IMP_ATTITUDE_COWARD; break;
1974 }
1975
1976 // attitude title
1977 AddIMPResultText(iOffSet);
1978
1979 // attitude tick
1980 // DEF: removed 1/12/99, cause it was changing the length of email that were already calculated
1981 // AddIMPResultText(iOffSet + Random(IMP_ATTITUDE_LENGTH - 2) + 1);
1982 AddIMPResultText(iOffSet + 1);
1983
1984 // attitude paragraph
1985 AddIMPResultText(iOffSet + IMP_ATTITUDE_LENGTH - 1);
1986
1987 //check for second paragraph
1988 if (iOffSet != IMP_ATTITUDE_NORMAL)
1989 {
1990 // attitude paragraph
1991 AddIMPResultText(iOffSet + IMP_ATTITUDE_LENGTH);
1992 }
1993
1994
1995 // skills
1996 // now the skills intro
1997 iOffSet = IMP_RESULTS_SKILLS;
1998 iEndOfSection = IMP_RESULTS_SKILLS_LENGTH;
1999 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
2000
2001
2002 SkillBits Skill;
2003
2004 Skill = SKILL_NONE;
2005 if (imp.bMarksmanship >= SUPER_SKILL_VALUE) Skill |= SKILL_MARK;
2006 if (imp.bMedical >= SUPER_SKILL_VALUE) Skill |= SKILL_MED;
2007 if (imp.bMechanical >= SUPER_SKILL_VALUE) Skill |= SKILL_MECH;
2008 if (imp.bExplosive >= SUPER_SKILL_VALUE) Skill |= SKILL_EXPL;
2009
2010 if (Skill != SKILL_NONE) AddIMPResultText(IMP_SKILLS_IMPERIAL_SKILLS);
2011
2012 if (Skill & SKILL_MARK) AddIMPResultText(IMP_SKILLS_IMPERIAL_MARK);
2013 if (Skill & SKILL_MED) AddIMPResultText(IMP_SKILLS_IMPERIAL_MED);
2014 if (Skill & SKILL_MECH) AddIMPResultText(IMP_SKILLS_IMPERIAL_MECH);
2015 if (Skill & SKILL_EXPL) AddIMPResultText(IMP_SKILLS_IMPERIAL_EXPL);
2016
2017
2018 // now the needs training values
2019 Skill = SKILL_NONE;
2020 if (imp.bMarksmanship > NO_CHANCE_IN_HELL_SKILL_VALUE && imp.bMarksmanship <= NEEDS_TRAINING_SKILL_VALUE) Skill |= SKILL_MARK;
2021 if (imp.bMedical > NO_CHANCE_IN_HELL_SKILL_VALUE && imp.bMedical <= NEEDS_TRAINING_SKILL_VALUE) Skill |= SKILL_MED;
2022 if (imp.bMechanical > NO_CHANCE_IN_HELL_SKILL_VALUE && imp.bMechanical <= NEEDS_TRAINING_SKILL_VALUE) Skill |= SKILL_MECH;
2023 if (imp.bExplosive > NO_CHANCE_IN_HELL_SKILL_VALUE && imp.bExplosive <= NEEDS_TRAINING_SKILL_VALUE) Skill |= SKILL_EXPL;
2024
2025 if (Skill != SKILL_NONE) AddIMPResultText(IMP_SKILLS_NEED_TRAIN_SKILLS);
2026
2027 if (Skill & SKILL_MARK) AddIMPResultText(IMP_SKILLS_NEED_TRAIN_MARK);
2028 if (Skill & SKILL_MED) AddIMPResultText(IMP_SKILLS_NEED_TRAIN_MED);
2029 if (Skill & SKILL_MECH) AddIMPResultText(IMP_SKILLS_NEED_TRAIN_MECH);
2030 if (Skill & SKILL_EXPL) AddIMPResultText(IMP_SKILLS_NEED_TRAIN_EXPL);
2031
2032
2033 // and the no chance in hell of doing anything useful values
2034 Skill = SKILL_NONE;
2035 if (imp.bMarksmanship <= NO_CHANCE_IN_HELL_SKILL_VALUE) Skill |= SKILL_MARK;
2036 if (imp.bMedical <= NO_CHANCE_IN_HELL_SKILL_VALUE) Skill |= SKILL_MED;
2037 if (imp.bMechanical <= NO_CHANCE_IN_HELL_SKILL_VALUE) Skill |= SKILL_MECH;
2038 if (imp.bExplosive <= NO_CHANCE_IN_HELL_SKILL_VALUE) Skill |= SKILL_EXPL;
2039
2040 if (Skill != SKILL_NONE) AddIMPResultText(IMP_SKILLS_NO_SKILL);
2041
2042 if (Skill & SKILL_MECH) AddIMPResultText(IMP_SKILLS_NO_SKILL_MECH);
2043 if (Skill & SKILL_MARK) AddIMPResultText(IMP_SKILLS_NO_SKILL_MARK);
2044 if (Skill & SKILL_MED) AddIMPResultText(IMP_SKILLS_NO_SKILL_MED);
2045 if (Skill & SKILL_EXPL) AddIMPResultText(IMP_SKILLS_NO_SKILL_EXPL);
2046
2047
2048 // now the specialized skills
2049 // imperial skills
2050 iOffSet = IMP_SKILLS_SPECIAL_INTRO;
2051 iEndOfSection = IMP_SKILLS_SPECIAL_INTRO_LENGTH;
2052 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
2053
2054 AddSkillTraitText(imp, KNIFING, IMP_SKILLS_SPECIAL_KNIFE);
2055 AddSkillTraitText(imp, LOCKPICKING, IMP_SKILLS_SPECIAL_LOCK);
2056 AddSkillTraitText(imp, HANDTOHAND, IMP_SKILLS_SPECIAL_HAND);
2057 AddSkillTraitText(imp, ELECTRONICS, IMP_SKILLS_SPECIAL_ELEC);
2058 AddSkillTraitText(imp, NIGHTOPS, IMP_SKILLS_SPECIAL_NIGHT);
2059 AddSkillTraitText(imp, THROWING, IMP_SKILLS_SPECIAL_THROW);
2060 AddSkillTraitText(imp, TEACHING, IMP_SKILLS_SPECIAL_TEACH);
2061 AddSkillTraitText(imp, HEAVY_WEAPS, IMP_SKILLS_SPECIAL_HEAVY);
2062 AddSkillTraitText(imp, AUTO_WEAPS, IMP_SKILLS_SPECIAL_AUTO);
2063 AddSkillTraitText(imp, STEALTHY, IMP_SKILLS_SPECIAL_STEALTH);
2064 AddSkillTraitText(imp, AMBIDEXT, IMP_SKILLS_SPECIAL_AMBI);
2065 AddSkillTraitText(imp, THIEF, IMP_SKILLS_SPECIAL_THIEF);
2066 AddSkillTraitText(imp, MARTIALARTS, IMP_SKILLS_SPECIAL_MARTIAL);
2067
2068
2069 // now the physical
2070 // imperial physical
2071 iOffSet = IMP_RESULTS_PHYSICAL;
2072 iEndOfSection = IMP_RESULTS_PHYSICAL_LENGTH;
2073 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
2074
2075 PhysicalBits Phys;
2076
2077 // super physical
2078 Phys = PHYS_NONE;
2079 if (imp.bLife >= SUPER_STAT_VALUE) Phys |= PHYS_HLTH;
2080 if (imp.bDexterity >= SUPER_STAT_VALUE) Phys |= PHYS_DEX;
2081 if (imp.bAgility >= SUPER_STAT_VALUE) Phys |= PHYS_AGI;
2082 if (imp.bStrength >= SUPER_STAT_VALUE) Phys |= PHYS_STR;
2083 if (imp.bWisdom >= SUPER_STAT_VALUE) Phys |= PHYS_WIS;
2084 if (imp.bLeadership >= SUPER_STAT_VALUE) Phys |= PHYS_LDR;
2085
2086 if (Phys != PHYS_NONE) AddIMPResultText(IMP_PHYSICAL_SUPER);
2087
2088 if (Phys & PHYS_HLTH) AddIMPResultText(IMP_PHYSICAL_SUPER_HEALTH);
2089 if (Phys & PHYS_DEX) AddIMPResultText(IMP_PHYSICAL_SUPER_DEXTERITY);
2090 if (Phys & PHYS_STR) AddIMPResultText(IMP_PHYSICAL_SUPER_STRENGTH);
2091 if (Phys & PHYS_AGI) AddIMPResultText(IMP_PHYSICAL_SUPER_AGILITY);
2092 if (Phys & PHYS_WIS) AddIMPResultText(IMP_PHYSICAL_SUPER_WISDOM);
2093 if (Phys & PHYS_LDR) AddIMPResultText(IMP_PHYSICAL_SUPER_LEADERSHIP);
2094
2095
2096 // now the low attributes
2097 Phys = PHYS_NONE;
2098 if (imp.bLife < NEEDS_TRAINING_STAT_VALUE && imp.bLife > NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_HLTH;
2099 if (imp.bStrength < NEEDS_TRAINING_STAT_VALUE && imp.bStrength > NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_STR;
2100 if (imp.bAgility < NEEDS_TRAINING_STAT_VALUE && imp.bAgility > NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_AGI;
2101 if (imp.bWisdom < NEEDS_TRAINING_STAT_VALUE && imp.bWisdom > NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_WIS;
2102 if (imp.bLeadership < NEEDS_TRAINING_STAT_VALUE && imp.bLeadership > NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_LDR;
2103 if (imp.bDexterity < NEEDS_TRAINING_STAT_VALUE && imp.bDexterity > NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_DEX;
2104
2105 if (Phys != PHYS_NONE) AddIMPResultText(IMP_PHYSICAL_LOW);
2106
2107 if (Phys & PHYS_HLTH) AddIMPResultText(IMP_PHYSICAL_LOW_HEALTH);
2108 if (Phys & PHYS_DEX) AddIMPResultText(IMP_PHYSICAL_LOW_DEXTERITY);
2109 if (Phys & PHYS_STR) AddIMPResultText(IMP_PHYSICAL_LOW_STRENGTH);
2110 if (Phys & PHYS_AGI) AddIMPResultText(IMP_PHYSICAL_LOW_AGILITY);
2111 if (Phys & PHYS_WIS) AddIMPResultText(IMP_PHYSICAL_LOW_WISDOM);
2112 if (Phys & PHYS_LDR) AddIMPResultText(IMP_PHYSICAL_LOW_LEADERSHIP);
2113
2114
2115 // very low physical
2116 Phys = PHYS_NONE;
2117 if (imp.bLife <= NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_HLTH;
2118 if (imp.bDexterity <= NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_DEX;
2119 if (imp.bStrength <= NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_STR;
2120 if (imp.bAgility <= NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_AGI;
2121 if (imp.bWisdom <= NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_WIS;
2122 if (imp.bLeadership <= NO_CHANCE_IN_HELL_STAT_VALUE) Phys |= PHYS_LDR;
2123
2124 if (Phys != PHYS_NONE) AddIMPResultText(IMP_PHYSICAL_VERY_LOW);
2125
2126 if (Phys & PHYS_HLTH) AddIMPResultText(IMP_PHYSICAL_VERY_LOW_HEALTH);
2127 if (Phys & PHYS_DEX) AddIMPResultText(IMP_PHYSICAL_VERY_LOW_DEXTERITY);
2128 if (Phys & PHYS_STR) AddIMPResultText(IMP_PHYSICAL_VERY_LOW_STRENGTH);
2129 if (Phys & PHYS_AGI) AddIMPResultText(IMP_PHYSICAL_VERY_LOW_AGILITY);
2130 if (Phys & PHYS_WIS) AddIMPResultText(IMP_PHYSICAL_VERY_LOW_WISDOM);
2131 if (Phys & PHYS_LDR) AddIMPResultText(IMP_PHYSICAL_VERY_LOW_LEADERSHIP);
2132
2133
2134 iOffSet = IMP_RESULTS_PORTRAIT;
2135 iEndOfSection = IMP_RESULTS_PORTRAIT_LENGTH;
2136 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
2137
2138 switch (iPortraitNumber)
2139 {
2140 case 0: iOffSet = IMP_PORTRAIT_MALE_1; break;
2141 case 1: iOffSet = IMP_PORTRAIT_MALE_2; break;
2142 case 2: iOffSet = IMP_PORTRAIT_MALE_3; break;
2143 case 3: iOffSet = IMP_PORTRAIT_MALE_4; break;
2144 case 4:
2145 case 5: iOffSet = IMP_PORTRAIT_MALE_5; break;
2146 case 6:
2147 case 7: iOffSet = IMP_PORTRAIT_MALE_6; break;
2148 case 8: iOffSet = IMP_PORTRAIT_FEMALE_1; break;
2149 case 9: iOffSet = IMP_PORTRAIT_FEMALE_2; break;
2150 case 10: iOffSet = IMP_PORTRAIT_FEMALE_3; break;
2151 case 11:
2152 case 12: iOffSet = IMP_PORTRAIT_FEMALE_4; break;
2153 case 13:
2154 case 14: iOffSet = IMP_PORTRAIT_FEMALE_5; break;
2155 }
2156
2157 if (iRand % 2 == 0) iOffSet += 2;
2158
2159 iEndOfSection = 2;
2160 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
2161
2162 iOffSet = IMP_RESULTS_END;
2163 iEndOfSection = IMP_RESULTS_END_LENGTH;
2164 for (INT32 i = 0; i < iEndOfSection; ++i) AddIMPResultText(iOffSet + i);
2165
2166 PreviousMail = CurrentMail;
2167 }
2168
2169
HandleEmailViewerButtonStates(void)2170 static void HandleEmailViewerButtonStates(void)
2171 {
2172 // handle state of email viewer buttons
2173
2174 // leave, if not displaying message
2175 if (!fDisplayMessageFlag) return;
2176
2177 if( giNumberOfPagesToCurrentEmail <= 2 )
2178 {
2179 return;
2180 }
2181
2182 // Turn on/off previous page button
2183 EnableButton(giMailMessageButtons[0], giMessagePage != 0);
2184 // Turn on/off next page button
2185 EnableButton(giMailMessageButtons[1], pEmailPageInfo[giMessagePage + 1].pFirstRecord);
2186 }
2187
2188
CreateNextPreviousEmailPageButtons(void)2189 static void CreateNextPreviousEmailPageButtons(void)
2190 {
2191 // this function will create the buttons to advance and go back email pages
2192 giMailPageButtons[0] = MakeButtonNewMail(1, NEXT_PAGE_X, NEXT_PAGE_Y, NextRegionButtonCallback);
2193 giMailPageButtons[1] = MakeButtonNewMail(0, PREVIOUS_PAGE_X, NEXT_PAGE_Y, PreviousRegionButtonCallback);
2194 }
2195
2196
UpdateStatusOfNextPreviousButtons(void)2197 static void UpdateStatusOfNextPreviousButtons(void)
2198 {
2199 // set the states of the page advance buttons
2200 EnableButton(giMailPageButtons[0], iCurrentPage < iLastPage);
2201 EnableButton(giMailPageButtons[1], iCurrentPage > 0);
2202 }
2203
2204
DisplayWhichPageOfEmailProgramIsDisplayed(void)2205 static void DisplayWhichPageOfEmailProgramIsDisplayed(void)
2206 {
2207 // will draw the number of the email program we are viewing right now
2208 SetFontAttributes(MESSAGE_FONT, FONT_BLACK, NO_SHADOW);
2209
2210 // page number
2211 INT32 CPage;
2212 INT32 LPage;
2213 if (iLastPage < 0)
2214 {
2215 CPage = 1;
2216 LPage = 1;
2217 }
2218 else
2219 {
2220 CPage = iCurrentPage + 1;
2221 LPage = iLastPage + 1;
2222 }
2223 MPrint(PAGE_NUMBER_X, PAGE_NUMBER_Y, ST::format("{} / {}", CPage, LPage));
2224
2225 // restore shadow
2226 SetFontShadow( DEFAULT_SHADOW );
2227 }
2228
2229
OpenMostRecentUnreadEmail(void)2230 static void OpenMostRecentUnreadEmail(void)
2231 {
2232 // will open the most recent email the player has recieved and not read
2233 Email* MostRecentMail = NULL;
2234 Email* pB = pEmailList;
2235 UINT32 iLowestDate = 9999999;
2236
2237 while( pB )
2238 {
2239 // if date is lesser and unread , swap
2240 if (pB->iDate < iLowestDate && !pB->fRead)
2241 {
2242 MostRecentMail = pB;
2243 iLowestDate = pB -> iDate;
2244 }
2245
2246 // next in B's list
2247 pB=pB->Next;
2248 }
2249
2250 CurrentMail = MostRecentMail;
2251
2252 // valid message, show it
2253 if (MostRecentMail != NULL) fDisplayMessageFlag = TRUE;
2254 }
2255
2256
DisplayNumberOfPagesToThisEmail(INT32 const iViewerY)2257 static void DisplayNumberOfPagesToThisEmail(INT32 const iViewerY)
2258 {
2259 // display the indent for the display of pages to this email..along with the current page/number of pages
2260 SetFontAttributes(FONT12ARIAL, FONT_BLACK, NO_SHADOW);
2261
2262 ST::string str = ST::format("{} / {}", giMessagePage + 1, giNumberOfPagesToCurrentEmail - 1);
2263 INT16 sX;
2264 INT16 sY;
2265 FindFontCenterCoordinates(VIEWER_X + INDENT_X_OFFSET, 0, INDENT_X_WIDTH, 0, str, FONT12ARIAL, &sX, &sY);
2266 MPrint(sX, VIEWER_Y + iViewerY + INDENT_Y_OFFSET - 2, str);
2267
2268 SetFontShadow(DEFAULT_SHADOW);
2269 }
2270
2271
GetNumberOfPagesToEmail(void)2272 static INT32 GetNumberOfPagesToEmail(void)
2273 {
2274 Record* pTempRecord;
2275 INT32 iNumberOfPagesToEmail = 0;
2276
2277
2278 // set temp record to head of list
2279 pTempRecord=pMessageRecordList;
2280
2281 // run through messages, and find out how many
2282 while( pTempRecord )
2283 {
2284 pTempRecord = GetFirstRecordOnThisPage(pMessageRecordList, iNumberOfPagesToEmail);
2285 iNumberOfPagesToEmail++;
2286 }
2287
2288
2289 return( iNumberOfPagesToEmail );
2290 }
2291
2292
ShutDownEmailList()2293 void ShutDownEmailList()
2294 {
2295 // Loop through all the emails to delete them
2296 Email* i = pEmailList;
2297 pEmailList = 0;
2298 while (i)
2299 {
2300 Email* const del = i;
2301 i = i->Next;
2302 delete del;
2303 }
2304 ClearPages();
2305 }
2306
2307
PreProcessEmail(Email * const m)2308 static void PreProcessEmail(Email* const m)
2309 {
2310 // already processed?
2311 if (pEmailPageInfo[0].pFirstRecord) return;
2312
2313 if (!pMessageRecordList)
2314 { // List doesn't exist, reload
2315 INT32 const offset = m->usOffset;
2316 for (INT32 i = 0; i != m->usLength; ++i)
2317 {
2318 // read one record from email file
2319 ST::string str = LoadEMailText(offset + i);
2320 AddEmailRecordToList(str);
2321 }
2322 PreviousMail = CurrentMail;
2323 }
2324
2325 Record* start = pMessageRecordList;
2326 if (start && m->usOffset != IMP_EMAIL_PROFILE_RESULTS)
2327 { // pass the subject line
2328 start = start->Next;
2329 }
2330
2331 // get number of pages to this email
2332 giNumberOfPagesToCurrentEmail = GetNumberOfPagesToEmail();
2333
2334 INT32 h = 0;
2335 for (Record const* i = start; i; i = i->Next)
2336 {
2337 // get the height of the string, ONLY!...must redisplay ON TOP OF background graphic
2338 h += IanWrappedStringHeight(MESSAGE_WIDTH, MESSAGE_GAP, MESSAGE_FONT, i->pRecord);
2339 }
2340
2341 // set iViewerY so to center the viewer
2342 iViewerPositionY = (LAPTOP_SCREEN_LR_Y - 2 * VIEWER_Y - 2 * VIEWER_MESSAGE_BODY_START_Y - h) / 2;
2343 if (iViewerPositionY < 0) iViewerPositionY = 0;
2344
2345 UINT16 const line_h = GetFontHeight(MESSAGE_FONT);
2346 if (h < line_h * MIN_MESSAGE_HEIGHT_IN_LINES)
2347 {
2348 // Use minimum height
2349 h = line_h * MIN_MESSAGE_HEIGHT_IN_LINES;
2350 }
2351 else if (h > MAX_EMAIL_MESSAGE_PAGE_SIZE)
2352 {
2353 // Message to big to fit on page
2354 h = MAX_EMAIL_MESSAGE_PAGE_SIZE;
2355 }
2356
2357 // set total height to height of records displayed
2358 iTotalHeight = h + 10;
2359
2360 INT32 page = 0;
2361 if (iTotalHeight < MAX_EMAIL_MESSAGE_PAGE_SIZE)
2362 {
2363 EmailPageInfoStruct& info = pEmailPageInfo[page];
2364 info.pFirstRecord = start;
2365 info.iPageNumber = 0;
2366
2367 Record* last_record = 0;
2368 for (Record* i = start; i; i = i->Next)
2369 {
2370 last_record = i;
2371 }
2372
2373 // only one record to this email?..then set next to null
2374 info.pLastRecord = last_record == info.pFirstRecord ? 0 : last_record;
2375 ++page;
2376 }
2377 else
2378 {
2379 // more than one page
2380 for (Record* i; (i = GetFirstRecordOnThisPage(start, page)); ++page)
2381 {
2382 EmailPageInfoStruct& info = pEmailPageInfo[page];
2383 info.pFirstRecord = i;
2384 info.iPageNumber = page;
2385
2386 // go to the right record
2387 Record* last_record = 0;
2388 INT32 y = 0;
2389 for (; i; i = last_record = i->Next)
2390 {
2391 UINT16 const h = IanWrappedStringHeight(MESSAGE_WIDTH, MESSAGE_GAP, MESSAGE_FONT, i->pRecord);
2392 // Gonna get cut off? End now
2393 if (y + h > MAX_EMAIL_MESSAGE_PAGE_SIZE) break;
2394 y += h;
2395 }
2396
2397 info.pLastRecord = last_record == info.pFirstRecord ? 0 : last_record;
2398 }
2399 }
2400
2401 EmailPageInfoStruct& info = pEmailPageInfo[page];
2402 info.pFirstRecord = 0;
2403 info.pLastRecord = 0;
2404 info.iPageNumber = page;
2405 }
2406
2407
ModifyInsuranceEmails(UINT16 usMessageId,Email * pMail,UINT8 ubNumberOfRecords)2408 static void ModifyInsuranceEmails(UINT16 usMessageId, Email* pMail, UINT8 ubNumberOfRecords)
2409 {
2410 UINT8 ubCnt;
2411
2412 for( ubCnt=0; ubCnt<ubNumberOfRecords; ubCnt++)
2413 {
2414 // read one record from email file
2415 ST::string pString = LoadEMailText(usMessageId);
2416
2417 //Replace the $MERCNAME$ and $AMOUNT$ with the mercs name and the amountm if the string contains the keywords.
2418 pString = ReplaceMercNameAndAmountWithProperData( pString, pMail );
2419
2420 // add to list
2421 AddEmailRecordToList( pString );
2422
2423 usMessageId++;
2424 }
2425
2426 PreviousMail = CurrentMail;
2427 }
2428
2429
ReplaceMercNameAndAmountWithProperData(const ST::string & pFinishedString,const Email * pMail)2430 static ST::string ReplaceMercNameAndAmountWithProperData(const ST::string& pFinishedString, const Email* pMail)
2431 {
2432 const ST::string sMercName = "$MERCNAME$"; //Doesnt need to be translated, inside Email.txt and will be replaced by the mercs name
2433 const ST::string sAmount = "$AMOUN$"; //Doesnt need to be translated, inside Email.txt and will be replaced by a dollar amount
2434
2435 ST::string mercName = gMercProfiles[ pMail->uiSecondData ].zName;
2436 ST::string amount = SPrintMoney(pMail->iFirstData);
2437 return pFinishedString.replace(sAmount, amount).replace(sMercName, mercName);
2438 }
2439
2440